diff --git a/build_files/build_environment/cmake/openvdb.cmake b/build_files/build_environment/cmake/openvdb.cmake index 8fa0bbc11ea8..a81c4ce3c9fe 100644 --- a/build_files/build_environment/cmake/openvdb.cmake +++ b/build_files/build_environment/cmake/openvdb.cmake @@ -48,7 +48,7 @@ set(OPENVDB_PATCH ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATC if(APPLE) set(OPENVDB_PATCH ${OPENVDB_PATCH} && - ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb_metal.diff + ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb_metal.diff ) endif() diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index 916602512131..4cc65f25cb56 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -478,8 +478,8 @@ set(EMBREE_HASH_TYPE MD5) set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip) set(USD_VERSION 23.05) -set(USD_URI https://github.com/PixarAnimationStudios/USD/archive/v${USD_VERSION}.tar.gz) -set(USD_HASH 56684f4fdd1a9209dabf03856be5eca6) +set(USD_URI https://github.com/PixarAnimationStudios/OpenUSD/archive/v${USD_VERSION}.tar.gz) +set(USD_HASH d4d92ff112bc82a1718bcd129b853a54) set(USD_HASH_TYPE MD5) set(USD_FILE usd-v${USD_VERSION}.tar.gz) diff --git a/build_files/build_environment/install_linux_packages.py b/build_files/build_environment/install_linux_packages.py index 07ae18ffd254..7e91903d6b87 100755 --- a/build_files/build_environment/install_linux_packages.py +++ b/build_files/build_environment/install_linux_packages.py @@ -267,6 +267,20 @@ def __init__(self, name, is_group=False, is_mandatory=False, DISTRO_ID_ARCH: "dbus", }, ), + Package(name="OpenGL Library", + distro_package_names={DISTRO_ID_DEBIAN: "libgl-dev", + DISTRO_ID_FEDORA: "mesa-libGL-devel", + DISTRO_ID_SUSE: "Mesa-libGL-devel", + DISTRO_ID_ARCH: "libglvnd", + }, + ), + Package(name="EGL Library", + distro_package_names={DISTRO_ID_DEBIAN: "libegl-dev", + DISTRO_ID_FEDORA: "mesa-libEGL-devel", + DISTRO_ID_SUSE: "Mesa-libEGL-devel", + DISTRO_ID_ARCH: None, # Included in libglvnd. + }, + ), ) diff --git a/build_files/build_environment/patches/embree.diff b/build_files/build_environment/patches/embree.diff index b31f7e43bfc3..fe69493f89e7 100644 --- a/build_files/build_environment/patches/embree.diff +++ b/build_files/build_environment/patches/embree.diff @@ -24,3 +24,57 @@ index 7c2f43d..106b1d5 100644 DISABLE_STACK_PROTECTOR_FOR_INTERSECTORS(${EMBREE_LIBRARY_FILES_AVX2}) ADD_LIBRARY(embree_avx2 STATIC ${EMBREE_LIBRARY_FILES_AVX2}) TARGET_LINK_LIBRARIES(embree_avx2 PRIVATE tasking) +diff --git a/kernels/rthwif/rtbuild/rtbuild.cpp b/kernels/rthwif/rtbuild/rtbuild.cpp +index 6d439f939..367b1ce7b 100644 +--- a/kernels/rthwif/rtbuild/rtbuild.cpp ++++ b/kernels/rthwif/rtbuild/rtbuild.cpp +@@ -10,7 +10,7 @@ namespace embree + { + using namespace embree::isa; + +- static std::unique_ptr g_arena; ++ static tbb::task_arena g_arena(tbb::this_task_arena::max_concurrency(),tbb::this_task_arena::max_concurrency()); + + typedef enum _ze_raytracing_accel_format_internal_t { + ZE_RTAS_DEVICE_FORMAT_EXP_INVALID = 0, // invalid acceleration structure format +@@ -210,13 +210,10 @@ namespace embree + + RTHWIF_API void zeRTASInitExp() + { +- uint32_t numThreads = tbb::this_task_arena::max_concurrency(); +- g_arena.reset(new tbb::task_arena(numThreads,numThreads)); + } + + RTHWIF_API void zeRTASExitExp() + { +- g_arena.reset(); + } + + typedef struct _zet_base_desc_t +@@ -740,7 +737,7 @@ namespace embree + //if (op->hBuilder != hBuilder) + // return ZE_RESULT_ERROR_INVALID_ARGUMENT; + +- g_arena->execute([&](){ op->group.run([=](){ ++ g_arena.execute([&](){ op->group.run([=](){ + op->errorCode = zeRTASBuilderBuildExpInternal(args, + pScratchBuffer, scratchBufferSizeBytes, + pRtasBuffer, rtasBufferSizeBytes, +@@ -753,7 +750,7 @@ namespace embree + else + { + ze_result_t errorCode = ZE_RESULT_SUCCESS; +- g_arena->execute([&](){ errorCode = zeRTASBuilderBuildExpInternal(args, ++ g_arena.execute([&](){ errorCode = zeRTASBuilderBuildExpInternal(args, + pScratchBuffer, scratchBufferSizeBytes, + pRtasBuffer, rtasBufferSizeBytes, + pBuildUserPtr, pBounds, pRtasBufferSizeBytes); +@@ -801,7 +798,7 @@ namespace embree + VALIDATE(hParallelOperation); + + ze_rtas_parallel_operation_t* op = (ze_rtas_parallel_operation_t*) hParallelOperation; +- g_arena->execute([&](){ op->group.wait(); }); ++ g_arena.execute([&](){ op->group.wait(); }); + return op->errorCode; + } + } diff --git a/build_files/build_environment/patches/openvdb_metal.diff b/build_files/build_environment/patches/openvdb_metal.diff index 6a1e723a9afe..ba3e5bca9397 100644 --- a/build_files/build_environment/patches/openvdb_metal.diff +++ b/build_files/build_environment/patches/openvdb_metal.diff @@ -1,14 +1,14 @@ -Index: nanovdb/nanovdb/NanoVDB.h -=================================================================== ---- nanovdb/nanovdb/NanoVDB.h (revision 63215) -+++ nanovdb/nanovdb/NanoVDB.h (working copy) -@@ -140,8 +140,28 @@ +diff --git a/nanovdb/nanovdb/NanoVDB.h b/nanovdb/nanovdb/NanoVDB.h +index fde5c47..cff460a 100644 +--- a/nanovdb/nanovdb/NanoVDB.h ++++ b/nanovdb/nanovdb/NanoVDB.h +@@ -140,7 +140,27 @@ #define NANOVDB_ALIGN(n) alignas(n) #endif // !defined(NANOVDB_ALIGN) -#ifdef __CUDACC_RTC__ +#ifdef __KERNEL_METAL__ - ++ +using namespace metal; +#define std metal +#define double uint64_t @@ -28,11 +28,10 @@ Index: nanovdb/nanovdb/NanoVDB.h +#define NANOVDB_ASSERT(x) + +#elif defined(__CUDACC_RTC__) -+ + typedef signed char int8_t; typedef short int16_t; - typedef int int32_t; -@@ -157,6 +177,10 @@ +@@ -157,6 +177,10 @@ typedef unsigned long long uint64_t; #else // !__CUDACC_RTC__ @@ -43,7 +42,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #include // for abs in clang7 #include // for types like int32_t etc #include // for size_t type -@@ -262,7 +286,7 @@ +@@ -262,7 +286,7 @@ enum class GridType : uint32_t { Unknown = 0, Index = 19,// index into an external array of values End = 20 }; @@ -52,7 +51,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Retuns a c-string used to describe a GridType inline const char* toStr(GridType gridType) { -@@ -289,7 +313,7 @@ +@@ -289,7 +313,7 @@ enum class GridClass : uint32_t { Unknown = 0, IndexGrid = 8,// grid whose values are offsets, e.g. into an external array End = 9 }; @@ -61,7 +60,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Retuns a c-string used to describe a GridClass inline const char* toStr(GridClass gridClass) { -@@ -313,7 +337,7 @@ +@@ -313,7 +337,7 @@ enum class GridFlags : uint32_t { End = 1 << 6, }; @@ -70,7 +69,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Retuns a c-string used to describe a GridFlags inline const char* toStr(GridFlags gridFlags) { -@@ -355,13 +379,13 @@ +@@ -355,13 +379,13 @@ enum class GridBlindDataSemantic : uint32_t { Unknown = 0, template struct is_same { @@ -86,7 +85,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // --------------------------> enable_if <------------------------------------ -@@ -383,13 +407,13 @@ +@@ -383,13 +407,13 @@ struct enable_if template struct is_const { @@ -102,7 +101,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // --------------------------> remove_const <------------------------------------ -@@ -412,7 +436,7 @@ +@@ -412,7 +436,7 @@ struct remove_const template struct is_floating_point { @@ -111,7 +110,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // --------------------------> is_specialization <------------------------------------ -@@ -425,12 +449,12 @@ +@@ -425,12 +449,12 @@ struct is_floating_point template class TemplateType> struct is_specialization { @@ -126,7 +125,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // --------------------------> Value Map <------------------------------------ -@@ -495,19 +519,19 @@ +@@ -495,19 +519,19 @@ struct BuildToValueMap // --------------------------> utility functions related to alignment <------------------------------------ /// @brief return true if the specified pointer is aligned @@ -149,7 +148,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { NANOVDB_ASSERT(p); return (NANOVDB_DATA_ALIGNMENT - (uint64_t(p) % NANOVDB_DATA_ALIGNMENT)) % NANOVDB_DATA_ALIGNMENT; -@@ -515,43 +539,66 @@ +@@ -515,43 +539,66 @@ __hostdev__ inline static uint64_t alignmentPadding(const void* p) /// @brief offset the specified pointer so it is aligned. template @@ -227,7 +226,7 @@ Index: nanovdb/nanovdb/NanoVDB.h // --------------------------> Rgba8 <------------------------------------ /// @brief 8-bit red, green, blue, alpha packed into 32 bit unsigned int -@@ -562,13 +609,13 @@ +@@ -562,13 +609,13 @@ class Rgba8 uint32_t packed;// 32 bit packed representation } mData; public: @@ -246,7 +245,7 @@ Index: nanovdb/nanovdb/NanoVDB.h __hostdev__ Rgba8() : mData{0,0,0,0} {static_assert(sizeof(uint32_t) == sizeof(Rgba8),"Unexpected sizeof");} __hostdev__ Rgba8(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255u) : mData{r, g, b, a} {} explicit __hostdev__ Rgba8(uint8_t v) : Rgba8(v,v,v,v) {} -@@ -579,8 +626,8 @@ +@@ -579,8 +626,8 @@ public: (uint8_t(0.5f + a * 255.0f))}// round to nearest { } @@ -257,7 +256,7 @@ Index: nanovdb/nanovdb/NanoVDB.h __hostdev__ float lengthSqr() const { return 0.0000153787005f*(float(mData.c[0])*mData.c[0] + -@@ -588,18 +635,18 @@ +@@ -588,18 +635,18 @@ public: float(mData.c[2])*mData.c[2]);//1/255^2 } __hostdev__ float length() const { return sqrtf(this->lengthSqr() ); } @@ -288,7 +287,7 @@ Index: nanovdb/nanovdb/NanoVDB.h };// Rgba8 using PackedRGBA8 = Rgba8;// for backwards compatibility -@@ -660,17 +707,17 @@ +@@ -660,17 +707,17 @@ public: NANOVDB_ASSERT(minor < (1u << 11));// max value of minor is 2047 NANOVDB_ASSERT(patch < (1u << 10));// max value of patch is 1023 } @@ -312,7 +311,7 @@ Index: nanovdb/nanovdb/NanoVDB.h const char* c_str() const { char *buffer = (char*)malloc(4 + 1 + 4 + 1 + 4 + 1);// xxxx.xxxx.xxxx\0 -@@ -749,7 +796,7 @@ +@@ -749,7 +796,7 @@ struct Maximum //@} template @@ -321,7 +320,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return !(x > Tolerance::value()) && !(x < -Tolerance::value()); } -@@ -771,10 +818,12 @@ +@@ -771,10 +818,12 @@ __hostdev__ inline float Min(float a, float b) { return fminf(a, b); } @@ -334,7 +333,7 @@ Index: nanovdb/nanovdb/NanoVDB.h template __hostdev__ inline Type Max(Type a, Type b) { -@@ -793,45 +842,55 @@ +@@ -793,45 +842,55 @@ __hostdev__ inline float Max(float a, float b) { return fmaxf(a, b); } @@ -390,7 +389,7 @@ Index: nanovdb/nanovdb/NanoVDB.h template __hostdev__ inline T Pow2(T x) -@@ -875,28 +934,54 @@ +@@ -875,46 +934,78 @@ __hostdev__ inline int Abs(int x) } template class Vec3T> @@ -450,7 +449,6 @@ Index: nanovdb/nanovdb/NanoVDB.h //@{ /// Return the square root of a floating-point value. __hostdev__ inline float Sqrt(float x) -@@ -903,18 +988,24 @@ { return sqrtf(x); } @@ -477,7 +475,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { #if 0 static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values -@@ -930,11 +1021,30 @@ +@@ -930,8 +1021,27 @@ __hostdev__ inline int MinIndex(const Vec3T& v) #endif } @@ -485,9 +483,9 @@ Index: nanovdb/nanovdb/NanoVDB.h template -__hostdev__ inline int MaxIndex(const Vec3T& v) +__hostdev__ inline int MinIndex(__local__ const Vec3T& v) - { - #if 0 - static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values ++{ ++#if 0 ++ static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values + const int hashKey = ((v[0] < v[1]) << 2) + ((v[0] < v[2]) << 1) + (v[1] < v[2]); // ?*4+?*2+?*1 + return hashTable[hashKey]; +#else @@ -503,13 +501,10 @@ Index: nanovdb/nanovdb/NanoVDB.h + +template +__hostdev__ inline int MaxIndex(__global__ const Vec3T& v) -+{ -+#if 0 -+ static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values - const int hashKey = ((v[0] > v[1]) << 2) + ((v[0] > v[2]) << 1) + (v[1] > v[2]); // ?*4+?*2+?*1 - return hashTable[hashKey]; - #else -@@ -947,6 +1057,25 @@ + { + #if 0 + static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values +@@ -947,6 +1057,25 @@ __hostdev__ inline int MaxIndex(const Vec3T& v) #endif } @@ -535,7 +530,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief round up byteSize to the nearest wordSize, e.g. to align to machine word: AlignUp>(IndexType n) const { return Coord(mVec[0] >> n, mVec[1] >> n, mVec[2] >> n); } /// @brief Return true if this Coord is lexicographically less than the given Coord. @@ -620,7 +615,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] &= n; mVec[1] &= n; -@@ -1051,7 +1197,7 @@ mVec[2] &= n; return *this; } @@ -629,7 +623,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] <<= n; mVec[1] <<= n; -@@ -1058,7 +1204,7 @@ mVec[2] <<= n; return *this; } @@ -638,7 +631,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] >>= n; mVec[1] >>= n; -@@ -1065,7 +1211,7 @@ mVec[2] >>= n; return *this; } @@ -647,7 +639,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] += n; mVec[1] += n; -@@ -1072,9 +1218,9 @@ mVec[2] += n; return *this; } @@ -660,7 +651,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] += rhs[0]; mVec[1] += rhs[1]; -@@ -1081,7 +1227,7 @@ mVec[2] += rhs[2]; return *this; } @@ -669,7 +659,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] -= rhs[0]; mVec[1] -= rhs[1]; -@@ -1090,7 +1236,7 @@ +@@ -1090,7 +1236,7 @@ public: } /// @brief Perform a component-wise minimum with the other Coord. @@ -678,7 +668,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (other[0] < mVec[0]) mVec[0] = other[0]; -@@ -1102,7 +1248,7 @@ +@@ -1102,7 +1248,7 @@ public: } /// @brief Perform a component-wise maximum with the other Coord. @@ -687,7 +677,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (other[0] > mVec[0]) mVec[0] = other[0]; -@@ -1113,16 +1259,16 @@ +@@ -1113,16 +1259,16 @@ public: return *this; } @@ -707,7 +697,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return (a[0] < b[0] || a[1] < b[1] || a[2] < b[2]); } -@@ -1130,7 +1276,13 @@ +@@ -1130,7 +1276,13 @@ public: /// @brief Return the largest integer coordinates that are not greater /// than @a xyz (node centered conversion). template @@ -722,7 +712,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Return a hash key derived from the existing coordinates. /// @details For details on this hash function please see the VDB paper. -@@ -1159,7 +1311,7 @@ +@@ -1159,7 +1311,7 @@ class Vec3 T mVec[3]; public: @@ -731,7 +721,7 @@ Index: nanovdb/nanovdb/NanoVDB.h using ValueType = T; Vec3() = default; __hostdev__ explicit Vec3(T x) -@@ -1171,18 +1323,18 @@ +@@ -1171,30 +1323,36 @@ public: { } template @@ -755,7 +745,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] = rhs[0]; mVec[1] = rhs[1]; -@@ -1189,12 +1341,18 @@ mVec[2] = rhs[2]; return *this; } @@ -778,7 +767,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return Vec3(mVec[1] * v[2] - mVec[2] * v[1], mVec[2] * v[0] - mVec[0] * v[2], -@@ -1206,13 +1364,26 @@ +@@ -1206,37 +1364,62 @@ public: } __hostdev__ T length() const { return Sqrt(this->lengthSqr()); } __hostdev__ Vec3 operator-() const { return Vec3(-mVec[0], -mVec[1], -mVec[2]); } @@ -812,7 +801,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] += v[0]; mVec[1] += v[1]; -@@ -1219,7 +1390,7 @@ mVec[2] += v[2]; return *this; } @@ -821,7 +809,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] -= v[0]; mVec[1] -= v[1]; -@@ -1226,7 +1397,7 @@ mVec[2] -= v[2]; return *this; } @@ -830,7 +817,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] *= s; mVec[1] *= s; -@@ -1233,10 +1404,22 @@ mVec[2] *= s; return *this; } @@ -856,7 +842,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (other[0] < mVec[0]) mVec[0] = other[0]; -@@ -1248,7 +1431,7 @@ +@@ -1248,7 +1431,7 @@ public: } /// @brief Perform a component-wise maximum with the other Coord. @@ -865,7 +851,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (other[0] > mVec[0]) mVec[0] = other[0]; -@@ -1274,15 +1457,29 @@ +@@ -1274,15 +1457,29 @@ public: }; // Vec3 template @@ -878,13 +864,13 @@ Index: nanovdb/nanovdb/NanoVDB.h template -__hostdev__ inline Vec3 operator/(T1 scalar, const Vec3& vec) +__hostdev__ inline Vec3 operator*(T1 scalar, __local__ const Vec3& vec) - { ++{ + return Vec3(scalar * vec[0], scalar * vec[1], scalar * vec[2]); +} +#endif +template +__hostdev__ inline Vec3 operator/(T1 scalar, __global__ const Vec3& vec) -+{ + { return Vec3(scalar / vec[0], scalar / vec[1], scalar / vec[2]); } +#if defined(__KERNEL_METAL__) @@ -897,7 +883,7 @@ Index: nanovdb/nanovdb/NanoVDB.h using Vec3R = Vec3; using Vec3d = Vec3; -@@ -1304,7 +1501,7 @@ +@@ -1304,7 +1501,7 @@ class Vec4 T mVec[4]; public: @@ -906,7 +892,7 @@ Index: nanovdb/nanovdb/NanoVDB.h using ValueType = T; Vec4() = default; __hostdev__ explicit Vec4(T x) -@@ -1316,14 +1513,14 @@ +@@ -1316,14 +1513,14 @@ public: { } template @@ -925,7 +911,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] = rhs[0]; mVec[1] = rhs[1]; -@@ -1331,10 +1528,10 @@ +@@ -1331,23 +1528,23 @@ public: mVec[3] = rhs[3]; return *this; } @@ -939,7 +925,6 @@ Index: nanovdb/nanovdb/NanoVDB.h __hostdev__ T lengthSqr() const { return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2] + mVec[3] * mVec[3]; // 7 flops -@@ -1341,13 +1538,13 @@ } __hostdev__ T length() const { return Sqrt(this->lengthSqr()); } __hostdev__ Vec4 operator-() const { return Vec4(-mVec[0], -mVec[1], -mVec[2], -mVec[3]); } @@ -960,7 +945,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] += v[0]; mVec[1] += v[1]; -@@ -1355,7 +1552,7 @@ +@@ -1355,7 +1552,7 @@ public: mVec[3] += v[3]; return *this; } @@ -969,7 +954,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] -= v[0]; mVec[1] -= v[1]; -@@ -1363,7 +1560,7 @@ +@@ -1363,7 +1560,7 @@ public: mVec[3] -= v[3]; return *this; } @@ -978,7 +963,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mVec[0] *= s; mVec[1] *= s; -@@ -1371,10 +1568,10 @@ +@@ -1371,10 +1568,10 @@ public: mVec[3] *= s; return *this; } @@ -992,7 +977,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (other[0] < mVec[0]) mVec[0] = other[0]; -@@ -1388,7 +1585,7 @@ +@@ -1388,7 +1585,7 @@ public: } /// @brief Perform a component-wise maximum with the other Coord. @@ -1001,7 +986,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (other[0] > mVec[0]) mVec[0] = other[0]; -@@ -1403,12 +1600,12 @@ +@@ -1403,12 +1600,12 @@ public: }; // Vec4 template @@ -1016,7 +1001,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return Vec4(scalar / vec[0], scalar / vec[1], scalar / vec[2], scalar / vec[3]); } -@@ -1428,23 +1625,23 @@ +@@ -1428,23 +1625,23 @@ struct TensorTraits; template struct TensorTraits { @@ -1050,7 +1035,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // ----------------------------> FloatTraits <-------------------------------------- -@@ -1528,71 +1725,80 @@ +@@ -1528,71 +1725,80 @@ __hostdev__ inline GridType mapToGridType() // ----------------------------> matMult <-------------------------------------- template @@ -1066,7 +1051,7 @@ Index: nanovdb/nanovdb/NanoVDB.h template -__hostdev__ inline Vec3T matMult(const double* mat, const Vec3T& xyz) +__hostdev__ inline Vec3T matMult(__global__ const float* mat, __local__ const Vec3T& xyz) - { ++{ + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], xyz[2] * mat[2])), + fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], xyz[2] * mat[5])), + fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops @@ -1075,7 +1060,7 @@ Index: nanovdb/nanovdb/NanoVDB.h +#ifndef __KERNEL_METAL__ +template +__hostdev__ inline Vec3T matMult(__global__ const double* mat, __global__ const Vec3T& xyz) -+{ + { return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[1], static_cast(xyz[2]) * mat[2])), fma(static_cast(xyz[0]), mat[3], fma(static_cast(xyz[1]), mat[4], static_cast(xyz[2]) * mat[5])), fma(static_cast(xyz[0]), mat[6], fma(static_cast(xyz[1]), mat[7], static_cast(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops @@ -1147,7 +1132,7 @@ Index: nanovdb/nanovdb/NanoVDB.h // ----------------------------> BBox <------------------------------------- // Base-class for static polymorphism (cannot be constructed directly) -@@ -1600,15 +1806,27 @@ +@@ -1600,22 +1806,34 @@ template struct BaseBBox { Vec3T mCoord[2]; @@ -1184,7 +1169,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mCoord[0] += xyz; mCoord[1] += xyz; -@@ -1615,7 +1833,7 @@ return *this; } // @brief Expand this bounding box to enclose point (i, j, k). @@ -1193,7 +1177,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mCoord[0].minComponent(xyz); mCoord[1].maxComponent(xyz); -@@ -1623,7 +1841,7 @@ +@@ -1623,7 +1841,7 @@ struct BaseBBox } /// @brief Intersect this bounding box with the given bounding box. @@ -1202,7 +1186,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mCoord[0].maxComponent(bbox.min()); mCoord[1].minComponent(bbox.max()); -@@ -1634,7 +1852,7 @@ +@@ -1634,7 +1852,7 @@ struct BaseBBox //{ // return BaseBBox(mCoord[0].offsetBy(-padding),mCoord[1].offsetBy(padding)); //} @@ -1211,7 +1195,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (xyz[0] < mCoord[0][0] || xyz[1] < mCoord[0][1] || xyz[2] < mCoord[0][2]) return false; -@@ -1642,10 +1860,20 @@ +@@ -1642,10 +1860,20 @@ struct BaseBBox return false; return true; } @@ -1233,7 +1217,7 @@ Index: nanovdb/nanovdb/NanoVDB.h : mCoord{min, max} { } -@@ -1659,38 +1887,45 @@ +@@ -1659,38 +1887,45 @@ struct BBox; /// @note Min is inclusive and max is exclusive. If min = max the dimension of /// the bounding box is zero and therefore it is also empty. template @@ -1286,7 +1270,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return p[0] > mCoord[0][0] && p[1] > mCoord[0][1] && p[2] > mCoord[0][2] && p[0] < mCoord[1][0] && p[1] < mCoord[1][1] && p[2] < mCoord[1][2]; -@@ -1703,24 +1938,32 @@ +@@ -1703,24 +1938,32 @@ struct BBox : public BaseBBox /// @note Both min and max are INCLUDED in the bbox so dim = max - min + 1. So, /// if min = max the bounding box contains exactly one point and dim = 1! template @@ -1323,7 +1307,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (mPos[2] < mBBox[1][2]) {// this is the most common case ++mPos[2]; -@@ -1734,7 +1977,7 @@ +@@ -1734,7 +1977,7 @@ struct BBox : public BaseBBox } return *this; } @@ -1332,7 +1316,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { auto tmp = *this; ++(*this); -@@ -1742,7 +1985,7 @@ +@@ -1742,20 +1985,20 @@ struct BBox : public BaseBBox } /// @brief Return @c true if the iterator still points to a valid coordinate. __hostdev__ operator bool() const { return mPos[0] <= mBBox[1][0]; } @@ -1341,7 +1325,6 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // Iterator __hostdev__ Iterator begin() const { return Iterator{*this}; } __hostdev__ BBox() -@@ -1749,13 +1992,13 @@ : BaseT(CoordT::max(), CoordT::min()) { } @@ -1357,7 +1340,7 @@ Index: nanovdb/nanovdb/NanoVDB.h : BaseT(other.mCoord[0], other.mCoord[1]) { NANOVDB_ASSERT(this->is_divisible()); -@@ -1764,7 +2007,7 @@ +@@ -1764,7 +2007,7 @@ struct BBox : public BaseBBox other.mCoord[0][n] = mCoord[1][n] + 1; } @@ -1366,7 +1349,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return BBox(min, min.offsetBy(dim - 1)); } -@@ -1778,15 +2021,23 @@ +@@ -1778,15 +2021,23 @@ struct BBox : public BaseBBox mCoord[0][2] > mCoord[1][2]; } __hostdev__ CoordT dim() const { return this->empty() ? Coord(0) : this->max() - this->min() + Coord(1); } __hostdev__ uint64_t volume() const { auto d = this->dim(); return uint64_t(d[0])*uint64_t(d[1])*uint64_t(d[2]); } @@ -1394,7 +1377,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return !(CoordT::lessThan(this->max(), b.min()) || CoordT::lessThan(b.max(), this->min())); } -@@ -1826,6 +2077,8 @@ +@@ -1826,6 +2077,8 @@ __hostdev__ static inline uint32_t FindLowestOn(uint32_t v) return static_cast(index); #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) return static_cast(__builtin_ctzl(v)); @@ -1403,7 +1386,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #else //#warning Using software implementation for FindLowestOn(uint32_t) static const unsigned char DeBruijn[32] = { -@@ -1856,6 +2109,8 @@ +@@ -1856,6 +2109,8 @@ __hostdev__ static inline uint32_t FindHighestOn(uint32_t v) return static_cast(index); #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(v); @@ -1412,7 +1395,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #else //#warning Using software implementation for FindHighestOn(uint32_t) static const unsigned char DeBruijn[32] = { -@@ -1884,6 +2139,8 @@ +@@ -1884,6 +2139,8 @@ __hostdev__ static inline uint32_t FindLowestOn(uint64_t v) return static_cast(index); #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) return static_cast(__builtin_ctzll(v)); @@ -1421,7 +1404,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #else //#warning Using software implementation for FindLowestOn(uint64_t) static const unsigned char DeBruijn[64] = { -@@ -1918,6 +2175,8 @@ +@@ -1918,6 +2175,8 @@ __hostdev__ static inline uint32_t FindHighestOn(uint64_t v) return static_cast(index); #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) return sizeof(unsigned long) * 8 - 1 - __builtin_clzll(v); @@ -1430,7 +1413,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #else const uint32_t* p = reinterpret_cast(&v); return p[1] ? 32u + FindHighestOn(p[1]) : FindHighestOn(p[0]); -@@ -1955,8 +2214,8 @@ +@@ -1955,8 +2214,8 @@ __hostdev__ inline uint32_t CountOn(uint64_t v) template class Mask { @@ -1441,7 +1424,7 @@ Index: nanovdb/nanovdb/NanoVDB.h uint64_t mWords[WORD_COUNT]; public: -@@ -1973,7 +2232,7 @@ +@@ -1973,7 +2232,7 @@ public: __hostdev__ uint32_t countOn() const { uint32_t sum = 0, n = WORD_COUNT; @@ -1450,7 +1433,7 @@ Index: nanovdb/nanovdb/NanoVDB.h sum += CountOn(*w); return sum; } -@@ -1982,7 +2241,7 @@ +@@ -1982,7 +2241,7 @@ public: inline __hostdev__ uint32_t countOn(uint32_t i) const { uint32_t n = i >> 6, sum = CountOn( mWords[n] & ((uint64_t(1) << (i & 63u))-1u) ); @@ -1459,7 +1442,7 @@ Index: nanovdb/nanovdb/NanoVDB.h return sum; } -@@ -1990,13 +2249,21 @@ +@@ -1990,13 +2249,21 @@ public: class Iterator { public: @@ -1485,7 +1468,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mPos = mParent->findNext(mPos + 1); return *this; -@@ -2010,7 +2277,7 @@ +@@ -2010,7 +2277,7 @@ public: private: uint32_t mPos; @@ -1494,7 +1477,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // Member class Iterator using OnIterator = Iterator; -@@ -2034,7 +2301,7 @@ +@@ -2034,7 +2301,7 @@ public: } /// @brief Copy constructor @@ -1503,7 +1486,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = other.mWords[i]; -@@ -2042,29 +2309,29 @@ +@@ -2042,36 +2309,36 @@ public: /// @brief Return a const reference to the nth word of the bit mask, for a word of arbitrary size. template @@ -1540,7 +1523,6 @@ Index: nanovdb/nanovdb/NanoVDB.h for (uint32_t i = 0; i < WORD_COUNT; ++i) { *dst++ = *src++; } -@@ -2071,7 +2338,7 @@ return *this; } @@ -1549,7 +1531,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { for (uint32_t i = 0; i < WORD_COUNT; ++i) { if (mWords[i] != other.mWords[i]) return false; -@@ -2079,16 +2346,18 @@ +@@ -2079,22 +2346,33 @@ public: return true; } @@ -1573,7 +1555,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { for (uint32_t i = 0; i < WORD_COUNT; ++i) if (mWords[i] != ~uint64_t(0)) -@@ -2095,6 +2364,15 @@ return false; return true; } @@ -1589,7 +1570,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Return true if none of the bits are set in this Mask. __hostdev__ bool isOff() const -@@ -2115,7 +2393,7 @@ +@@ -2115,7 +2393,7 @@ public: __hostdev__ void set(uint32_t n, bool On) { #if 1 // switch between branchless @@ -1598,7 +1579,7 @@ Index: nanovdb/nanovdb/NanoVDB.h n &= 63; word &= ~(uint64_t(1) << n); word |= uint64_t(On) << n; -@@ -2149,40 +2427,40 @@ +@@ -2149,40 +2427,40 @@ public: __hostdev__ void toggle() { uint32_t n = WORD_COUNT; @@ -1652,7 +1633,7 @@ Index: nanovdb/nanovdb/NanoVDB.h for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 ^= *w2; return *this; } -@@ -2194,7 +2472,7 @@ +@@ -2194,7 +2472,7 @@ private: __hostdev__ uint32_t findFirst() const { uint32_t n = 0; @@ -1661,7 +1642,7 @@ Index: nanovdb/nanovdb/NanoVDB.h for (; n @@ -1702,13 +1683,13 @@ Index: nanovdb/nanovdb/NanoVDB.h template - __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const + __hostdev__ Vec3T applyInverseMap(__local__ const Vec3T& xyz) const __global__ - { ++ { + return matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2])); + } +#endif + template + __hostdev__ Vec3T applyInverseMapF(const __global__ Vec3T& xyz) const __global__ -+ { + { return matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2])); } +#if defined(__KERNEL_METAL__) @@ -1751,7 +1732,7 @@ Index: nanovdb/nanovdb/NanoVDB.h mTaperF = static_cast(taper); mTaperD = taper; for (int i = 0; i < 3; ++i) { -@@ -2295,8 +2593,19 @@ +@@ -2295,8 +2593,19 @@ __hostdev__ inline void Map::set(const Mat3T& mat, const Mat3T& invMat, const Ve } template @@ -1772,7 +1753,7 @@ Index: nanovdb/nanovdb/NanoVDB.h const double mat[3][3] = { {dx, 0.0, 0.0}, // row 0 {0.0, dx, 0.0}, // row 1 -@@ -2306,6 +2615,7 @@ +@@ -2306,6 +2615,7 @@ __hostdev__ inline void Map::set(double dx, const Vec3T &trans, double taper) {0.0, idx, 0.0}, // row 1 {0.0, 0.0, idx}, // row 2 }; @@ -1780,7 +1761,7 @@ Index: nanovdb/nanovdb/NanoVDB.h this->set(mat, invMat, trans, taper); } -@@ -2313,7 +2623,7 @@ +@@ -2313,7 +2623,7 @@ __hostdev__ inline void Map::set(double dx, const Vec3T &trans, double taper) struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData { @@ -1789,7 +1770,7 @@ Index: nanovdb/nanovdb/NanoVDB.h int64_t mByteOffset; // byte offset to the blind data, relative to the GridData. uint64_t mElementCount; // number of elements, e.g. point count uint32_t mFlags; // flags -@@ -2328,10 +2638,10 @@ +@@ -2328,10 +2638,10 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData return blindDataCount * sizeof(GridBlindMetaData); } @@ -1802,7 +1783,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // GridBlindMetaData -@@ -2430,7 +2740,7 @@ +@@ -2430,7 +2740,7 @@ struct NodeTrait /// @note No client code should (or can) interface with this struct so it can safely be ignored! struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData {// sizeof(GridData) = 672B @@ -1811,7 +1792,7 @@ Index: nanovdb/nanovdb/NanoVDB.h uint64_t mMagic; // 8B (0) magic to validate it is valid grid data. uint64_t mChecksum; // 8B (8). Checksum of grid buffer. Version mVersion;// 4B (16) major, minor, and patch version numbers -@@ -2450,8 +2760,8 @@ +@@ -2450,8 +2760,8 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData uint64_t mData1, mData2;// 2x8B (656) padding to 32 B alignment. mData1 is use for the total number of values indexed by an IndexGrid // Set and unset various bit flags @@ -1822,7 +1803,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (on) { mFlags |= static_cast(GridFlags::HasMinMax); -@@ -2459,7 +2769,7 @@ +@@ -2459,7 +2769,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData mFlags &= ~static_cast(GridFlags::HasMinMax); } } @@ -1831,7 +1812,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (on) { mFlags |= static_cast(GridFlags::HasBBox); -@@ -2467,7 +2777,7 @@ +@@ -2467,7 +2777,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData mFlags &= ~static_cast(GridFlags::HasBBox); } } @@ -1840,7 +1821,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (on) { mFlags |= static_cast(GridFlags::HasLongGridName); -@@ -2475,7 +2785,7 @@ +@@ -2475,7 +2785,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData mFlags &= ~static_cast(GridFlags::HasLongGridName); } } @@ -1849,7 +1830,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (on) { mFlags |= static_cast(GridFlags::HasAverage); -@@ -2483,7 +2793,7 @@ +@@ -2483,7 +2793,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData mFlags &= ~static_cast(GridFlags::HasAverage); } } @@ -1858,7 +1839,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (on) { mFlags |= static_cast(GridFlags::HasStdDeviation); -@@ -2491,7 +2801,7 @@ +@@ -2491,7 +2801,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData mFlags &= ~static_cast(GridFlags::HasStdDeviation); } } @@ -1867,7 +1848,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (on) { mFlags |= static_cast(GridFlags::IsBreadthFirst); -@@ -2502,37 +2812,49 @@ +@@ -2502,37 +2812,49 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData // Affine transformations based on double precision template @@ -1930,7 +1911,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { NANOVDB_ASSERT(n < mBlindMetadataCount); return PtrAdd(this, mBlindMetadataOffset) + n; -@@ -2552,8 +2874,17 @@ +@@ -2552,8 +2874,17 @@ using DefaultReadAccessor = ReadAccessor; /// /// @note This the API of this class to interface with client code template @@ -1949,7 +1930,7 @@ Index: nanovdb/nanovdb/NanoVDB.h public: using TreeType = TreeT; using RootType = typename TreeT::RootType; -@@ -2566,183 +2897,195 @@ +@@ -2566,183 +2897,195 @@ public: /// @brief Disallow constructions, copy and assignment /// /// @note Only a Serializer, defined elsewhere, can instantiate this class @@ -1987,7 +1968,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// /// @note This method is only defined for IndexGrid = NanoGrid template -- __hostdev__ typename enable_if::value, uint64_t>::type valueCount() const {return DataType::mData1;} +- __hostdev__ typename enable_if::value, const uint64_t&>::type valueCount() const {return DataType::mData1;} + __hostdev__ typename enable_if::value, uint64_t>::type valueCount() const {return BASE(mData1);} /// @brief Return a const reference to the tree @@ -2014,12 +1995,12 @@ Index: nanovdb/nanovdb/NanoVDB.h template - __hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); } + __hostdev__ Vec3T worldToIndex(__global__ const Vec3T& xyz) const __global__ { return BASE(applyInverseMap)(xyz); } - ++ +#if defined(__KERNEL_METAL__) + template + __hostdev__ Vec3T worldToIndex(__local__ const Vec3T& xyz) const __global__ { return BASE(applyInverseMap)(xyz); } +#endif -+ + /// @brief index to world space transformation template - __hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); } @@ -2190,11 +2171,11 @@ Index: nanovdb/nanovdb/NanoVDB.h NANOVDB_ASSERT(n < DataType::mBlindMetadataCount); return this->blindMetaData(n).template getBlindData(); } +- +- __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return *DataType::blindMetaData(n); } + + __hostdev__ __global__ const GridBlindMetaData& blindMetaData(uint32_t n) const __global__ { return *BASE(blindMetaData)(n); } -- __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return *DataType::blindMetaData(n); } -- private: static_assert(sizeof(GridData) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(GridData) is misaligned"); }; // Class Grid @@ -2205,7 +2186,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { for (uint32_t i = 0, n = this->blindDataCount(); i < n; ++i) if (this->blindMetaData(i).mSemantic == semantic) -@@ -2762,14 +3105,14 @@ +@@ -2762,14 +3105,14 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) TreeData uint64_t mVoxelCount;// 8B, total number of active voxels in the root and all its child nodes. // No padding since it's always 32B aligned template @@ -2224,7 +2205,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mNodeOffset[NodeT::LEVEL] = node ? PtrDiff(node, this) : 0; } -@@ -2795,8 +3138,17 @@ +@@ -2795,8 +3138,17 @@ struct GridTree /// @brief VDB Tree, which is a thin wrapper around a RootNode. template @@ -2243,7 +2224,7 @@ Index: nanovdb/nanovdb/NanoVDB.h static_assert(RootT::LEVEL == 3, "Tree depth is not supported"); static_assert(RootT::ChildNodeType::LOG2DIM == 5, "Tree configuration is not supported"); static_assert(RootT::ChildNodeType::ChildNodeType::LOG2DIM == 4, "Tree configuration is not supported"); -@@ -2817,47 +3169,54 @@ +@@ -2817,79 +3169,86 @@ public: using Node0 = LeafNodeType; /// @brief This class cannot be constructed or deleted @@ -2315,7 +2296,6 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Return the total number of active tiles at the specified level of the tree. /// -@@ -2864,23 +3223,23 @@ /// @details level = 1,2,3 corresponds to active tile count in lower internal nodes, upper /// internal nodes, and the root level. Note active values at the leaf level are /// referred to as active voxels (see activeVoxelCount defined above). @@ -2345,7 +2325,6 @@ Index: nanovdb/nanovdb/NanoVDB.h } /// @brief return a pointer to the first node of the specified type -@@ -2887,9 +3246,9 @@ /// /// @warning Note it may return NULL if no nodes exist template @@ -2357,7 +2336,7 @@ Index: nanovdb/nanovdb/NanoVDB.h return offset>0 ? PtrAdd(this, offset) : nullptr; } -@@ -2897,9 +3256,9 @@ +@@ -2897,9 +3256,9 @@ public: /// /// @warning Note it may return NULL if no nodes exist template @@ -2369,7 +2348,7 @@ Index: nanovdb/nanovdb/NanoVDB.h return offset>0 ? PtrAdd(this, offset) : nullptr; } -@@ -2907,8 +3266,8 @@ +@@ -2907,8 +3266,8 @@ public: /// /// @warning Note it may return NULL if no nodes exist template @@ -2380,7 +2359,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return this->template getFirstNode::type>(); } -@@ -2917,27 +3276,28 @@ +@@ -2917,27 +3276,28 @@ public: /// /// @warning Note it may return NULL if no nodes exist template @@ -2418,7 +2397,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { min = this->root().minimum(); max = this->root().maximum(); -@@ -2955,13 +3315,13 @@ +@@ -2955,13 +3315,13 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData using BuildT = typename ChildT::BuildType;// in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool using CoordT = typename ChildT::CoordType; using StatsT = typename ChildT::FloatType; @@ -2434,7 +2413,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof"); static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys"); -@@ -2969,9 +3329,20 @@ +@@ -2969,17 +3329,28 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // y is the middle 21 bits (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // x is the upper 21 bits } @@ -2442,8 +2421,7 @@ Index: nanovdb/nanovdb/NanoVDB.h +#if defined(__KERNEL_METAL__) + template + __hostdev__ static KeyT CoordToKey(__local__ const CoordType& ijk) - { -- static constexpr uint64_t MASK = (1u << 21) - 1; ++ { + static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof"); + static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys"); + return (KeyT(uint32_t(ijk[2]) >> ChildT::TOTAL)) | // z is the lower 21 bits @@ -2453,11 +2431,11 @@ Index: nanovdb/nanovdb/NanoVDB.h +#endif + static __constant__ constexpr uint64_t MASK = (1u << 21) - 1; + __hostdev__ static CoordT KeyToCoord(__global__ const KeyT& key) -+ { + { +- static constexpr uint64_t MASK = (1u << 21) - 1; return CoordT(((key >> 42) & MASK) << ChildT::TOTAL, ((key >> 21) & MASK) << ChildT::TOTAL, (key & MASK) << ChildT::TOTAL); -@@ -2978,8 +3349,8 @@ } #else using KeyT = CoordT; @@ -2468,7 +2446,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #endif BBox mBBox; // 24B. AABB of active values in index space. uint32_t mTableSize; // 4B. number of tiles and child pointers in the root node -@@ -3000,13 +3371,13 @@ +@@ -3000,23 +3371,23 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) Tile { template @@ -2484,7 +2462,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { key = CoordToKey(k); state = s; -@@ -3013,10 +3384,10 @@ value = v; child = 0; } @@ -2499,7 +2476,7 @@ Index: nanovdb/nanovdb/NanoVDB.h KeyT key; // USE_SINGLE_ROOT_KEY ? 8B : 12B int64_t child; // 8B. signed byte offset from this node to the child node. 0 means it is a constant tile, so use value. uint32_t state; // 4B. state of tile value -@@ -3026,53 +3397,64 @@ +@@ -3026,53 +3397,64 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData /// @brief Returns a non-const reference to the tile at the specified linear offset. /// /// @warning The linear offset is assumed to be in the valid range @@ -2581,7 +2558,7 @@ Index: nanovdb/nanovdb/NanoVDB.h using DataType = RootData; using LeafNodeType = typename ChildT::LeafNodeType; using ChildNodeType = ChildT; -@@ -3086,27 +3468,27 @@ +@@ -3086,27 +3468,27 @@ public: using BBoxType = BBox; using AccessorType = DefaultReadAccessor; using Tile = typename DataType::Tile; @@ -2618,7 +2595,7 @@ Index: nanovdb/nanovdb/NanoVDB.h NANOVDB_ASSERT(mParent); ++mPos; while (mPos < mSize && mParent->tile(mPos)->isValue()) ++mPos; -@@ -3123,21 +3505,21 @@ +@@ -3123,21 +3505,21 @@ public: class ValueIterator { @@ -2645,7 +2622,7 @@ Index: nanovdb/nanovdb/NanoVDB.h NANOVDB_ASSERT(mParent); ++mPos; while (mPos < mSize && mParent->tile(mPos)->isChild()) ++mPos; -@@ -3154,20 +3536,20 @@ +@@ -3154,20 +3536,20 @@ public: class ValueOnIterator { @@ -2670,7 +2647,7 @@ Index: nanovdb/nanovdb/NanoVDB.h NANOVDB_ASSERT(mParent); ++mPos; while (mPos < mSize && !mParent->tile(mPos)->isActive()) ++mPos; -@@ -3183,75 +3565,107 @@ +@@ -3183,75 +3565,107 @@ public: ValueOnIterator beginValueOn() const {return ValueOnIterator(this);} /// @brief This class cannot be constructed or deleted @@ -2744,9 +2721,13 @@ Index: nanovdb/nanovdb/NanoVDB.h } return DataType::mBackground; } +- +- __hostdev__ bool isActive(const CoordType& ijk) const +#if defined(__KERNEL_METAL__) + __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ -+ { + { +- if (const Tile* tile = this->probeTile(ijk)) { +- return tile->isChild() ? this->getChild(tile)->isActive(ijk) : tile->state; + if (__global__ const Tile* tile = this->findTile(ijk)) { + return tile->isChild() ? this->getChild(tile)->getValue(ijk) : tile->value; + } @@ -2760,12 +2741,9 @@ Index: nanovdb/nanovdb/NanoVDB.h + return DataType::mBackground; + } +#endif - -- __hostdev__ bool isActive(const CoordType& ijk) const ++ + __hostdev__ bool isActive(__global__ const CoordType& ijk) const __global__ - { -- if (const Tile* tile = this->probeTile(ijk)) { -- return tile->isChild() ? this->getChild(tile)->isActive(ijk) : tile->state; ++ { + if (__global__ const Tile* tile = this->findTile(ijk)) { + return tile->isChild() ? BASE(getChild)(tile)->isActive(ijk) : tile->state; } @@ -2803,13 +2781,16 @@ Index: nanovdb/nanovdb/NanoVDB.h return child->probeValue(ijk, v); } v = tile->value; -@@ -3260,20 +3674,35 @@ +@@ -3260,33 +3674,49 @@ public: v = DataType::mBackground; return false; } +- +- __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const +#if defined(__KERNEL_METAL__) + __hostdev__ bool probeValue(__local__ const CoordType& ijk, __local__ ValueType& v) const __global__ -+ { + { +- const Tile* tile = this->probeTile(ijk); + if (__global__ const Tile* tile = this->findTile(ijk)) { + if (tile->isChild()) { + __global__ const auto *child = BASE(getChild)(tile); @@ -2822,11 +2803,9 @@ Index: nanovdb/nanovdb/NanoVDB.h + return false; + } +#endif - -- __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const ++ + __hostdev__ __global__ const LeafNodeType* probeLeaf(__global__ const CoordType& ijk) const - { -- const Tile* tile = this->probeTile(ijk); ++ { + __global__ const Tile* tile = this->probeTile(ijk); if (tile && tile->isChild()) { - const auto *child = this->getChild(tile); @@ -2844,7 +2823,6 @@ Index: nanovdb/nanovdb/NanoVDB.h if (tile && tile->isChild()) { return this->getChild(tile); } -@@ -3280,13 +3709,14 @@ return nullptr; } @@ -2863,7 +2841,7 @@ Index: nanovdb/nanovdb/NanoVDB.h if (tiles[i].key == key) return &tiles[i]; } #else// do not enable binary search if tiles are not guaranteed to be sorted!!!!!! -@@ -3306,6 +3736,33 @@ +@@ -3306,6 +3736,33 @@ public: #endif return nullptr; } @@ -2897,7 +2875,7 @@ Index: nanovdb/nanovdb/NanoVDB.h private: static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData) is misaligned"); -@@ -3319,12 +3776,12 @@ +@@ -3319,12 +3776,12 @@ private: /// @brief Private method to return node information and update a ReadAccessor template @@ -2913,7 +2891,7 @@ Index: nanovdb/nanovdb/NanoVDB.h acc.insert(ijk, child); return child->getNodeInfoAndCache(ijk, acc); } -@@ -3337,11 +3794,11 @@ +@@ -3337,11 +3794,11 @@ private: /// @brief Private method to return a voxel value and update a ReadAccessor template @@ -2928,7 +2906,7 @@ Index: nanovdb/nanovdb/NanoVDB.h acc.insert(ijk, child); return child->getValueAndCache(ijk, acc); } -@@ -3349,25 +3806,66 @@ +@@ -3349,25 +3806,66 @@ private: } return DataType::mBackground; } @@ -3001,7 +2979,7 @@ Index: nanovdb/nanovdb/NanoVDB.h acc.insert(ijk, child); return child->probeValueAndCache(ijk, v, acc); } -@@ -3379,11 +3877,11 @@ +@@ -3379,11 +3877,11 @@ private: } template @@ -3016,7 +2994,7 @@ Index: nanovdb/nanovdb/NanoVDB.h acc.insert(ijk, child); return child->probeLeafAndCache(ijk, acc); } -@@ -3391,11 +3889,11 @@ +@@ -3391,11 +3889,11 @@ private: } template @@ -3031,7 +3009,7 @@ Index: nanovdb/nanovdb/NanoVDB.h acc.insert(ijk, child); return child->getDimAndCache(ijk, ray, acc); } -@@ -3403,7 +3901,23 @@ +@@ -3403,7 +3901,23 @@ private: } return ChildNodeType::dim(); // background } @@ -3055,7 +3033,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // RootNode class // After the RootNode the memory layout is assumed to be the sorted Tiles -@@ -3421,7 +3935,7 @@ +@@ -3421,7 +3935,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData using StatsT = typename ChildT::FloatType; using CoordT = typename ChildT::CoordType; using MaskT = typename ChildT::template MaskType; @@ -3064,7 +3042,7 @@ Index: nanovdb/nanovdb/NanoVDB.h union Tile { -@@ -3429,8 +3943,8 @@ +@@ -3429,8 +3943,8 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData int64_t child;//signed 64 bit byte offset relative to the InternalData!! /// @brief This class cannot be constructed or deleted Tile() = delete; @@ -3075,7 +3053,7 @@ Index: nanovdb/nanovdb/NanoVDB.h ~Tile() = delete; }; -@@ -3456,7 +3970,7 @@ +@@ -3456,32 +3970,32 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData __hostdev__ static uint64_t memUsage() { return sizeof(InternalData); } @@ -3084,7 +3062,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { NANOVDB_ASSERT(mChildMask.isOn(n)); mTable[n].child = PtrDiff(ptr, this); -@@ -3463,7 +3977,7 @@ } template @@ -3093,7 +3070,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { NANOVDB_ASSERT(!mChildMask.isOn(n)); mTable[n].value = v; -@@ -3470,18 +3984,18 @@ } /// @brief Returns a pointer to the child node at the specifed linear offset. @@ -3115,7 +3091,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { NANOVDB_ASSERT(!mChildMask.isOn(n)); return mTable[n].value; -@@ -3496,29 +4010,38 @@ +@@ -3496,29 +4010,38 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData __hostdev__ bool isChild(uint32_t n) const {return mChildMask.isOn(n);} template @@ -3166,7 +3142,7 @@ Index: nanovdb/nanovdb/NanoVDB.h public: using DataType = InternalData; using ValueType = typename DataType::ValueT; -@@ -3527,31 +4050,40 @@ +@@ -3527,76 +4050,109 @@ public: using LeafNodeType = typename ChildT::LeafNodeType; using ChildNodeType = ChildT; using CoordType = typename ChildT::CoordType; @@ -3221,7 +3197,6 @@ Index: nanovdb/nanovdb/NanoVDB.h __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return (*this)->origin();} }; // Member class ChildIterator -@@ -3558,45 +4090,69 @@ ChildIterator beginChild() const {return ChildIterator(this);} /// @brief Visits all tile values in this node, i.e. both inactive and active tiles @@ -3309,7 +3284,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32) __hostdev__ static uint32_t dim() { return 1u << TOTAL; } -@@ -3605,47 +4161,66 @@ +@@ -3605,47 +4161,66 @@ public: __hostdev__ static size_t memUsage() { return DataType::memUsage(); } /// @brief Return a const reference to the bit mask of active voxels in this internal node @@ -3388,7 +3363,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { const uint32_t n = CoordToOffset(ijk); if (DataType::mChildMask.isOn(n)) -@@ -3653,8 +4228,18 @@ +@@ -3653,8 +4228,18 @@ public: v = DataType::getValue(n); return DataType::isActive(n); } @@ -3408,7 +3383,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { const uint32_t n = CoordToOffset(ijk); if (DataType::mChildMask.isOn(n)) -@@ -3662,7 +4247,7 @@ +@@ -3662,14 +4247,14 @@ public: return nullptr; } @@ -3417,7 +3392,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { const uint32_t n = CoordToOffset(ijk); return DataType::mChildMask.isOn(n) ? this->getChild(n) : nullptr; -@@ -3669,7 +4254,7 @@ } /// @brief Return the linear offset corresponding to the given coordinate @@ -3426,7 +3400,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { #if 0 return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) + -@@ -3681,6 +4266,20 @@ +@@ -3681,6 +4266,20 @@ public: ((ijk[2] & MASK) >> ChildT::TOTAL); #endif } @@ -3447,7 +3421,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @return the local coordinate of the n'th tile or child node __hostdev__ static Coord OffsetToLocalCoord(uint32_t n) -@@ -3691,13 +4290,13 @@ +@@ -3691,13 +4290,13 @@ public: } /// @brief modifies local coordinates to global coordinates of a tile or child node @@ -3463,7 +3437,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { Coord ijk = InternalNode::OffsetToLocalCoord(n); this->localToGlobalCoord(ijk); -@@ -3705,13 +4304,24 @@ +@@ -3705,13 +4304,24 @@ public: } /// @brief Return true if this node or any of its child nodes contain active values @@ -3489,7 +3463,7 @@ Index: nanovdb/nanovdb/NanoVDB.h //static_assert(offsetof(DataType, mTable) % 32 == 0, "InternalData::mTable is misaligned"); template -@@ -3724,18 +4334,30 @@ +@@ -3724,18 +4334,30 @@ private: /// @brief Private read access method used by the ReadAccessor template @@ -3524,7 +3498,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { using NodeInfoT = typename AccT::NodeInfo; const uint32_t n = CoordToOffset(ijk); -@@ -3743,24 +4365,36 @@ +@@ -3743,61 +4365,91 @@ private: return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(), this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]}; } @@ -3565,7 +3539,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { const uint32_t n = CoordToOffset(ijk); if (!DataType::mChildMask.isOn(n)) { -@@ -3767,24 +4401,24 @@ v = DataType::getValue(n); return DataType::isActive(n); } @@ -3594,7 +3567,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (DataType::mFlags & uint32_t(1u)) return this->dim(); // skip this node if the 1st bit is set //if (!ray.intersects( this->bbox() )) return 1< LeafNode <------------------------------------ -@@ -3814,7 +4466,7 @@ +@@ -3814,7 +4466,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData using BuildType = ValueT; using FloatType = typename FloatTraits::FloatType; using ArrayType = ValueT;// type used for the internal mValue array @@ -3636,7 +3608,7 @@ Index: nanovdb/nanovdb/NanoVDB.h CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. -@@ -3826,7 +4478,7 @@ +@@ -3826,7 +4478,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData FloatType mAverage; // typically 4B, average of all the active values in this node and its child nodes FloatType mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes alignas(32) ValueType mValues[1u << 3 * LOG2DIM]; @@ -3645,7 +3617,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment /// /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members. -@@ -3838,32 +4490,35 @@ +@@ -3838,32 +4490,35 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } //__hostdev__ const ValueType* values() const { return mValues; } @@ -3697,7 +3669,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // LeafData /// @brief Base-class for quantized float leaf nodes -@@ -3892,7 +4547,7 @@ +@@ -3892,39 +4547,39 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafFnBase __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafFnBase) - (12 + 3 + 1 + sizeof(MaskT) + 2*4 + 4*2); } @@ -3706,7 +3678,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { mMinimum = min; mQuantum = (max - min)/float((1 << bitWidth)-1); -@@ -3899,32 +4554,32 @@ } /// @brief return the quantized minimum of the active values in this node @@ -3748,7 +3719,7 @@ Index: nanovdb/nanovdb/NanoVDB.h };// LeafFnBase /// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode) -@@ -3932,12 +4587,24 @@ +@@ -3932,12 +4587,24 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafFnBase /// @note No client code should (or can) interface with this struct so it can safely be ignored! template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData @@ -3774,7 +3745,7 @@ Index: nanovdb/nanovdb/NanoVDB.h alignas(32) uint8_t mCode[1u << (3 * LOG2DIM - 1)];// LeafFnBase is 32B aligned and so is mCode __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); } -@@ -3947,31 +4614,53 @@ +@@ -3947,31 +4614,53 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData> 5;// b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits +#if 0// use LUT + uint16_t code = reinterpret_cast(this + 1)[i >> (4 - b)]; @@ -3987,12 +3958,10 @@ Index: nanovdb/nanovdb/NanoVDB.h + } +#if defined(__KERNEL_METAL__) + __hostdev__ float getValue(uint32_t i) const __local__ -+ { -+#ifdef NANOVDB_FPN_BRANCHLESS// faster + { + #ifdef NANOVDB_FPN_BRANCHLESS// faster const int b = BaseT::mFlags >> 5;// b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits - #if 0// use LUT - uint16_t code = reinterpret_cast(this + 1)[i >> (4 - b)]; -@@ -4047,7 +4813,7 @@ +@@ -4047,14 +4813,14 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData>= (i & shift[b]) << b; code &= mask[b]; #else// no LUT @@ -4001,7 +3970,6 @@ Index: nanovdb/nanovdb/NanoVDB.h //code >>= (i & ((16 >> b) - 1)) << b; code >>= (i & ((32 >> b) - 1)) << b; code &= (1 << (1 << b)) - 1; -@@ -4054,7 +4820,7 @@ #endif #else// use branched version (slow) float code; @@ -4010,7 +3978,7 @@ Index: nanovdb/nanovdb/NanoVDB.h switch (BaseT::mFlags >> 5) { case 0u:// 1 bit float code = float((values[i>>3] >> (i&7) ) & uint8_t(1)); -@@ -4074,12 +4840,15 @@ +@@ -4074,12 +4840,15 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData // Partial template specialization of LeafData with bool -@@ -4092,7 +4861,7 @@ +@@ -4092,7 +4861,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData;// type used for the internal mValue array @@ -4039,7 +4007,7 @@ Index: nanovdb/nanovdb/NanoVDB.h CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. -@@ -4104,31 +4873,34 @@ +@@ -4104,31 +4873,34 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData) - 16u;} __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } @@ -4090,7 +4058,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // LeafData // Partial template specialization of LeafData with ValueMask -@@ -4141,7 +4913,7 @@ +@@ -4141,7 +4913,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData // Partial template specialization of LeafData with ValueIndex -@@ -4191,7 +4966,7 @@ +@@ -4191,7 +4966,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData /// @brief Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels) -@@ -4248,13 +5031,22 @@ +@@ -4248,13 +5031,22 @@ template class MaskT = Mask, uint32_t Log2Dim = 3> @@ -4246,7 +4213,7 @@ Index: nanovdb/nanovdb/NanoVDB.h __hostdev__ static uint32_t dim() { return 1u; } }; // Voxel using LeafNodeType = LeafNode; -@@ -4263,7 +5055,7 @@ +@@ -4263,38 +5055,56 @@ public: using FloatType = typename DataType::FloatType; using BuildType = typename DataType::BuildType; using CoordType = CoordT; @@ -4255,7 +4222,6 @@ Index: nanovdb/nanovdb/NanoVDB.h template using MaskType = MaskT; template -@@ -4270,31 +5062,49 @@ using MaskIterT = typename Mask::template Iterator; /// @brief Visits all active values in a leaf node @@ -4317,7 +4283,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // Member class ValueOffIterator ValueOffIterator beginValueOff() const {return ValueOffIterator(this);} -@@ -4302,17 +5112,17 @@ +@@ -4302,17 +5112,17 @@ public: /// @brief Visits all values in a leaf node, i.e. both active and inactive values class ValueIterator { @@ -4339,7 +4305,7 @@ Index: nanovdb/nanovdb/NanoVDB.h __hostdev__ ValueIterator operator++(int) { auto tmp = *this; ++(*this); -@@ -4320,43 +5130,49 @@ +@@ -4320,43 +5130,49 @@ public: } }; // Member class ValueIterator @@ -4406,7 +4372,7 @@ Index: nanovdb/nanovdb/NanoVDB.h __hostdev__ static CoordT OffsetToLocalCoord(uint32_t n) { -@@ -4366,9 +5182,9 @@ +@@ -4366,9 +5182,9 @@ public: } /// @brief Converts (in place) a local index coordinate to a global index coordinate @@ -4418,7 +4384,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return OffsetToLocalCoord(n) + this->origin(); } -@@ -4377,7 +5193,7 @@ +@@ -4377,7 +5193,7 @@ public: __hostdev__ static uint32_t dim() { return 1u << LOG2DIM; } /// @brief Return the bounding box in index space of active values in this leaf node @@ -4427,7 +4393,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { BBox bbox(DataType::mBBoxMin, DataType::mBBoxMin); if ( this->hasBBox() ) { -@@ -4399,54 +5215,85 @@ +@@ -4399,54 +5215,85 @@ public: __hostdev__ uint64_t memUsage() { return DataType::memUsage(); } /// @brief This class cannot be constructed or deleted @@ -4442,12 +4408,12 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Return the voxel value at the given offset. - __hostdev__ ValueType getValue(uint32_t offset) const { return DataType::getValue(offset); } - ++ + __hostdev__ ValueType getValue(uint32_t offset) const __global__ { return DataType::getValue(offset); } +#if defined(__KERNEL_METAL__) + __hostdev__ ValueType getValue(uint32_t offset) const __local__ { return DataType::getValue(offset); } +#endif -+ + /// @brief Return the voxel value at the given coordinate. - __hostdev__ ValueType getValue(const CoordT& ijk) const { return DataType::getValue(CoordToOffset(ijk)); } + __hostdev__ ValueType getValue(__global__ const CoordT& ijk) const __global__ { return BASE(getValue)(CoordToOffset(ijk)); } @@ -4478,12 +4444,12 @@ Index: nanovdb/nanovdb/NanoVDB.h + __hostdev__ bool isActive(__local__ const CoordT& ijk) const __global__ { return BASE(mValueMask).isOn(CoordToOffset(ijk)); } + __hostdev__ bool isActive(__local__ const CoordT& ijk) const __local__ { return BASE(mValueMask).isOn(CoordToOffset(ijk)); } +#endif - ++ + __hostdev__ bool isActive(uint32_t n) const __global__ { return BASE(mValueMask).isOn(n); } +#if defined(__KERNEL_METAL__) + __hostdev__ bool isActive(uint32_t n) const __local__ { return BASE(mValueMask).isOn(n); } +#endif -+ + /// @brief Return @c true if any of the voxel value are active in this leaf node. - __hostdev__ bool isActive() const + __hostdev__ bool isActive() const __global__ @@ -4529,7 +4495,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { #if 0 return ((ijk[0] & MASK) << (2 * LOG2DIM)) + ((ijk[1] & MASK) << LOG2DIM) + (ijk[2] & MASK); -@@ -4454,6 +5301,16 @@ +@@ -4454,6 +5301,16 @@ public: return ((ijk[0] & MASK) << (2 * LOG2DIM)) | ((ijk[1] & MASK) << LOG2DIM) | (ijk[2] & MASK); #endif } @@ -4546,7 +4512,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Updates the local bounding box of active voxels in this node. Return true if bbox was updated. /// -@@ -4461,8 +5318,9 @@ +@@ -4461,8 +5318,9 @@ public: /// /// @details This method is based on few (intrinsic) bit operations and hence is relatively fast. /// However, it should only only be called of either the value mask has changed or if the @@ -4557,7 +4523,7 @@ Index: nanovdb/nanovdb/NanoVDB.h private: static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(LeafData) is misaligned"); -@@ -4478,11 +5336,15 @@ +@@ -4478,49 +5336,77 @@ private: /// @brief Private method to return a voxel value and update a (dummy) ReadAccessor template @@ -4575,7 +4541,6 @@ Index: nanovdb/nanovdb/NanoVDB.h using NodeInfoT = typename AccT::NodeInfo; return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(), this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]}; -@@ -4489,16 +5351,20 @@ } template @@ -4600,7 +4565,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (DataType::mFlags & uint8_t(1u)) return this->dim(); // skip this node if the 1st bit is set -@@ -4505,11 +5371,21 @@ //if (!ray.intersects( this->bbox() )) return 1 << LOG2DIM; return ChildNodeType::dim(); } @@ -4624,7 +4588,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { static_assert(LOG2DIM == 3, "LeafNode::updateBBox: only supports LOGDIM = 3!"); if (DataType::mValueMask.isOff()) { -@@ -4516,11 +5392,21 @@ DataType::mFlags &= ~uint8_t(2);// set 2nd bit off, which indicates that this nodes has no bbox return false; } @@ -4646,7 +4609,7 @@ Index: nanovdb/nanovdb/NanoVDB.h uint64_t word64 = DataType::mValueMask.template getWord(0); uint32_t Xmin = word64 ? 0u : 8u; uint32_t Xmax = Xmin; -@@ -4534,6 +5420,17 @@ +@@ -4534,6 +5420,17 @@ __hostdev__ inline bool LeafNode::updateBBox() } } NANOVDB_ASSERT(word64); @@ -4664,7 +4627,7 @@ Index: nanovdb/nanovdb/NanoVDB.h update(Xmin, Xmax, 0); update(FindLowestOn(word64) >> 3, FindHighestOn(word64) >> 3, 1); const uint32_t *p = reinterpret_cast(&word64), word32 = p[0] | p[1]; -@@ -4541,8 +5438,9 @@ +@@ -4541,8 +5438,9 @@ __hostdev__ inline bool LeafNode::updateBBox() const uint8_t *b = reinterpret_cast(&word16), byte = b[0] | b[1]; NANOVDB_ASSERT(byte); update(FindLowestOn(static_cast(byte)), FindHighestOn(static_cast(byte)), 2); @@ -4675,7 +4638,7 @@ Index: nanovdb/nanovdb/NanoVDB.h } // LeafNode::updateBBox // --------------------------> Template specializations and traits <------------------------------------ -@@ -4651,12 +5549,12 @@ +@@ -4651,12 +5549,12 @@ class ReadAccessor using FloatType = typename RootT::FloatType; using CoordValueType = typename RootT::CoordType::ValueType; @@ -4690,7 +4653,7 @@ Index: nanovdb/nanovdb/NanoVDB.h struct NodeInfo { uint32_t mLevel; // 4B -@@ -4670,60 +5568,77 @@ +@@ -4670,60 +5568,77 @@ public: }; /// @brief Constructor from a root node @@ -4732,13 +4695,13 @@ Index: nanovdb/nanovdb/NanoVDB.h + +#if defined(__KERNEL_METAL__) + __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __local__ - { ++ { + return mRoot->getValueAndCache(ijk, *this); + } +#endif + + __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __local__ -+ { + { return this->getValue(ijk); } - __hostdev__ ValueType operator()(int i, int j, int k) const @@ -4783,7 +4746,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return mRoot->getDimAndCache(ijk, ray, *this); } -@@ -4739,7 +5654,11 @@ +@@ -4739,7 +5654,11 @@ private: /// @brief No-op template @@ -4796,7 +4759,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // ReadAccessor class /// @brief Node caching at a single tree level -@@ -4761,19 +5680,19 @@ +@@ -4761,19 +5680,19 @@ class ReadAccessor//e.g. 0, 1, 2 // All member data are mutable to allow for access methods to be const mutable CoordT mKey; // 3*4 = 12 bytes @@ -4820,7 +4783,7 @@ Index: nanovdb/nanovdb/NanoVDB.h : mKey(CoordType::max()) , mRoot(&root) , mNode(nullptr) -@@ -4781,10 +5700,10 @@ +@@ -4781,10 +5700,10 @@ public: } /// @brief Constructor from a grid @@ -4833,7 +4796,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Reset this access to its initial state, i.e. with an empty cache __hostdev__ void clear() -@@ -4793,21 +5712,38 @@ +@@ -4793,37 +5712,64 @@ public: mNode = nullptr; } @@ -4878,14 +4841,13 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (this->isCached(ijk)) { return mNode->getValueAndCache(ijk, *this); -@@ -4814,16 +5750,26 @@ } return mRoot->getValueAndCache(ijk, *this); } - __hostdev__ ValueType operator()(const CoordType& ijk) const +#if defined(__KERNEL_METAL__) + __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ - { ++ { + if (this->isCached(ijk)) { + return mNode->getValueAndCache(ijk, *this); + } @@ -4894,7 +4856,7 @@ Index: nanovdb/nanovdb/NanoVDB.h +#endif + + __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __global__ -+ { + { return this->getValue(ijk); } - __hostdev__ ValueType operator()(int i, int j, int k) const @@ -4908,7 +4870,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (this->isCached(ijk)) { return mNode->getNodeInfoAndCache(ijk, *this); -@@ -4831,7 +5777,7 @@ +@@ -4831,15 +5777,24 @@ public: return mRoot->getNodeInfoAndCache(ijk, *this); } @@ -4917,7 +4879,6 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (this->isCached(ijk)) { return mNode->isActiveAndCache(ijk, *this); -@@ -4838,8 +5784,17 @@ } return mRoot->isActiveAndCache(ijk, *this); } @@ -4936,7 +4897,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (this->isCached(ijk)) { return mNode->probeValueAndCache(ijk, v, *this); -@@ -4847,7 +5802,7 @@ +@@ -4847,7 +5802,7 @@ public: return mRoot->probeValueAndCache(ijk, v, *this); } @@ -4945,7 +4906,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (this->isCached(ijk)) { return mNode->probeLeafAndCache(ijk, *this); -@@ -4856,7 +5811,7 @@ +@@ -4856,7 +5811,7 @@ public: } template @@ -4954,7 +4915,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (this->isCached(ijk)) { return mNode->getDimAndCache(ijk, ray, *this); -@@ -4874,15 +5829,26 @@ +@@ -4874,15 +5829,26 @@ private: friend class LeafNode; /// @brief Inserts a leaf node and key pair into this ReadAccessor @@ -4983,7 +4944,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // ReadAccessor -@@ -4909,20 +5875,20 @@ +@@ -4909,20 +5875,20 @@ class ReadAccessor//e.g. (0,1), (1,2), (0,2) #else // 68 bytes total mutable CoordT mKeys[2]; // 2*3*4 = 24 bytes #endif @@ -5009,7 +4970,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #ifdef USE_SINGLE_ACCESSOR_KEY : mKey(CoordType::max()) #else -@@ -4935,10 +5901,10 @@ +@@ -4935,10 +5901,10 @@ public: } /// @brief Constructor from a grid @@ -5022,7 +4983,7 @@ Index: nanovdb/nanovdb/NanoVDB.h /// @brief Reset this access to its initial state, i.e. with an empty cache __hostdev__ void clear() -@@ -4952,15 +5918,18 @@ +@@ -4952,15 +5918,18 @@ public: mNode2 = nullptr; } @@ -5045,7 +5006,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (!mNode1) return false; -@@ -4970,7 +5939,7 @@ +@@ -4970,7 +5939,7 @@ public: } return true; } @@ -5054,7 +5015,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (!mNode2) return false; -@@ -4980,18 +5949,18 @@ +@@ -4980,18 +5949,18 @@ public: } return true; } @@ -5076,7 +5037,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return (ijk[0] & int32_t(~Node2T::MASK)) == mKeys[1][0] && (ijk[1] & int32_t(~Node2T::MASK)) == mKeys[1][1] && -@@ -4999,12 +5968,12 @@ +@@ -4999,12 +5968,12 @@ public: } #endif @@ -5091,17 +5052,27 @@ Index: nanovdb/nanovdb/NanoVDB.h #endif if (this->isCached1(dirty)) { return mNode1->getValueAndCache(ijk, *this); -@@ -5013,21 +5982,37 @@ +@@ -5013,21 +5982,37 @@ public: } return mRoot->getValueAndCache(ijk, *this); } - __hostdev__ ValueType operator()(const CoordType& ijk) const +- { +- return this->getValue(ijk); +- } +- __hostdev__ ValueType operator()(int i, int j, int k) const +- { +- return this->getValue(CoordType(i,j,k)); +- } +- +- __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const +#if defined(__KERNEL_METAL__) + __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ { -+#ifdef USE_SINGLE_ACCESSOR_KEY -+ const CoordValueType dirty = this->computeDirty(ijk); -+#else + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; + __global__ auto&& dirty = ijk; +#endif + if (this->isCached1(dirty)) { @@ -5114,26 +5085,23 @@ Index: nanovdb/nanovdb/NanoVDB.h +#endif + __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __global__ + { - return this->getValue(ijk); - } -- __hostdev__ ValueType operator()(int i, int j, int k) const ++ return this->getValue(ijk); ++ } + __hostdev__ ValueType operator()(int i, int j, int k) const __global__ - { - return this->getValue(CoordType(i,j,k)); - } - -- __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const ++ { ++ return this->getValue(CoordType(i,j,k)); ++ } ++ + __hostdev__ NodeInfo getNodeInfo(__global__ const CoordType& ijk) const __global__ - { - #ifdef USE_SINGLE_ACCESSOR_KEY - const CoordValueType dirty = this->computeDirty(ijk); - #else -- auto&& dirty = ijk; ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else + __global__ auto&& dirty = ijk; #endif if (this->isCached1(dirty)) { return mNode1->getNodeInfoAndCache(ijk, *this); -@@ -5037,12 +6022,12 @@ +@@ -5037,12 +6022,12 @@ public: return mRoot->getNodeInfoAndCache(ijk, *this); } @@ -5148,7 +5116,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #endif if (this->isCached1(dirty)) { return mNode1->isActiveAndCache(ijk, *this); -@@ -5052,12 +6037,12 @@ +@@ -5052,12 +6037,12 @@ public: return mRoot->isActiveAndCache(ijk, *this); } @@ -5163,7 +5131,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #endif if (this->isCached1(dirty)) { return mNode1->probeValueAndCache(ijk, v, *this); -@@ -5067,12 +6052,12 @@ +@@ -5067,12 +6052,12 @@ public: return mRoot->probeValueAndCache(ijk, v, *this); } @@ -5178,7 +5146,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #endif if (this->isCached1(dirty)) { return mNode1->probeLeafAndCache(ijk, *this); -@@ -5083,12 +6068,12 @@ +@@ -5083,12 +6068,12 @@ public: } template @@ -5193,7 +5161,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #endif if (this->isCached1(dirty)) { return mNode1->getDimAndCache(ijk, ray, *this); -@@ -5108,7 +6093,7 @@ +@@ -5108,7 +6093,7 @@ private: friend class LeafNode; /// @brief Inserts a leaf node and key pair into this ReadAccessor @@ -5202,7 +5170,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { #ifdef USE_SINGLE_ACCESSOR_KEY mKey = ijk; -@@ -5117,7 +6102,7 @@ +@@ -5117,7 +6102,7 @@ private: #endif mNode1 = node; } @@ -5211,7 +5179,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { #ifdef USE_SINGLE_ACCESSOR_KEY mKey = ijk; -@@ -5127,7 +6112,11 @@ +@@ -5127,7 +6112,11 @@ private: mNode2 = node; } template @@ -5224,7 +5192,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // ReadAccessor -@@ -5145,7 +6134,7 @@ +@@ -5145,7 +6134,7 @@ class ReadAccessor using ValueT = typename RootT::ValueType; using FloatType = typename RootT::FloatType; @@ -5233,7 +5201,7 @@ Index: nanovdb/nanovdb/NanoVDB.h // All member data are mutable to allow for access methods to be const #ifdef USE_SINGLE_ACCESSOR_KEY // 44 bytes total -@@ -5153,19 +6142,19 @@ +@@ -5153,19 +6142,19 @@ class ReadAccessor #else // 68 bytes total mutable CoordT mKeys[3]; // 3*3*4 = 36 bytes #endif @@ -5257,7 +5225,7 @@ Index: nanovdb/nanovdb/NanoVDB.h #ifdef USE_SINGLE_ACCESSOR_KEY : mKey(CoordType::max()) #else -@@ -5177,35 +6166,38 @@ +@@ -5177,35 +6166,38 @@ public: } /// @brief Constructor from a grid @@ -5306,7 +5274,7 @@ Index: nanovdb/nanovdb/NanoVDB.h } -@@ -5222,7 +6214,7 @@ +@@ -5222,7 +6214,7 @@ public: #ifdef USE_SINGLE_ACCESSOR_KEY template @@ -5315,7 +5283,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { if (!mNode[NodeT::LEVEL]) return false; -@@ -5233,128 +6225,229 @@ +@@ -5233,128 +6225,229 @@ public: return true; } @@ -5369,7 +5337,7 @@ Index: nanovdb/nanovdb/NanoVDB.h - __hostdev__ ValueType operator()(const CoordType& ijk) const +#if defined(__KERNEL_METAL__) + __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ - { ++ { +#ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); +#else @@ -5403,7 +5371,7 @@ Index: nanovdb/nanovdb/NanoVDB.h +#endif // __KERNEL_METAL__ + + __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __global__ -+ { + { return this->getValue(ijk); } - __hostdev__ ValueType operator()(int i, int j, int k) const @@ -5455,42 +5423,43 @@ Index: nanovdb/nanovdb/NanoVDB.h } return mRoot->isActiveAndCache(ijk, *this); } +- +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const +#if defined(__KERNEL_METAL__) + __hostdev__ bool isActive(__local__ const CoordType& ijk) const __local__ -+ { -+#ifdef USE_SINGLE_ACCESSOR_KEY -+ const CoordValueType dirty = this->computeDirty(ijk); -+#else -+ __local__ auto&& dirty = ijk; -+#endif -+ if (this->isCached(dirty)) { -+ return ((__global__ LeafT*)mNode[0])->isActive(ijk); -+ } else if (this->isCached(dirty)) { -+ return ((__global__ NodeT1*)mNode[1])->isActiveAndCache(ijk, *this); -+ } else if (this->isCached(dirty)) { -+ return ((__global__ NodeT2*)mNode[2])->isActiveAndCache(ijk, *this); -+ } -+ return mRoot->isActiveAndCache(ijk, *this); -+ } -+#endif - -- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const -+ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __global__ { #ifdef USE_SINGLE_ACCESSOR_KEY const CoordValueType dirty = this->computeDirty(ijk); #else - auto&& dirty = ijk; -+ __global__ auto&& dirty = ijk; ++ __local__ auto&& dirty = ijk; #endif if (this->isCached(dirty)) { - return ((LeafT*)mNode[0])->probeValue(ijk, v); -+ return ((__global__ LeafT*)mNode[0])->probeValue(ijk, v); ++ return ((__global__ LeafT*)mNode[0])->isActive(ijk); } else if (this->isCached(dirty)) { - return ((NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this); -+ return ((__global__ NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this); ++ return ((__global__ NodeT1*)mNode[1])->isActiveAndCache(ijk, *this); } else if (this->isCached(dirty)) { - return ((NodeT2*)mNode[2])->probeValueAndCache(ijk, v, *this); ++ return ((__global__ NodeT2*)mNode[2])->isActiveAndCache(ijk, *this); ++ } ++ return mRoot->isActiveAndCache(ijk, *this); ++ } ++#endif ++ ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __global__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else ++ __global__ auto&& dirty = ijk; ++#endif ++ if (this->isCached(dirty)) { ++ return ((__global__ LeafT*)mNode[0])->probeValue(ijk, v); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this); ++ } else if (this->isCached(dirty)) { + return ((__global__ NodeT2*)mNode[2])->probeValueAndCache(ijk, v, *this); } return mRoot->probeValueAndCache(ijk, v, *this); @@ -5579,7 +5548,7 @@ Index: nanovdb/nanovdb/NanoVDB.h private: /// @brief Allow nodes to insert themselves into the cache. -@@ -5367,7 +6460,7 @@ +@@ -5367,7 +6460,7 @@ private: /// @brief Inserts a leaf node and key pair into this ReadAccessor template @@ -5588,7 +5557,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { #ifdef USE_SINGLE_ACCESSOR_KEY mKey = ijk; -@@ -5376,6 +6469,28 @@ +@@ -5376,6 +6469,28 @@ private: #endif mNode[NodeT::LEVEL] = node; } @@ -5617,7 +5586,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // ReadAccessor ////////////////////////////////////////////////// -@@ -5393,19 +6508,19 @@ +@@ -5393,19 +6508,19 @@ private: /// createAccessor<0,1,2>(grid): Caching of all nodes at all tree levels template @@ -5640,7 +5609,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { return ReadAccessor(root); } -@@ -5424,52 +6539,59 @@ +@@ -5424,52 +6539,59 @@ class GridMetaData // memory-layout of the data structure and the reasons why certain methods are safe // to call and others are not! using GridT = NanoGrid; @@ -5732,7 +5701,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { NANOVDB_ASSERT(grid.gridType() == GridType::UInt32); NANOVDB_ASSERT((grid.gridClass() == GridClass::PointIndex && is_same::value) || -@@ -5478,7 +6600,7 @@ +@@ -5478,7 +6600,7 @@ public: } /// @brief Return the total number of point in the grid and set the /// iterators to the complete range of points. @@ -5741,7 +5710,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { const uint64_t count = mGrid->blindMetaData(0u).mElementCount; begin = mData; -@@ -5488,9 +6610,9 @@ +@@ -5488,9 +6610,9 @@ public: /// @brief Return the number of points in the leaf node containing the coordinate @a ijk. /// If this return value is larger than zero then the iterators @a begin and @a end /// will point to all the attributes contained within that leaf node. @@ -5753,7 +5722,7 @@ Index: nanovdb/nanovdb/NanoVDB.h if (leaf == nullptr) { return 0; } -@@ -5500,14 +6622,14 @@ +@@ -5500,14 +6622,14 @@ public: } /// @brief get iterators over offsets to points at a specific voxel location @@ -5771,7 +5740,7 @@ Index: nanovdb/nanovdb/NanoVDB.h begin = p + (offset == 0 ? 0 : leaf->getValue(offset - 1)); end = p + leaf->getValue(offset); return end - begin; -@@ -5520,11 +6642,20 @@ +@@ -5520,11 +6642,20 @@ public: /// /// @note The ChannelT template parameter can be either const and non-const. template @@ -5795,7 +5764,7 @@ Index: nanovdb/nanovdb/NanoVDB.h public: using ValueType = ChannelT; -@@ -5533,7 +6664,7 @@ +@@ -5533,7 +6664,7 @@ public: /// @brief Ctor from an IndexGrid and an integer ID of an internal channel /// that is assumed to exist as blind data in the IndexGrid. @@ -5804,7 +5773,7 @@ Index: nanovdb/nanovdb/NanoVDB.h : BaseT(grid.tree().root()) , mGrid(grid) , mChannel(nullptr) -@@ -5544,7 +6675,7 @@ +@@ -5544,7 +6675,7 @@ public: } /// @brief Ctor from an IndexGrid and an external channel @@ -5813,7 +5782,7 @@ Index: nanovdb/nanovdb/NanoVDB.h : BaseT(grid.tree().root()) , mGrid(grid) , mChannel(channelPtr) -@@ -5555,19 +6686,19 @@ +@@ -5555,19 +6686,19 @@ public: } /// @brief Return a const reference to the IndexGrid @@ -5838,7 +5807,7 @@ Index: nanovdb/nanovdb/NanoVDB.h { mChannel = channelPtr; NANOVDB_ASSERT(mChannel); -@@ -5577,23 +6708,24 @@ +@@ -5577,23 +6708,24 @@ public: /// in the IndexGrid. __hostdev__ void setChannel(uint32_t channelID) { @@ -5871,7 +5840,7 @@ Index: nanovdb/nanovdb/NanoVDB.h v = mChannel[idx]; return isActive; } -@@ -5601,7 +6733,7 @@ +@@ -5601,7 +6733,7 @@ public: /// /// @note The template parameter can be either const or non-const template @@ -5880,7 +5849,7 @@ Index: nanovdb/nanovdb/NanoVDB.h }; // ChannelAccessor -@@ -5643,6 +6775,7 @@ +@@ -5643,6 +6775,7 @@ namespace io { /// @throw std::invalid_argument if buffer does not point to a valid NanoVDB grid. /// /// @warning This is pretty ugly code that involves lots of pointer and bit manipulations - not for the faint of heart :) @@ -5888,7 +5857,7 @@ Index: nanovdb/nanovdb/NanoVDB.h template // StreamT class must support: "void write(char*, size_t)" void writeUncompressedGrid(StreamT &os, const void *buffer) { -@@ -5768,7 +6901,7 @@ +@@ -5768,7 +6901,7 @@ VecT readUncompressedGrids(const char *fileName, const typename Gri } return readUncompressedGrids(is, buffer); }// readUncompressedGrids @@ -5897,10 +5866,10 @@ Index: nanovdb/nanovdb/NanoVDB.h } // namespace io #endif// if !defined(__CUDA_ARCH__) && !defined(__HIP__) -Index: nanovdb/nanovdb/util/SampleFromVoxels.h -=================================================================== ---- nanovdb/nanovdb/util/SampleFromVoxels.h (revision 63221) -+++ nanovdb/nanovdb/util/SampleFromVoxels.h (working copy) +diff --git a/nanovdb/nanovdb/util/SampleFromVoxels.h b/nanovdb/nanovdb/util/SampleFromVoxels.h +index e779d66..e2f9283 100644 +--- a/nanovdb/nanovdb/util/SampleFromVoxels.h ++++ b/nanovdb/nanovdb/util/SampleFromVoxels.h @@ -1,983 +1,1120 @@ -// Copyright Contributors to the OpenVDB Project -// SPDX-License-Identifier: MPL-2.0 diff --git a/extern/audaspace/src/sequence/AnimateableProperty.cpp b/extern/audaspace/src/sequence/AnimateableProperty.cpp index c9c2a358219a..b38827f5cc79 100644 --- a/extern/audaspace/src/sequence/AnimateableProperty.cpp +++ b/extern/audaspace/src/sequence/AnimateableProperty.cpp @@ -184,6 +184,12 @@ void AnimateableProperty::read(float position, float* out) t = 0; } + if(position < 0) + { + position = 0; + t = 0; + } + if(t == 0) { std::memcpy(out, getBuffer() + int(std::floor(position)) * m_count, m_count * sizeof(float)); diff --git a/intern/cycles/bvh/split.cpp b/intern/cycles/bvh/split.cpp index e62f9fda9ef6..08602f59cca3 100644 --- a/intern/cycles/bvh/split.cpp +++ b/intern/cycles/bvh/split.cpp @@ -425,6 +425,7 @@ void BVHSpatialSplit::split_point_primitive(const PointCloud *pointcloud, /* No real splitting support for points, assume they are small enough for it * not to matter. */ float3 point = pointcloud->get_points()[prim_index]; + float radius = pointcloud->get_radius()[prim_index]; if (tfm != NULL) { point = transform_point(tfm, point); @@ -432,11 +433,11 @@ void BVHSpatialSplit::split_point_primitive(const PointCloud *pointcloud, point = get_unaligned_point(point); if (point[dim] <= pos) { - left_bounds.grow(point); + left_bounds.grow(point, radius); } if (point[dim] >= pos) { - right_bounds.grow(point); + right_bounds.grow(point, radius); } } diff --git a/intern/cycles/device/cpu/device_impl.cpp b/intern/cycles/device/cpu/device_impl.cpp index 4cf76c1f5fdf..881e5a7dfe65 100644 --- a/intern/cycles/device/cpu/device_impl.cpp +++ b/intern/cycles/device/cpu/device_impl.cpp @@ -266,6 +266,7 @@ void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit) if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE || bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE || bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE || + bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE || bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE) { BVHEmbree *const bvh_embree = static_cast(bvh); diff --git a/intern/cycles/device/multi/device.cpp b/intern/cycles/device/multi/device.cpp index 3cf81189186b..91407af6fdaf 100644 --- a/intern/cycles/device/multi/device.cpp +++ b/intern/cycles/device/multi/device.cpp @@ -141,6 +141,11 @@ class MultiDevice : public Device { return BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE; } + const BVHLayoutMask BVH_LAYOUT_HIPRT_EMBREE = (BVH_LAYOUT_HIPRT | BVH_LAYOUT_EMBREE); + if ((bvh_layout_mask_all & BVH_LAYOUT_HIPRT_EMBREE) == BVH_LAYOUT_HIPRT_EMBREE) { + return BVH_LAYOUT_MULTI_HIPRT_EMBREE; + } + return bvh_layout_mask; } @@ -213,7 +218,7 @@ class MultiDevice : public Device { params.bvh_layout = sub.device->info.type == DEVICE_METAL ? BVH_LAYOUT_METAL : BVH_LAYOUT_EMBREE; else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE) - params.bvh_layout = sub.device->info.type == DEVICE_HIPRT ? BVH_LAYOUT_HIPRT : + params.bvh_layout = sub.device->info.type == DEVICE_HIP ? BVH_LAYOUT_HIPRT : BVH_LAYOUT_EMBREE; else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE) params.bvh_layout = sub.device->info.type == DEVICE_ONEAPI ? BVH_LAYOUT_EMBREEGPU : diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 9eae0188f30b..2c8131e93dcc 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -76,7 +76,7 @@ static GHOST_TButton convertButton(int button) * \param recvChar: the character ignoring modifiers (except for shift) * \return Ghost key code */ -static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction) +static GHOST_TKey convertKey(int rawCode, unichar recvChar) { // printf("\nrecvchar %c 0x%x",recvChar,recvChar); switch (rawCode) { @@ -237,7 +237,10 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction) return GHOST_kKeyUpPage; case kVK_PageDown: return GHOST_kKeyDownPage; -#if 0 /* TODO: why are these commented? */ +#if 0 + /* These constants with "ANSI" in the name are labeled according to the key position on an + * ANSI-standard US keyboard. Therefore they may not match the physical key label on other + * keyboard layouts. */ case kVK_ANSI_Minus: return GHOST_kKeyMinus; case kVK_ANSI_Equal: return GHOST_kKeyEqual; case kVK_ANSI_Comma: return GHOST_kKeyComma; @@ -283,10 +286,10 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction) UCKeyTranslate((UCKeyboardLayout *)CFDataGetBytePtr(uchrHandle), rawCode, - keyAction, + kUCKeyActionDown, 0, LMGetKbdType(), - kUCKeyTranslateNoDeadKeysBit, + kUCKeyTranslateNoDeadKeysMask, &deadKeyState, 1, &actualStrLength, @@ -1829,18 +1832,13 @@ - (void)windowWillClose:(NSNotification *)notification case NSEventTypeKeyDown: case NSEventTypeKeyUp: + /* Returns an empty string for dead keys. */ charsIgnoringModifiers = [event charactersIgnoringModifiers]; if ([charsIgnoringModifiers length] > 0) { - keyCode = convertKey([event keyCode], - [charsIgnoringModifiers characterAtIndex:0], - [event type] == NSEventTypeKeyDown ? kUCKeyActionDown : - kUCKeyActionUp); + keyCode = convertKey([event keyCode], [charsIgnoringModifiers characterAtIndex:0]); } else { - keyCode = convertKey([event keyCode], - 0, - [event type] == NSEventTypeKeyDown ? kUCKeyActionDown : - kUCKeyActionUp); + keyCode = convertKey([event keyCode], 0); } characters = [event characters]; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index c3ff79bc6324..e56cb426e007 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -4284,7 +4284,9 @@ static void gwl_seat_capability_pointer_enable(GWL_Seat *seat) zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures(); if (pointer_gestures) { + const uint pointer_gestures_version = zwp_pointer_gestures_v1_get_version(pointer_gestures); #ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE + if (pointer_gestures_version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE_SINCE_VERSION) { /* Hold gesture. */ struct zwp_pointer_gesture_hold_v1 *gesture = zwp_pointer_gestures_v1_get_hold_gesture( pointer_gestures, seat->wl_pointer); @@ -5125,7 +5127,10 @@ static void gwl_registry_wp_pointer_gestures_add(GWL_Display *display, const GWL_RegisteryAdd_Params *params) { display->wp_pointer_gestures = static_cast( - wl_registry_bind(display->wl_registry, params->name, &zwp_pointer_gestures_v1_interface, 3)); + wl_registry_bind(display->wl_registry, + params->name, + &zwp_pointer_gestures_v1_interface, + std::min(params->version, 3u))); gwl_registry_entry_add(display, params, nullptr); } static void gwl_registry_wp_pointer_gestures_remove(GWL_Display *display, diff --git a/intern/ghost/intern/GHOST_SystemWin32.cc b/intern/ghost/intern/GHOST_SystemWin32.cc index 0fc70c6634ee..6e3dd3ba6fa7 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cc +++ b/intern/ghost/intern/GHOST_SystemWin32.cc @@ -458,24 +458,27 @@ GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(int32_t x, int32_t y) GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) const { - bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0; + /* `GetAsyncKeyState` returns the current interrupt-level state of the hardware, which is needed + * when passing key states to a newly-activated window - #40059. Alterative `GetKeyState` only + * returns the state as processed by the thread's message queue. */ + bool down = HIBYTE(::GetAsyncKeyState(VK_LSHIFT)) != 0; keys.set(GHOST_kModifierKeyLeftShift, down); - down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0; + down = HIBYTE(::GetAsyncKeyState(VK_RSHIFT)) != 0; keys.set(GHOST_kModifierKeyRightShift, down); - down = HIBYTE(::GetKeyState(VK_LMENU)) != 0; + down = HIBYTE(::GetAsyncKeyState(VK_LMENU)) != 0; keys.set(GHOST_kModifierKeyLeftAlt, down); - down = HIBYTE(::GetKeyState(VK_RMENU)) != 0; + down = HIBYTE(::GetAsyncKeyState(VK_RMENU)) != 0; keys.set(GHOST_kModifierKeyRightAlt, down); - down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0; + down = HIBYTE(::GetAsyncKeyState(VK_LCONTROL)) != 0; keys.set(GHOST_kModifierKeyLeftControl, down); - down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0; + down = HIBYTE(::GetAsyncKeyState(VK_RCONTROL)) != 0; keys.set(GHOST_kModifierKeyRightControl, down); - down = HIBYTE(::GetKeyState(VK_LWIN)) != 0; + down = HIBYTE(::GetAsyncKeyState(VK_LWIN)) != 0; keys.set(GHOST_kModifierKeyLeftOS, down); - down = HIBYTE(::GetKeyState(VK_RWIN)) != 0; + down = HIBYTE(::GetAsyncKeyState(VK_RWIN)) != 0; keys.set(GHOST_kModifierKeyRightOS, down); return GHOST_kSuccess; @@ -1201,16 +1204,11 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA bool is_repeat = false; bool is_repeated_modifier = false; if (key_down) { - if (system->m_keycode_last_repeat_key == vk) { + if (HIBYTE(::GetKeyState(vk)) != 0) { + /* This thread's message queue shows this key as already down. */ is_repeat = true; is_repeated_modifier = GHOST_KEY_MODIFIER_CHECK(key); } - system->m_keycode_last_repeat_key = vk; - } - else { - if (system->m_keycode_last_repeat_key == vk) { - system->m_keycode_last_repeat_key = 0; - } } /* We used to check `if (key != GHOST_kKeyUnknown)`, but since the message @@ -1884,8 +1882,14 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, else if (!new_parent && !old_parent) { /* Between main windows that don't overlap. */ RECT new_rect, old_rect, dest_rect; - ::GetWindowRect(hwnd, &new_rect); - ::GetWindowRect(old_hwnd, &old_rect); + + /* The rects without the outside shadows and slightly inset. */ + DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &new_rect, sizeof(RECT)); + ::InflateRect(&new_rect, -1, -1); + DwmGetWindowAttribute( + old_hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &old_rect, sizeof(RECT)); + ::InflateRect(&old_rect, -1, -1); + if (!IntersectRect(&dest_rect, &new_rect, &old_rect)) { ::SetFocus(hwnd); } @@ -1980,7 +1984,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, * so the window is activated immediately. */ system->m_wheelDeltaAccum = 0; - system->m_keycode_last_repeat_key = 0; event = processWindowEvent( LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window); /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL diff --git a/intern/ghost/intern/GHOST_SystemWin32.hh b/intern/ghost/intern/GHOST_SystemWin32.hh index 2f91ddf345b7..24e44ff16037 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.hh +++ b/intern/ghost/intern/GHOST_SystemWin32.hh @@ -454,8 +454,6 @@ class GHOST_SystemWin32 : public GHOST_System { */ bool setConsoleWindowState(GHOST_TConsoleWindowState action); - /** The virtual-key code (VKey) of the last press event. Used to detect repeat events. */ - unsigned short m_keycode_last_repeat_key; /** State variable set at initialization. */ bool m_hasPerformanceCounter; /** High frequency timer variable. */ diff --git a/release/datafiles/colormanagement/config.ocio b/release/datafiles/colormanagement/config.ocio index 91d722a311f2..5a7734e5a9ec 100644 --- a/release/datafiles/colormanagement/config.ocio +++ b/release/datafiles/colormanagement/config.ocio @@ -69,6 +69,7 @@ active_views: [Standard, Filmic, Filmic Log, Raw, False Color] colorspaces: - ! name: Linear + aliases: [Linear Rec.709] family: linear equalitygroup: bitdepth: 32f @@ -85,6 +86,7 @@ colorspaces: - ! name: Linear ACES + aliases: [ACES2065-1] family: linear equalitygroup: bitdepth: 32f @@ -98,6 +100,7 @@ colorspaces: - ! name: Linear ACEScg + aliases: [ACEScg] family: linear equalitygroup: bitdepth: 32f @@ -123,6 +126,7 @@ colorspaces: - ! name: XYZ + aliases: [Linear CIE-XYZ D65] family: linear equalitygroup: bitdepth: 32f diff --git a/scripts/modules/bpy_types.py b/scripts/modules/bpy_types.py index c319ede24a82..23550c2247ad 100644 --- a/scripts/modules/bpy_types.py +++ b/scripts/modules/bpy_types.py @@ -176,7 +176,8 @@ class Object(bpy_types.ID): @property def children(self): - """All the children of this object. + """ + All the children of this object. :type: tuple of `Object` @@ -187,7 +188,8 @@ def children(self): @property def children_recursive(self): - """A list of all children from this object. + """ + A list of all children from this object. :type: tuple of `Object` @@ -229,7 +231,8 @@ def users_collection(self): @property def users_scene(self): - """The scenes this object is in. + """ + The scenes this object is in. :type: tuple of `Scene` diff --git a/scripts/modules/rna_manual_reference.py b/scripts/modules/rna_manual_reference.py index 7218c8ec1cc2..ca15165e9fbd 100644 --- a/scripts/modules/rna_manual_reference.py +++ b/scripts/modules/rna_manual_reference.py @@ -66,6 +66,7 @@ ("bpy.types.spacespreadsheet.display_context_path_collapsed*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-display-context-path-collapsed"), ("bpy.types.toolsettings.annotation_stroke_placement_view2d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view2d"), ("bpy.types.toolsettings.annotation_stroke_placement_view3d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view3d"), + ("bpy.ops.object.simulation_nodes_cache_calculate_to_frame*", "physics/simulation_nodes.html#bpy-ops-object-simulation-nodes-cache-calculate-to-frame"), ("bpy.types.brushcurvessculptsettings.density_add_attempts*", "sculpt_paint/curves_sculpting/tools/density_curves.html#bpy-types-brushcurvessculptsettings-density-add-attempts"), ("bpy.types.brushgpencilsettings.use_random_press_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-strength"), ("bpy.types.fluiddomainsettings.use_collision_border_front*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-front"), @@ -89,6 +90,7 @@ ("bpy.types.fluiddomainsettings.use_collision_border_left*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-left"), ("bpy.types.lineartgpencilmodifier.use_intersection_match*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection-match"), ("bpy.types.rendersettings_simplify_gpencil_view_modifier*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-modifier"), + ("bpy.types.spaceoutliner.use_filter_object_grease_pencil*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-grease-pencil"), ("bpy.types.brushcurvessculptsettings.interpolate_length*", "sculpt_paint/curves_sculpting/tools/add_curves.html#bpy-types-brushcurvessculptsettings-interpolate-length"), ("bpy.types.brushgpencilsettings.eraser_thickness_factor*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-thickness-factor"), ("bpy.types.brushgpencilsettings.use_random_press_radius*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-radius"), @@ -280,6 +282,7 @@ ("bpy.types.materialgpencilstyle.use_stroke_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-stroke-holdout"), ("bpy.types.movietrackingplanetrack.use_auto_keying*", "movie_clip/tracking/clip/sidebar/track/plane_track.html#bpy-types-movietrackingplanetrack-use-auto-keying"), ("bpy.types.movietrackingsettings.use_tripod_solver*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-tripod-solver"), + ("bpy.types.nodesmodifier.simulation_bake_directory*", "modeling/modifiers/generate/geometry_nodes.html#bpy-types-nodesmodifier-simulation-bake-directory"), ("bpy.types.rendersettings.simplify_child_particles*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-child-particles"), ("bpy.types.rendersettings.use_high_quality_normals*", "render/eevee/render_settings/performance.html#bpy-types-rendersettings-use-high-quality-normals"), ("bpy.types.sculpt.automasking_start_normal_falloff*", "sculpt_paint/sculpting/controls.html#bpy-types-sculpt-automasking-start-normal-falloff"), @@ -405,6 +408,7 @@ ("bpy.types.spacesequenceeditor.proxy_render_size*", "editors/video_sequencer/preview/sidebar.html#bpy-types-spacesequenceeditor-proxy-render-size"), ("bpy.types.spacespreadsheetrowfilter.column_name*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-column-name"), ("bpy.types.toolsettings.gpencil_stroke_placement*", "grease_pencil/modes/draw/stroke_placement.html#bpy-types-toolsettings-gpencil-stroke-placement"), + ("bpy.types.toolsettings.snap_elements_individual*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-elements-individual"), ("bpy.types.toolsettings.use_keyframe_cycle_aware*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-cycle-aware"), ("bpy.types.toolsettings.use_keyframe_insert_auto*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-insert-auto"), ("bpy.types.view3doverlay.show_sculpt_curves_cage*", "sculpt_paint/curves_sculpting/introduction.html#bpy-types-view3doverlay-show-sculpt-curves-cage"), @@ -542,8 +546,10 @@ ("bpy.types.transformsequence.use_uniform_scale*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-use-uniform-scale"), ("bpy.types.view3doverlay.show_face_orientation*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-face-orientation"), ("bpy.types.view3doverlay.show_viewer_attribute*", "modeling/geometry_nodes/output/viewer.html#bpy-types-view3doverlay-show-viewer-attribute"), + ("bpy.types.viewlayereevee.use_pass_transparent*", "render/layers/passes.html#bpy-types-viewlayereevee-use-pass-transparent"), ("bpy.ops.gpencil.bake_grease_pencil_animation*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-bake-grease-pencil-animation"), ("bpy.ops.object.multires_higher_levels_delete*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-higher-levels-delete"), + ("bpy.ops.object.simulation_nodes_cache_delete*", "physics/simulation_nodes.html#bpy-ops-object-simulation-nodes-cache-delete"), ("bpy.ops.object.vertex_group_copy_to_selected*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy-to-selected"), ("bpy.ops.outliner.collection_duplicate_linked*", "editors/outliner/editing.html#bpy-ops-outliner-collection-duplicate-linked"), ("bpy.ops.view3d.edit_mesh_extrude_move_normal*", "modeling/meshes/editing/face/extrude_faces.html#bpy-ops-view3d-edit-mesh-extrude-move-normal"), @@ -612,6 +618,8 @@ ("bpy.types.spacespreadsheet.object_eval_state*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-object-eval-state"), ("bpy.types.spaceuveditor.display_stretch_type*", "editors/uv/overlays.html#bpy-types-spaceuveditor-display-stretch-type"), ("bpy.types.spaceuveditor.show_grid_over_image*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-grid-over-image"), + ("bpy.types.textcharacterformat.use_small_caps*", "modeling/texts/properties.html#bpy-types-textcharacterformat-use-small-caps"), + ("bpy.types.toolsettings.proportional_distance*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-proportional-distance"), ("bpy.types.toolsettings.transform_pivot_point*", "editors/3dview/controls/pivot_point/index.html#bpy-types-toolsettings-transform-pivot-point"), ("bpy.types.toolsettings.use_proportional_edit*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit"), ("bpy.types.toolsettings.uv_sticky_select_mode*", "editors/uv/selecting.html#bpy-types-toolsettings-uv-sticky-select-mode"), @@ -620,6 +628,7 @@ ("bpy.ops.geometry.color_attribute_render_set*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-render-set"), ("bpy.ops.mesh.customdata_crease_vertex_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-crease-vertex-clear"), ("bpy.ops.object.geometry_nodes_move_to_nodes*", "modeling/modifiers/generate/geometry_nodes.html#bpy-ops-object-geometry-nodes-move-to-nodes"), + ("bpy.ops.preferences.script_directory_remove*", "editors/preferences/file_paths.html#bpy-ops-preferences-script-directory-remove"), ("bpy.types.brushgpencilsettings.angle_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle-factor"), ("bpy.types.brushgpencilsettings.pen_strength*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-pen-strength"), ("bpy.types.clothcollisionsettings.collection*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings-collection"), @@ -679,6 +688,7 @@ ("bpy.types.spaceuveditor.show_modified_edges*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-modified-edges"), ("bpy.types.spaceview3d.transform_orientation*", "editors/3dview/controls/orientation.html#bpy-types-spaceview3d-transform-orientation"), ("bpy.types.spaceview3d.use_local_collections*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-local-collections"), + ("bpy.types.textcharacterformat.use_underline*", "modeling/texts/properties.html#bpy-types-textcharacterformat-use-underline"), ("bpy.types.toolsettings.use_snap_peel_object*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-peel-object"), ("bpy.types.transformsequence.translate_start*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-translate-start"), ("bpy.types.view3doverlay.fade_inactive_alpha*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-fade-inactive-alpha"), @@ -689,6 +699,7 @@ ("bpy.ops.geometry.color_attribute_duplicate*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-duplicate"), ("bpy.ops.object.constraint_add_with_targets*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraint-add-with-targets"), ("bpy.ops.object.material_slot_remove_unused*", "scene_layout/object/editing/cleanup.html#bpy-ops-object-material-slot-remove-unused"), + ("bpy.ops.object.simulation_nodes_cache_bake*", "physics/simulation_nodes.html#bpy-ops-object-simulation-nodes-cache-bake"), ("bpy.ops.outliner.collection_disable_render*", "editors/outliner/editing.html#bpy-ops-outliner-collection-disable-render"), ("bpy.ops.scene.freestyle_alpha_modifier_add*", "render/freestyle/view_layer/line_style/alpha.html#bpy-ops-scene-freestyle-alpha-modifier-add"), ("bpy.ops.scene.freestyle_color_modifier_add*", "render/freestyle/view_layer/line_style/color.html#bpy-ops-scene-freestyle-color-modifier-add"), @@ -736,6 +747,8 @@ ("bpy.types.geometrynodesamplenearestsurface*", "modeling/geometry_nodes/mesh/sample/sample_nearest_surface.html#bpy-types-geometrynodesamplenearestsurface"), ("bpy.types.gpencillayer.use_viewlayer_masks*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-viewlayer-masks"), ("bpy.types.greasepencil.onion_keyframe_type*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-onion-keyframe-type"), + ("bpy.types.imagetexture.use_calculate_alpha*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-calculate-alpha"), + ("bpy.types.imagetexture.use_filter_size_min*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-filter-size-min"), ("bpy.types.lineartgpencilmodifier.use_cache*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-cache"), ("bpy.types.lineartgpencilmodifier.use_loose*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-loose"), ("bpy.types.materialgpencilstyle.show_stroke*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-show-stroke"), @@ -772,7 +785,8 @@ ("bpy.ops.outliner.collection_enable_render*", "editors/outliner/editing.html#bpy-ops-outliner-collection-enable-render"), ("bpy.ops.outliner.collection_exclude_clear*", "editors/outliner/editing.html#bpy-ops-outliner-collection-exclude-clear"), ("bpy.ops.outliner.collection_holdout_clear*", "render/layers/introduction.html#bpy-ops-outliner-collection-holdout-clear"), - ("bpy.ops.sculpt.face_set_change_visibility*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-set-change-visibility"), + ("bpy.ops.sculpt.face_set_change_visibility*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-face-set-change-visibility"), + ("bpy.ops.sculpt.face_set_invert_visibility*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-set-invert-visibility"), ("bpy.ops.sculpt.face_sets_randomize_colors*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-sets-randomize-colors"), ("bpy.types.animvizmotionpaths.frame_before*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-before"), ("bpy.types.brush.disconnected_distance_max*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-disconnected-distance-max"), @@ -847,12 +861,15 @@ ("bpy.types.spaceuveditor.show_pixel_coords*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-show-pixel-coords"), ("bpy.types.spaceview3d.show_reconstruction*", "editors/3dview/display/overlays.html#bpy-types-spaceview3d-show-reconstruction"), ("bpy.types.toolsettings.gpencil_selectmode*", "grease_pencil/selecting.html#bpy-types-toolsettings-gpencil-selectmode"), + ("bpy.types.toolsettings.snap_elements_base*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-elements-base"), ("bpy.types.toolsettings.use_auto_normalize*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-toolsettings-use-auto-normalize"), ("bpy.types.toolsettings.use_mesh_automerge*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-mesh-automerge"), ("bpy.types.toolsettings.use_snap_sequencer*", "video_editing/edit/montage/editing.html#bpy-types-toolsettings-use-snap-sequencer"), ("bpy.types.toolsettings.use_snap_translate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-translate"), ("bpy.types.toolsettings.use_uv_select_sync*", "editors/uv/selecting.html#bpy-types-toolsettings-use-uv-select-sync"), ("bpy.types.transformsequence.interpolation*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-interpolation"), + ("bpy.types.view3doverlay.retopology_offset*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-retopology-offset"), + ("bpy.types.view3doverlay.show_light_colors*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-light-colors"), ("bpy.types.view3doverlay.wireframe_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-wireframe-opacity"), ("bpy.ops.asset.open_containing_blend_file*", "editors/asset_browser.html#bpy-ops-asset-open-containing-blend-file"), ("bpy.ops.geometry.color_attribute_convert*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-convert"), @@ -862,6 +879,7 @@ ("bpy.ops.object.anim_transforms_to_deltas*", "scene_layout/object/editing/apply.html#bpy-ops-object-anim-transforms-to-deltas"), ("bpy.ops.object.modifier_copy_to_selected*", "modeling/modifiers/introduction.html#bpy-ops-object-modifier-copy-to-selected"), ("bpy.ops.preferences.app_template_install*", "advanced/app_templates.html#bpy-ops-preferences-app-template-install"), + ("bpy.ops.preferences.script_directory_add*", "editors/preferences/file_paths.html#bpy-ops-preferences-script-directory-add"), ("bpy.types.animvizmotionpaths.frame_after*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-after"), ("bpy.types.animvizmotionpaths.frame_start*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-start"), ("bpy.types.bakesettings.use_pass_indirect*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-indirect"), @@ -911,6 +929,7 @@ ("bpy.types.greasepencil.ghost_after_range*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-ghost-after-range"), ("bpy.types.greasepencil.use_ghosts_always*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-use-ghosts-always"), ("bpy.types.imageformatsettings.color_mode*", "render/output/properties/output.html#bpy-types-imageformatsettings-color-mode"), + ("bpy.types.imagetexture.use_interpolation*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-interpolation"), ("bpy.types.linestyle*modifier_alongstroke*", "render/freestyle/view_layer/line_style/modifiers/color/along_stroke.html#bpy-types-linestyle-modifier-alongstroke"), ("bpy.types.linestyle*modifier_creaseangle*", "render/freestyle/view_layer/line_style/modifiers/color/crease_angle.html#bpy-types-linestyle-modifier-creaseangle"), ("bpy.types.linestylecolormodifier_tangent*", "render/freestyle/view_layer/line_style/modifiers/color/tangent.html#bpy-types-linestylecolormodifier-tangent"), @@ -944,7 +963,9 @@ ("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"), ("bpy.types.spaceuveditor.pixel_round_mode*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-pixel-round-mode"), ("bpy.types.spaceview3d.show_object_select*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-select"), + ("bpy.types.textcharacterformat.use_italic*", "modeling/texts/properties.html#bpy-types-textcharacterformat-use-italic"), ("bpy.types.toolsettings.use_lock_relative*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-toolsettings-use-lock-relative"), + ("bpy.types.toolsettings.vertex_group_user*", "editors/3dview/display/overlays.html#bpy-types-toolsettings-vertex-group-user"), ("bpy.types.vertexpaint.use_group_restrict*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-vertexpaint-use-group-restrict"), ("bpy.types.volumedisplay.wireframe_detail*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-detail"), ("bpy.types.windowmanager.asset_path_dummy*", "editors/asset_browser.html#bpy-types-windowmanager-asset-path-dummy"), @@ -1014,6 +1035,7 @@ ("bpy.types.geometrynodematerialselection*", "modeling/geometry_nodes/material/material_selection.html#bpy-types-geometrynodematerialselection"), ("bpy.types.gpencillayer.viewlayer_render*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-viewlayer-render"), ("bpy.types.imagepaint.use_normal_falloff*", "sculpt_paint/brush/falloff.html#bpy-types-imagepaint-use-normal-falloff"), + ("bpy.types.imagetexture.use_mipmap_gauss*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-mipmap-gauss"), ("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"), ("bpy.types.layercollection.indirect_only*", "editors/outliner/interface.html#bpy-types-layercollection-indirect-only"), ("bpy.types.material.use_backface_culling*", "render/eevee/materials/settings.html#bpy-types-material-use-backface-culling"), @@ -1038,6 +1060,7 @@ ("bpy.types.spacesequenceeditor.view_type*", "editors/video_sequencer/introduction.html#bpy-types-spacesequenceeditor-view-type"), ("bpy.types.spacetexteditor.margin_column*", "editors/text_editor.html#bpy-types-spacetexteditor-margin-column"), ("bpy.types.spacetexteditor.use_find_wrap*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-wrap"), + ("bpy.types.spacetexteditor.use_live_edit*", "editors/text_editor.html#bpy-types-spacetexteditor-use-live-edit"), ("bpy.types.spaceuveditor.tile_grid_shape*", "editors/uv/overlays.html#bpy-types-spaceuveditor-tile-grid-shape"), ("bpy.types.spaceuveditor.use_live_unwrap*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-use-live-unwrap"), ("bpy.types.spaceview3d.use_render_border*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-render-border"), @@ -1045,14 +1068,14 @@ ("bpy.types.toolsettings.lock_object_mode*", "interface/window_system/topbar.html#bpy-types-toolsettings-lock-object-mode"), ("bpy.types.toolsettings.mesh_select_mode*", "modeling/meshes/selecting/introduction.html#bpy-types-toolsettings-mesh-select-mode"), ("bpy.types.toolsettings.use_snap_nonedit*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-nonedit"), - ("bpy.types.toolsettings.use_snap_project*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-project"), ("bpy.types.transformorientationslot.type*", "editors/3dview/controls/orientation.html#bpy-types-transformorientationslot-type"), ("bpy.types.transformsequence.scale_start*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-scale-start"), ("bpy.types.unitsettings.temperature_unit*", "scene_layout/scene/properties.html#bpy-types-unitsettings-temperature-unit"), ("bpy.types.vertexweightproximitymodifier*", "modeling/modifiers/modify/weight_proximity.html#bpy-types-vertexweightproximitymodifier"), + ("bpy.types.view3doverlay.show_retopology*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-retopology"), ("bpy.types.view3doverlay.show_wireframes*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-wireframes"), ("bpy.types.view3dshading.background_type*", "editors/3dview/display/shading.html#bpy-types-view3dshading-background-type"), - ("bpy.types.windowmanager.poselib_flipped*", "animation/armatures/posing/editing/pose_library.html#bpy-types-windowmanager-poselib-flipped"), + ("bpy.types.viewlayereevee.use_pass_bloom*", "render/layers/passes.html#bpy-types-viewlayereevee-use-pass-bloom"), ("bpy.types.workspace.use_filter_by_owner*", "interface/window_system/workspaces.html#bpy-types-workspace-use-filter-by-owner"), ("bpy.ops.brush.stencil_fit_image_aspect*", "sculpt_paint/brush/texture.html#bpy-ops-brush-stencil-fit-image-aspect"), ("bpy.ops.gpencil.image_to_grease_pencil*", "editors/image/editing.html#bpy-ops-gpencil-image-to-grease-pencil"), @@ -1098,6 +1121,7 @@ ("bpy.types.geometrynoderealizeinstances*", "modeling/geometry_nodes/instances/realize_instances.html#bpy-types-geometrynoderealizeinstances"), ("bpy.types.geometrynodeseparategeometry*", "modeling/geometry_nodes/geometry/operations/separate_geometry.html#bpy-types-geometrynodeseparategeometry"), ("bpy.types.geometrynodesetmaterialindex*", "modeling/geometry_nodes/material/set_material_index.html#bpy-types-geometrynodesetmaterialindex"), + ("bpy.types.geometrynodesimulationoutput*", "modeling/geometry_nodes/simulation/simulation_zone.html#bpy-types-geometrynodesimulationoutput"), ("bpy.types.greasepencil.edit_line_color*", "grease_pencil/properties/display.html#bpy-types-greasepencil-edit-line-color"), ("bpy.types.material.preview_render_type*", "render/materials/preview.html#bpy-types-material-preview-render-type"), ("bpy.types.materialgpencilstyle.pattern*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-pattern"), @@ -1128,14 +1152,16 @@ ("bpy.types.spacetexteditor.replace_text*", "editors/text_editor.html#bpy-types-spacetexteditor-replace-text"), ("bpy.types.spacetexteditor.use_find_all*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-all"), ("bpy.types.spaceview3d.use_local_camera*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-local-camera"), + ("bpy.types.textcharacterformat.use_bold*", "modeling/texts/properties.html#bpy-types-textcharacterformat-use-bold"), + ("bpy.types.textcurve.underline_position*", "modeling/texts/properties.html#bpy-types-textcurve-underline-position"), ("bpy.types.toolsettings.snap_uv_element*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-snap-uv-element"), ("bpy.types.toolsettings.use_snap_rotate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-rotate"), ("bpy.types.toolsettings.uv_relax_method*", "modeling/meshes/uv/tools/relax.html#bpy-types-toolsettings-uv-relax-method"), ("bpy.types.unitsettings.system_rotation*", "scene_layout/scene/properties.html#bpy-types-unitsettings-system-rotation"), ("bpy.types.view3doverlay.display_handle*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-display-handle"), ("bpy.types.volumedisplay.wireframe_type*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-type"), - ("bpy.ops.anim.channels_editable_toggle*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-editable-toggle"), - ("bpy.ops.anim.channels_setting_disable*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-setting-disable"), + ("bpy.ops.anim.channels_editable_toggle*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-editable-toggle"), + ("bpy.ops.anim.channels_setting_disable*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-setting-disable"), ("bpy.ops.brush.stencil_reset_transform*", "sculpt_paint/brush/texture.html#bpy-ops-brush-stencil-reset-transform"), ("bpy.ops.curve.normals_make_consistent*", "modeling/curves/editing/control_points.html#bpy-ops-curve-normals-make-consistent"), ("bpy.ops.curves.snap_curves_to_surface*", "sculpt_paint/curves_sculpting/introduction.html#bpy-ops-curves-snap-curves-to-surface"), @@ -1184,7 +1210,7 @@ ("bpy.types.compositornodeseparatecolor*", "compositing/types/converter/separate_color.html#bpy-types-compositornodeseparatecolor"), ("bpy.types.compositornodesetalpha.mode*", "compositing/types/converter/set_alpha.html#bpy-types-compositornodesetalpha-mode"), ("bpy.types.curves.use_sculpt_collision*", "sculpt_paint/curves_sculpting/introduction.html#bpy-types-curves-use-sculpt-collision"), - ("bpy.types.dopesheet.use_filter_invert*", "editors/graph_editor/channels.html#bpy-types-dopesheet-use-filter-invert"), + ("bpy.types.dopesheet.use_filter_invert*", "editors/graph_editor/channels/introduction.html#bpy-types-dopesheet-use-filter-invert"), ("bpy.types.editbone.use_local_location*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-use-local-location"), ("bpy.types.ffmpegsettings.audio_volume*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio-volume"), ("bpy.types.ffmpegsettings.max_b_frames*", "render/output/properties/output.html#bpy-types-ffmpegsettings-max-b-frames"), @@ -1209,6 +1235,7 @@ ("bpy.types.geometrynoderotateinstances*", "modeling/geometry_nodes/instances/rotate_instances.html#bpy-types-geometrynoderotateinstances"), ("bpy.types.geometrynodesampleuvsurface*", "modeling/geometry_nodes/mesh/sample/sample_uv_surface.html#bpy-types-geometrynodesampleuvsurface"), ("bpy.types.geometrynodesetsplinecyclic*", "modeling/geometry_nodes/curve/write/set_spline_cyclic.html#bpy-types-geometrynodesetsplinecyclic"), + ("bpy.types.geometrynodesimulationinput*", "modeling/geometry_nodes/simulation/simulation_zone.html#bpy-types-geometrynodesimulationinput"), ("bpy.types.geometrynodesplineparameter*", "modeling/geometry_nodes/curve/read/spline_parameter.html#bpy-types-geometrynodesplineparameter"), ("bpy.types.gpencillayer.use_mask_layer*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-mask-layer"), ("bpy.types.greasepencil.use_curve_edit*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-use-curve-edit"), @@ -1219,6 +1246,7 @@ ("bpy.types.motionpath.use_custom_color*", "animation/motion_paths.html#bpy-types-motionpath-use-custom-color"), ("bpy.types.movietrackingcamera.brown_k*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-brown-k"), ("bpy.types.movietrackingcamera.brown_p*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-brown-p"), + ("bpy.types.object.use_simulation_cache*", "physics/simulation_nodes.html#bpy-types-object-use-simulation-cache"), ("bpy.types.object.visible_transmission*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-transmission"), ("bpy.types.particlesettingstextureslot*", "physics/particles/texture_influence.html#bpy-types-particlesettingstextureslot"), ("bpy.types.pointlight.shadow_soft_size*", "render/lights/light_object.html#bpy-types-pointlight-shadow-soft-size"), @@ -1249,12 +1277,13 @@ ("bpy.types.toolsettings.use_snap_scale*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-scale"), ("bpy.types.toolsettings.uv_select_mode*", "editors/uv/selecting.html#bpy-types-toolsettings-uv-select-mode"), ("bpy.types.viewlayer.material_override*", "render/layers/introduction.html#bpy-types-viewlayer-material-override"), - ("bpy.ops.anim.channels_fcurves_enable*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-fcurves-enable"), - ("bpy.ops.anim.channels_setting_enable*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-setting-enable"), - ("bpy.ops.anim.channels_setting_toggle*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-setting-toggle"), + ("bpy.ops.anim.channels_fcurves_enable*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-fcurves-enable"), + ("bpy.ops.anim.channels_setting_enable*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-setting-enable"), + ("bpy.ops.anim.channels_setting_toggle*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-setting-toggle"), ("bpy.ops.clip.set_viewport_background*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-viewport-background"), ("bpy.ops.geometry.color_attribute_add*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-add"), ("bpy.ops.gpencil.interpolate_sequence*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-interpolate-sequence"), + ("bpy.ops.graph.driver_variables_paste*", "animation/drivers/drivers_panel.html#bpy-ops-graph-driver-variables-paste"), ("bpy.ops.mask.normals_make_consistent*", "movie_clip/masking/editing.html#bpy-ops-mask-normals-make-consistent"), ("bpy.ops.mesh.normals_make_consistent*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-normals-make-consistent"), ("bpy.ops.mesh.offset_edge_loops_slide*", "modeling/meshes/editing/edge/offset_edge_slide.html#bpy-ops-mesh-offset-edge-loops-slide"), @@ -1300,6 +1329,7 @@ ("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierfunctiongenerator"), ("bpy.types.geometrynodecollectioninfo*", "modeling/geometry_nodes/input/scene/collection_info.html#bpy-types-geometrynodecollectioninfo"), ("bpy.types.geometrynodedeletegeometry*", "modeling/geometry_nodes/geometry/operations/delete_geometry.html#bpy-types-geometrynodedeletegeometry"), + ("bpy.types.geometrynodeindexofnearest*", "modeling/geometry_nodes/geometry/sample/index_of_nearest.html#bpy-types-geometrynodeindexofnearest"), ("bpy.types.geometrynodeinputcurvetilt*", "modeling/geometry_nodes/curve/read/curve_tilt.html#bpy-types-geometrynodeinputcurvetilt"), ("bpy.types.geometrynodeinputscenetime*", "modeling/geometry_nodes/input/scene/scene_time.html#bpy-types-geometrynodeinputscenetime"), ("bpy.types.geometrynodepointstovolume*", "modeling/geometry_nodes/point/points_to_volume.html#bpy-types-geometrynodepointstovolume"), @@ -1314,6 +1344,7 @@ ("bpy.types.gpencillayer.channel_color*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-channel-color"), ("bpy.types.gpencillayer.use_solo_mode*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-solo-mode"), ("bpy.types.greasepencil.use_multiedit*", "grease_pencil/multiframe.html#bpy-types-greasepencil-use-multiedit"), + ("bpy.types.imagetexture.use_flip_axis*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-flip-axis"), ("bpy.types.keyframe.handle_right_type*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-right-type"), ("bpy.types.materialgpencilstyle.color*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-color"), ("bpy.types.movietrackingcamera.nuke_k*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-nuke-k"), @@ -1339,12 +1370,13 @@ ("bpy.types.spaceoutliner.filter_state*", "editors/outliner/interface.html#bpy-types-spaceoutliner-filter-state"), ("bpy.types.spaceuveditor.show_stretch*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-stretch"), ("bpy.types.spotlight.shadow_soft_size*", "render/lights/light_object.html#bpy-types-spotlight-shadow-soft-size"), + ("bpy.types.textcurve.small_caps_scale*", "modeling/texts/properties.html#bpy-types-textcurve-small-caps-scale"), ("bpy.types.toolsettings.keyframe_type*", "editors/timeline.html#bpy-types-toolsettings-keyframe-type"), - ("bpy.types.toolsettings.snap_elements*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-elements"), ("bpy.types.toolsettings.use_snap_edit*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-edit"), ("bpy.types.toolsettings.use_snap_node*", "interface/controls/nodes/arranging.html#bpy-types-toolsettings-use-snap-node"), ("bpy.types.toolsettings.use_snap_self*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-self"), ("bpy.types.viewlayer.active_aov_index*", "render/layers/passes.html#bpy-types-viewlayer-active-aov-index"), + ("bpy.ops.anim.channels_view_selected*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-view-selected"), ("bpy.ops.clip.tracking_object_remove*", "movie_clip/tracking/clip/sidebar/track/objects.html#bpy-ops-clip-tracking-object-remove"), ("bpy.ops.constraint.copy_to_selected*", "animation/constraints/interface/header.html#bpy-ops-constraint-copy-to-selected"), ("bpy.ops.curves.set_selection_domain*", "modeling/curves/primitives.html#bpy-ops-curves-set-selection-domain"), @@ -1355,6 +1387,7 @@ ("bpy.ops.gpencil.stroke_cyclical_set*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-cyclical-set"), ("bpy.ops.gpencil.vertex_color_invert*", "grease_pencil/modes/vertex_paint/editing.html#bpy-ops-gpencil-vertex-color-invert"), ("bpy.ops.gpencil.vertex_color_levels*", "grease_pencil/modes/vertex_paint/editing.html#bpy-ops-gpencil-vertex-color-levels"), + ("bpy.ops.graph.driver_variables_copy*", "animation/drivers/drivers_panel.html#bpy-ops-graph-driver-variables-copy"), ("bpy.ops.mask.slide_spline_curvature*", "movie_clip/masking/editing.html#bpy-ops-mask-slide-spline-curvature"), ("bpy.ops.mesh.flip_quad_tessellation*", "modeling/meshes/editing/face/face_data.html#bpy-ops-mesh-flip-quad-tessellation"), ("bpy.ops.mesh.primitive_cylinder_add*", "modeling/meshes/primitives.html#bpy-ops-mesh-primitive-cylinder-add"), @@ -1374,6 +1407,7 @@ ("bpy.ops.poselib.convert_old_poselib*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-convert-old-poselib"), ("bpy.ops.render.shutter_curve_preset*", "render/cycles/render_settings/motion_blur.html#bpy-ops-render-shutter-curve-preset"), ("bpy.ops.scene.view_layer_remove_aov*", "render/layers/passes.html#bpy-ops-scene-view-layer-remove-aov"), + ("bpy.ops.sculpt.project_line_gesture*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-project-line-gesture"), ("bpy.ops.sculpt_curves.select_random*", "sculpt_paint/curves_sculpting/introduction.html#bpy-ops-sculpt-curves-select-random"), ("bpy.ops.sequencer.view_ghost_border*", "editors/video_sequencer/preview/sidebar.html#bpy-ops-sequencer-view-ghost-border"), ("bpy.ops.ui.override_idtemplate_make*", "files/linked_libraries/library_overrides.html#bpy-ops-ui-override-idtemplate-make"), @@ -1416,9 +1450,10 @@ ("bpy.types.freestylelineset.qi_start*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-qi-start"), ("bpy.types.freestylelinestyle.rounds*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-rounds"), ("bpy.types.functionnodereplacestring*", "modeling/geometry_nodes/utilities/text/replace_string.html#bpy-types-functionnodereplacestring"), - ("bpy.types.functionnodeseparatecolor*", "modeling/geometry_nodes/utilities/color/separate_color.html#bpy-types-functionnodeseparatecolor"), + ("bpy.types.functionnodeseparatecolor*", "editors/texture_node/types/color/separate_color.html#bpy-types-functionnodeseparatecolor"), ("bpy.types.functionnodevaluetostring*", "modeling/geometry_nodes/utilities/text/value_to_string.html#bpy-types-functionnodevaluetostring"), ("bpy.types.geometrynodeblurattribute*", "modeling/geometry_nodes/attribute/blur_attribute.html#bpy-types-geometrynodeblurattribute"), + ("bpy.types.geometrynodecornersofedge*", "modeling/geometry_nodes/mesh/topology/corners_of_edge.html#bpy-types-geometrynodecornersofedge"), ("bpy.types.geometrynodecornersofface*", "modeling/geometry_nodes/mesh/topology/corners_of_face.html#bpy-types-geometrynodecornersofface"), ("bpy.types.geometrynodecurvetopoints*", "modeling/geometry_nodes/curve/operations/curve_to_points.html#bpy-types-geometrynodecurvetopoints"), ("bpy.types.geometrynodeedgesofcorner*", "modeling/geometry_nodes/mesh/topology/edges_of_corner.html#bpy-types-geometrynodeedgesofcorner"), @@ -1436,6 +1471,7 @@ ("bpy.types.greasepencil.before_color*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-before-color"), ("bpy.types.greasepencil.onion_factor*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-onion-factor"), ("bpy.types.greasepencil.pixel_factor*", "grease_pencil/properties/strokes.html#bpy-types-greasepencil-pixel-factor"), + ("bpy.types.imagetexture.invert_alpha*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-invert-alpha"), ("bpy.types.keyframe.handle_left_type*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-left-type"), ("bpy.types.light.use_custom_distance*", "render/eevee/lighting.html#bpy-types-light-use-custom-distance"), ("bpy.types.material.refraction_depth*", "render/eevee/materials/settings.html#bpy-types-material-refraction-depth"), @@ -1457,7 +1493,7 @@ ("bpy.types.sculpt.use_smooth_shading*", "sculpt_paint/sculpting/tool_settings/dyntopo.html#bpy-types-sculpt-use-smooth-shading"), ("bpy.types.sequence.frame_offset_end*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-sequence-frame-offset-end"), ("bpy.types.sequenceeditor.show_cache*", "editors/video_sequencer/sequencer/navigating.html#bpy-types-sequenceeditor-show-cache"), - ("bpy.types.shadernodebsdfanisotropic*", "render/shader_nodes/shader/anisotropic.html#bpy-types-shadernodebsdfanisotropic"), + ("bpy.types.shadernodebsdfanisotropic*", "render/shader_nodes/shader/glossy.html#bpy-types-shadernodebsdfanisotropic"), ("bpy.types.shadernodebsdftranslucent*", "render/shader_nodes/shader/translucent.html#bpy-types-shadernodebsdftranslucent"), ("bpy.types.shadernodebsdftransparent*", "render/shader_nodes/shader/transparent.html#bpy-types-shadernodebsdftransparent"), ("bpy.types.shadernodetexpointdensity*", "render/shader_nodes/textures/point_density.html#bpy-types-shadernodetexpointdensity"), @@ -1476,9 +1512,11 @@ ("bpy.types.spacetexteditor.tab_width*", "editors/text_editor.html#bpy-types-spacetexteditor-tab-width"), ("bpy.types.spaceuveditor.lock_bounds*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-lock-bounds"), ("bpy.types.spline.tilt_interpolation*", "modeling/curves/properties/active_spline.html#bpy-types-spline-tilt-interpolation"), + ("bpy.types.textcurve.space_character*", "modeling/texts/properties.html#bpy-types-textcurve-space-character"), ("bpy.types.transformorientation.name*", "editors/3dview/controls/orientation.html#bpy-types-transformorientation-name"), ("bpy.types.unitsettings.scale_length*", "scene_layout/scene/properties.html#bpy-types-unitsettings-scale-length"), ("bpy.types.unitsettings.use_separate*", "scene_layout/scene/properties.html#bpy-types-unitsettings-use-separate"), + ("bpy.types.view3doverlay.show_weight*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-weight"), ("bpy.types.viewlayer.use_motion_blur*", "render/layers/introduction.html#bpy-types-viewlayer-use-motion-blur"), ("bpy.types.volumedisplay.slice_depth*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-depth"), ("bpy.types.worldmistsettings.falloff*", "render/cycles/world_settings.html#bpy-types-worldmistsettings-falloff"), @@ -1509,6 +1547,7 @@ ("bpy.ops.sculpt.set_persistent_base*", "sculpt_paint/sculpting/tools/layer.html#bpy-ops-sculpt-set-persistent-base"), ("bpy.ops.sequencer.crossfade_sounds*", "video_editing/edit/montage/strips/transitions/sound_crossfade.html#bpy-ops-sequencer-crossfade-sounds"), ("bpy.ops.sequencer.export_subtitles*", "editors/video_sequencer/preview/header.html#bpy-ops-sequencer-export-subtitles"), + ("bpy.ops.text.jump_to_file_at_point*", "editors/text_editor.html#bpy-ops-text-jump-to-file-at-point"), ("bpy.ops.transform.edge_bevelweight*", "modeling/meshes/editing/edge/edge_data.html#bpy-ops-transform-edge-bevelweight"), ("bpy.ops.view3d.clear_render_border*", "editors/3dview/navigate/regions.html#bpy-ops-view3d-clear-render-border"), ("bpy.ops.wm.previews_batch_generate*", "files/blend/previews.html#bpy-ops-wm-previews-batch-generate"), @@ -1545,7 +1584,7 @@ ("bpy.types.freestylelineset.exclude*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-exclude"), ("bpy.types.freestylelinestyle.alpha*", "render/freestyle/view_layer/line_style/alpha.html#bpy-types-freestylelinestyle-alpha"), ("bpy.types.freestylelinestyle.color*", "render/freestyle/view_layer/line_style/color.html#bpy-types-freestylelinestyle-color"), - ("bpy.types.functionnodecombinecolor*", "modeling/geometry_nodes/utilities/color/combine_color.html#bpy-types-functionnodecombinecolor"), + ("bpy.types.functionnodecombinecolor*", "editors/texture_node/types/color/combine_color.html#bpy-types-functionnodecombinecolor"), ("bpy.types.functionnodestringlength*", "modeling/geometry_nodes/utilities/text/string_length.html#bpy-types-functionnodestringlength"), ("bpy.types.geometrynodecurveofpoint*", "modeling/geometry_nodes/curve/topology/curve_of_point.html#bpy-types-geometrynodecurveofpoint"), ("bpy.types.geometrynodefaceofcorner*", "modeling/geometry_nodes/mesh/topology/face_of_corner.html#bpy-types-geometrynodefaceofcorner"), @@ -1557,6 +1596,7 @@ ("bpy.types.geometrynodemeshtopoints*", "modeling/geometry_nodes/mesh/operations/mesh_to_points.html#bpy-types-geometrynodemeshtopoints"), ("bpy.types.geometrynodemeshtovolume*", "modeling/geometry_nodes/mesh/operations/mesh_to_volume.html#bpy-types-geometrynodemeshtovolume"), ("bpy.types.geometrynodemeshuvsphere*", "modeling/geometry_nodes/mesh/primitives/uv_sphere.html#bpy-types-geometrynodemeshuvsphere"), + ("bpy.types.geometrynoderepeatoutput*", "modeling/geometry_nodes/utilities/repeat_zone.html#bpy-types-geometrynoderepeatoutput"), ("bpy.types.geometrynodereversecurve*", "modeling/geometry_nodes/curve/operations/reverse_curve.html#bpy-types-geometrynodereversecurve"), ("bpy.types.geometrynodesetcurvetilt*", "modeling/geometry_nodes/curve/write/set_curve_tilt.html#bpy-types-geometrynodesetcurvetilt"), ("bpy.types.geometrynodesplinelength*", "modeling/geometry_nodes/curve/read/spline_length.html#bpy-types-geometrynodesplinelength"), @@ -1568,6 +1608,8 @@ ("bpy.types.image.use_half_precision*", "editors/image/image_settings.html#bpy-types-image-use-half-precision"), ("bpy.types.image.use_view_as_render*", "editors/image/image_settings.html#bpy-types-image-use-view-as-render"), ("bpy.types.imagepaint.interpolation*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-types-imagepaint-interpolation"), + ("bpy.types.imagetexture.filter_size*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-filter-size"), + ("bpy.types.imagetexture.filter_type*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-filter-type"), ("bpy.types.linestyle*modifier_noise*", "render/freestyle/view_layer/line_style/modifiers/color/noise.html#bpy-types-linestyle-modifier-noise"), ("bpy.types.maintainvolumeconstraint*", "animation/constraints/transform/maintain_volume.html#bpy-types-maintainvolumeconstraint"), ("bpy.types.material.alpha_threshold*", "render/eevee/materials/settings.html#bpy-types-material-alpha-threshold"), @@ -1638,6 +1680,7 @@ ("bpy.ops.preferences.theme_install*", "editors/preferences/themes.html#bpy-ops-preferences-theme-install"), ("bpy.ops.render.play_rendered_anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"), ("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-set-pivot-position"), + ("bpy.ops.sculpt.trim_lasso_gesture*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-trim-lasso-gesture"), ("bpy.ops.sculpt_curves.select_grow*", "sculpt_paint/curves_sculpting/introduction.html#bpy-ops-sculpt-curves-select-grow"), ("bpy.ops.sequencer.image_strip_add*", "video_editing/edit/montage/strips/image.html#bpy-ops-sequencer-image-strip-add"), ("bpy.ops.sequencer.images_separate*", "video_editing/edit/montage/editing.html#bpy-ops-sequencer-images-separate"), @@ -1697,6 +1740,7 @@ ("bpy.types.geometrynodeinputradius*", "modeling/geometry_nodes/geometry/read/radius.html#bpy-types-geometrynodeinputradius"), ("bpy.types.geometrynodemeshboolean*", "modeling/geometry_nodes/mesh/operations/mesh_boolean.html#bpy-types-geometrynodemeshboolean"), ("bpy.types.geometrynodemeshtocurve*", "modeling/geometry_nodes/mesh/operations/mesh_to_curve.html#bpy-types-geometrynodemeshtocurve"), + ("bpy.types.geometrynoderepeatinput*", "modeling/geometry_nodes/utilities/repeat_zone.html#bpy-types-geometrynoderepeatinput"), ("bpy.types.geometrynodesamplecurve*", "modeling/geometry_nodes/curve/sample/sample_curve.html#bpy-types-geometrynodesamplecurve"), ("bpy.types.geometrynodesampleindex*", "modeling/geometry_nodes/geometry/sample/sample_index.html#bpy-types-geometrynodesampleindex"), ("bpy.types.geometrynodesetmaterial*", "modeling/geometry_nodes/material/set_material.html#bpy-types-geometrynodesetmaterial"), @@ -1710,6 +1754,7 @@ ("bpy.types.greasepencil.onion_mode*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-onion-mode"), ("bpy.types.greasepencilgrid.offset*", "grease_pencil/properties/display.html#bpy-types-greasepencilgrid-offset"), ("bpy.types.imagepaint.normal_angle*", "sculpt_paint/brush/falloff.html#bpy-types-imagepaint-normal-angle"), + ("bpy.types.imagetexture.use_mipmap*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-mipmap"), ("bpy.types.laplaciandeformmodifier*", "modeling/modifiers/deform/laplacian_deform.html#bpy-types-laplaciandeformmodifier"), ("bpy.types.laplaciansmoothmodifier*", "modeling/modifiers/deform/laplacian_smooth.html#bpy-types-laplaciansmoothmodifier"), ("bpy.types.layercollection.exclude*", "editors/outliner/interface.html#bpy-types-layercollection-exclude"), @@ -1738,6 +1783,7 @@ ("bpy.types.spaceview3d.lock_cursor*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-lock-cursor"), ("bpy.types.spaceview3d.lock_object*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-lock-object"), ("bpy.types.spaceview3d.show_viewer*", "modeling/geometry_nodes/output/viewer.html#bpy-types-spaceview3d-show-viewer"), + ("bpy.types.textcurve.use_fast_edit*", "modeling/texts/properties.html#bpy-types-textcurve-use-fast-edit"), ("bpy.types.texturenodecombinecolor*", "editors/texture_node/types/color/combine_color.html#bpy-types-texturenodecombinecolor"), ("bpy.types.texturenodetexdistnoise*", "editors/texture_node/types/textures/distorted_noise.html#bpy-types-texturenodetexdistnoise"), ("bpy.types.vertexweightmixmodifier*", "modeling/modifiers/modify/weight_mix.html#bpy-types-vertexweightmixmodifier"), @@ -1756,8 +1802,9 @@ ("bpy.ops.gpencil.stroke_subdivide*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-subdivide"), ("bpy.ops.gpencil.vertex_color_hsv*", "grease_pencil/modes/vertex_paint/editing.html#bpy-ops-gpencil-vertex-color-hsv"), ("bpy.ops.gpencil.vertex_color_set*", "grease_pencil/modes/vertex_paint/editing.html#bpy-ops-gpencil-vertex-color-set"), - ("bpy.ops.graph.extrapolation_type*", "editors/graph_editor/channels.html#bpy-ops-graph-extrapolation-type"), + ("bpy.ops.graph.extrapolation_type*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-extrapolation-type"), ("bpy.ops.graph.interpolation_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-interpolation-type"), + ("bpy.ops.image.match_movie_length*", "editors/image/image_settings.html#bpy-ops-image-match-movie-length"), ("bpy.ops.mesh.customdata_skin_add*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-skin-add"), ("bpy.ops.mesh.dissolve_degenerate*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-dissolve-degenerate"), ("bpy.ops.mesh.face_split_by_edges*", "modeling/meshes/editing/face/weld_edges_faces.html#bpy-ops-mesh-face-split-by-edges"), @@ -1854,6 +1901,8 @@ ("bpy.types.greasepencilgrid.scale*", "grease_pencil/properties/display.html#bpy-types-greasepencilgrid-scale"), ("bpy.types.imagepaint.use_occlude*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-use-occlude"), ("bpy.types.imagesequence.use_flip*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-imagesequence-use-flip"), + ("bpy.types.imagetexture.extension*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-extension"), + ("bpy.types.imagetexture.use_alpha*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-alpha"), ("bpy.types.keyframe.interpolation*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-interpolation"), ("bpy.types.latticegpencilmodifier*", "grease_pencil/modifiers/deform/lattice.html#bpy-types-latticegpencilmodifier"), ("bpy.types.lineartgpencilmodifier*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier"), @@ -1886,6 +1935,7 @@ ("bpy.types.sound.use_memory_cache*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-sound-use-memory-cache"), ("bpy.types.spaceview3d.clip_start*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-clip-start"), ("bpy.types.spaceview3d.show_gizmo*", "editors/3dview/display/gizmo.html#bpy-types-spaceview3d-show-gizmo"), + ("bpy.types.textcurve.follow_curve*", "modeling/texts/properties.html#bpy-types-textcurve-follow-curve"), ("bpy.types.texturegpencilmodifier*", "grease_pencil/modifiers/modify/texture_mapping.html#bpy-types-texturegpencilmodifier"), ("bpy.types.texturenodecoordinates*", "editors/texture_node/types/input/coordinates.html#bpy-types-texturenodecoordinates"), ("bpy.types.texturenodetexmusgrave*", "editors/texture_node/types/textures/musgrave.html#bpy-types-texturenodetexmusgrave"), @@ -1903,6 +1953,7 @@ ("bpy.ops.armature.select_similar*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-similar"), ("bpy.ops.clip.create_plane_track*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-create-plane-track"), ("bpy.ops.curve.spline_weight_set*", "modeling/curves/editing/other.html#bpy-ops-curve-spline-weight-set"), + ("bpy.ops.file.external_operation*", "editors/file_browser.html#bpy-ops-file-external-operation"), ("bpy.ops.gpencil.blank_frame_add*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-blank-frame-add"), ("bpy.ops.gpencil.frame_duplicate*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-frame-duplicate"), ("bpy.ops.gpencil.layer_duplicate*", "grease_pencil/properties/layers.html#bpy-ops-gpencil-layer-duplicate"), @@ -1937,7 +1988,6 @@ ("bpy.ops.object.shape_key_remove*", "animation/shape_keys/shape_keys_panel.html#bpy-ops-object-shape-key-remove"), ("bpy.ops.object.shape_key_retime*", "animation/shape_keys/shape_keys_panel.html#bpy-ops-object-shape-key-retime"), ("bpy.ops.object.vertex_group_add*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-add"), - ("bpy.ops.object.vertex_group_fix*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-fix"), ("bpy.ops.outliner.collection_new*", "editors/outliner/editing.html#bpy-ops-outliner-collection-new"), ("bpy.ops.outliner.show_hierarchy*", "editors/outliner/editing.html#bpy-ops-outliner-show-hierarchy"), ("bpy.ops.outliner.show_one_level*", "editors/outliner/editing.html#bpy-ops-outliner-show-one-level"), @@ -1950,6 +2000,7 @@ ("bpy.ops.scene.view_layer_remove*", "render/layers/introduction.html#bpy-ops-scene-view-layer-remove"), ("bpy.ops.screen.screen_full_area*", "interface/window_system/areas.html#bpy-ops-screen-screen-full-area"), ("bpy.ops.sculpt.face_sets_create*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-sets-create"), + ("bpy.ops.sculpt.trim_box_gesture*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-trim-box-gesture"), ("bpy.ops.sequencer.select_linked*", "video_editing/edit/montage/selecting.html#bpy-ops-sequencer-select-linked"), ("bpy.ops.transform.rotate_normal*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-transform-rotate-normal"), ("bpy.ops.transform.shrink_fatten*", "modeling/meshes/editing/mesh/transform/shrink-fatten.html#bpy-ops-transform-shrink-fatten"), @@ -1986,7 +2037,7 @@ ("bpy.types.curves.surface_uv_map*", "modeling/curves/primitives.html#bpy-types-curves-surface-uv-map"), ("bpy.types.dampedtrackconstraint*", "animation/constraints/tracking/damped_track.html#bpy-types-dampedtrackconstraint"), ("bpy.types.distortednoisetexture*", "render/materials/legacy_textures/types/distorted_noise.html#bpy-types-distortednoisetexture"), - ("bpy.types.dopesheet.filter_text*", "editors/graph_editor/channels.html#bpy-types-dopesheet-filter-text"), + ("bpy.types.dopesheet.filter_text*", "editors/graph_editor/channels/introduction.html#bpy-types-dopesheet-filter-text"), ("bpy.types.editbone.bbone_easein*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-easein"), ("bpy.types.editbone.bbone_rollin*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-rollin"), ("bpy.types.fcurve.auto_smoothing*", "editors/graph_editor/fcurves/properties.html#bpy-types-fcurve-auto-smoothing"), @@ -2052,7 +2103,7 @@ ("bpy.types.volumedisplay.density*", "modeling/volumes/properties.html#bpy-types-volumedisplay-density"), ("bpy.types.volumerender.clipping*", "modeling/volumes/properties.html#bpy-types-volumerender-clipping"), ("bpy.types.workspace.object_mode*", "interface/window_system/workspaces.html#bpy-types-workspace-object-mode"), - ("bpy.ops.anim.channels_collapse*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-collapse"), + ("bpy.ops.anim.channels_collapse*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-collapse"), ("bpy.ops.anim.driver_button_add*", "animation/drivers/usage.html#bpy-ops-anim-driver-button-add"), ("bpy.ops.armature.click_extrude*", "animation/armatures/bones/editing/extrude.html#bpy-ops-armature-click-extrude"), ("bpy.ops.armature.select_linked*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-linked"), @@ -2104,7 +2155,7 @@ ("bpy.types.compositornodefilter*", "compositing/types/filter/filter_node.html#bpy-types-compositornodefilter"), ("bpy.types.compositornodehuesat*", "compositing/types/color/hue_saturation.html#bpy-types-compositornodehuesat"), ("bpy.types.compositornodeidmask*", "compositing/types/converter/id_mask.html#bpy-types-compositornodeidmask"), - ("bpy.types.compositornodeinvert*", "compositing/types/color/invert.html#bpy-types-compositornodeinvert"), + ("bpy.types.compositornodeinvert*", "compositing/types/color/invert_color.html#bpy-types-compositornodeinvert"), ("bpy.types.compositornodekeying*", "compositing/types/matte/keying.html#bpy-types-compositornodekeying"), ("bpy.types.compositornodelevels*", "compositing/types/output/levels.html#bpy-types-compositornodelevels"), ("bpy.types.compositornodemixrgb*", "compositing/types/color/mix.html#bpy-types-compositornodemixrgb"), @@ -2149,7 +2200,6 @@ ("bpy.types.scene.background_set*", "scene_layout/scene/properties.html#bpy-types-scene-background-set"), ("bpy.types.sequence.frame_start*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-sequence-frame-start"), ("bpy.types.shadernodebackground*", "render/shader_nodes/shader/background.html#bpy-types-shadernodebackground"), - ("bpy.types.shadernodebsdfglossy*", "render/shader_nodes/shader/glossy.html#bpy-types-shadernodebsdfglossy"), ("bpy.types.shadernodebsdfvelvet*", "render/shader_nodes/shader/velvet.html#bpy-types-shadernodebsdfvelvet"), ("bpy.types.shadernodecameradata*", "render/shader_nodes/input/camera_data.html#bpy-types-shadernodecameradata"), ("bpy.types.shadernodecombinexyz*", "render/shader_nodes/converter/combine_xyz.html#bpy-types-shadernodecombinexyz"), @@ -2168,6 +2218,8 @@ ("bpy.types.spaceview3d.clip_end*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-clip-end"), ("bpy.types.speedcontrolsequence*", "video_editing/edit/montage/strips/effects/speed_control.html#bpy-types-speedcontrolsequence"), ("bpy.types.spotlight.spot_blend*", "render/lights/light_object.html#bpy-types-spotlight-spot-blend"), + ("bpy.types.textcurve.space_line*", "modeling/texts/properties.html#bpy-types-textcurve-space-line"), + ("bpy.types.textcurve.space_word*", "modeling/texts/properties.html#bpy-types-textcurve-space-word"), ("bpy.types.texturenodecurvetime*", "editors/texture_node/types/input/time.html#bpy-types-texturenodecurvetime"), ("bpy.types.texturenodetexclouds*", "editors/texture_node/types/textures/clouds.html#bpy-types-texturenodetexclouds"), ("bpy.types.texturenodetexmarble*", "editors/texture_node/types/textures/marble.html#bpy-types-texturenodetexmarble"), @@ -2179,7 +2231,7 @@ ("bpy.types.volume.sequence_mode*", "modeling/volumes/properties.html#bpy-types-volume-sequence-mode"), ("bpy.types.volumetomeshmodifier*", "modeling/modifiers/generate/volume_to_mesh.html#bpy-types-volumetomeshmodifier"), ("bpy.types.whitebalancemodifier*", "editors/video_sequencer/sequencer/sidebar/modifiers.html#bpy-types-whitebalancemodifier"), - ("bpy.ops.anim.channels_ungroup*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-ungroup"), + ("bpy.ops.anim.channels_ungroup*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-ungroup"), ("bpy.ops.armature.extrude_move*", "animation/armatures/bones/editing/extrude.html#bpy-ops-armature-extrude-move"), ("bpy.ops.armature.parent_clear*", "animation/armatures/bones/editing/parenting.html#bpy-ops-armature-parent-clear"), ("bpy.ops.clip.clear_track_path*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clear-track-path"), @@ -2194,6 +2246,7 @@ ("bpy.ops.gpencil.select_random*", "grease_pencil/selecting.html#bpy-ops-gpencil-select-random"), ("bpy.ops.gpencil.stroke_sample*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-sample"), ("bpy.ops.gpencil.stroke_smooth*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-stroke-smooth"), + ("bpy.ops.graph.gaussian_smooth*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-gaussian-smooth"), ("bpy.ops.graph.keyframe_insert*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-keyframe-insert"), ("bpy.ops.image.read_viewlayers*", "editors/image/editing.html#bpy-ops-image-read-viewlayers"), ("bpy.ops.mask.add_vertex_slide*", "movie_clip/masking/editing.html#bpy-ops-mask-add-vertex-slide"), @@ -2267,6 +2320,8 @@ ("bpy.types.curves.use_mirror_z*", "sculpt_paint/curves_sculpting/introduction.html#bpy-types-curves-use-mirror-z"), ("bpy.types.cyclesworldsettings*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings"), ("bpy.types.dashgpencilmodifier*", "grease_pencil/modifiers/generate/dash.html#bpy-types-dashgpencilmodifier"), + ("bpy.types.drivervariable.name*", "animation/drivers/drivers_panel.html#bpy-types-drivervariable-name"), + ("bpy.types.drivervariable.type*", "animation/drivers/drivers_panel.html#bpy-types-drivervariable-type"), ("bpy.types.fieldsettings.noise*", "physics/forces/force_fields/introduction.html#bpy-types-fieldsettings-noise"), ("bpy.types.fieldsettings.shape*", "physics/forces/force_fields/introduction.html#bpy-types-fieldsettings-shape"), ("bpy.types.fluiddomainsettings*", "physics/fluid/type/domain/index.html#bpy-types-fluiddomainsettings"), @@ -2324,8 +2379,8 @@ ("bpy.types.viewlayer.use_solid*", "render/layers/introduction.html#bpy-types-viewlayer-use-solid"), ("bpy.types.volume.frame_offset*", "modeling/volumes/properties.html#bpy-types-volume-frame-offset"), ("bpy.types.windowmanager.addon*", "editors/preferences/addons.html#bpy-types-windowmanager-addon"), - ("bpy.ops.anim.channels_delete*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-delete"), - ("bpy.ops.anim.channels_expand*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-expand"), + ("bpy.ops.anim.channels_delete*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-delete"), + ("bpy.ops.anim.channels_expand*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-expand"), ("bpy.ops.anim.keyframe_delete*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-delete"), ("bpy.ops.anim.keyframe_insert*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-insert"), ("bpy.ops.armature.bone_layers*", "animation/armatures/bones/editing/change_layers.html#bpy-ops-armature-bone-layers"), @@ -2457,6 +2512,9 @@ ("bpy.types.shrinkwrapmodifier*", "modeling/modifiers/deform/shrinkwrap.html#bpy-types-shrinkwrapmodifier"), ("bpy.types.spaceview3d.camera*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-camera"), ("bpy.types.splineikconstraint*", "animation/constraints/tracking/spline_ik.html#bpy-types-splineikconstraint"), + ("bpy.types.textcurve.offset_x*", "modeling/texts/properties.html#bpy-types-textcurve-offset-x"), + ("bpy.types.textcurve.offset_y*", "modeling/texts/properties.html#bpy-types-textcurve-offset-y"), + ("bpy.types.textcurve.overflow*", "modeling/texts/properties.html#bpy-types-textcurve-overflow"), ("bpy.types.texturenodechecker*", "editors/texture_node/types/patterns/checker.html#bpy-types-texturenodechecker"), ("bpy.types.texturenodergbtobw*", "editors/texture_node/types/converter/rgb_to_bw.html#bpy-types-texturenodergbtobw"), ("bpy.types.texturenodetexture*", "editors/texture_node/types/input/texture.html#bpy-types-texturenodetexture"), @@ -2466,7 +2524,7 @@ ("bpy.types.volume.frame_start*", "modeling/volumes/properties.html#bpy-types-volume-frame-start"), ("bpy.types.volume.is_sequence*", "modeling/volumes/properties.html#bpy-types-volume-is-sequence"), ("bpy.types.volumerender.space*", "modeling/volumes/properties.html#bpy-types-volumerender-space"), - ("bpy.ops.anim.channels_group*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-group"), + ("bpy.ops.anim.channels_group*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-group"), ("bpy.ops.anim.keyframe_clear*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-clear"), ("bpy.ops.armature.flip_names*", "animation/armatures/bones/editing/naming.html#bpy-ops-armature-flip-names"), ("bpy.ops.armature.parent_set*", "animation/armatures/bones/editing/parenting.html#bpy-ops-armature-parent-set"), @@ -2492,7 +2550,7 @@ ("bpy.ops.gpencil.stroke_join*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-join"), ("bpy.ops.gpencil.stroke_trim*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-trim"), ("bpy.ops.gpencil.trace_image*", "grease_pencil/modes/object/trace_image.html#bpy-ops-gpencil-trace-image"), - ("bpy.ops.graph.fmodifier_add*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-fmodifier-add"), + ("bpy.ops.graph.fmodifier_add*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-fmodifier-add"), ("bpy.ops.image.external_edit*", "editors/image/editing.html#bpy-ops-image-external-edit"), ("bpy.ops.mesh.colors_reverse*", "modeling/meshes/editing/face/face_data.html#bpy-ops-mesh-colors-reverse"), ("bpy.ops.mesh.dissolve_edges*", "modeling/meshes/editing/mesh/delete.html#bpy-ops-mesh-dissolve-edges"), @@ -2534,6 +2592,7 @@ ("bpy.ops.ui.eyedropper_color*", "interface/controls/templates/color_picker.html#bpy-ops-ui-eyedropper-color"), ("bpy.ops.uv.cylinder_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-cylinder-project"), ("bpy.ops.uv.minimize_stretch*", "modeling/meshes/uv/editing.html#bpy-ops-uv-minimize-stretch"), + ("bpy.ops.uv.select_edge_loop*", "editors/uv/selecting.html#bpy-ops-uv-select-edge-loop"), ("bpy.ops.uv.select_edge_ring*", "editors/uv/selecting.html#bpy-ops-uv-select-edge-ring"), ("bpy.ops.wm.save_as_mainfile*", "files/blend/open_save.html#bpy-ops-wm-save-as-mainfile"), ("bpy.types.action.use_cyclic*", "animation/actions.html#bpy-types-action-use-cyclic"), @@ -2551,6 +2610,7 @@ ("bpy.types.compositornodergb*", "compositing/types/input/rgb.html#bpy-types-compositornodergb"), ("bpy.types.curve.bevel_depth*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-depth"), ("bpy.types.curve.use_stretch*", "modeling/curves/properties/shape.html#bpy-types-curve-use-stretch"), + ("bpy.types.driver.expression*", "animation/drivers/drivers_panel.html#bpy-types-driver-expression"), ("bpy.types.edgesplitmodifier*", "modeling/modifiers/generate/edge_split.html#bpy-types-edgesplitmodifier"), ("bpy.types.fcurve.color_mode*", "editors/graph_editor/fcurves/properties.html#bpy-types-fcurve-color-mode"), ("bpy.types.fluidflowsettings*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings"), @@ -2560,6 +2620,7 @@ ("bpy.types.geometrynodesetid*", "modeling/geometry_nodes/geometry/write/set_id.html#bpy-types-geometrynodesetid"), ("bpy.types.gpencillayer.hide*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-hide"), ("bpy.types.gpencillayer.lock*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-lock"), + ("bpy.types.image.seam_margin*", "editors/image/image_settings.html#bpy-types-image-seam-margin"), ("bpy.types.imagepaint.dither*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-dither"), ("bpy.types.material.metallic*", "render/materials/settings.html#bpy-types-material-metallic"), ("bpy.types.materialslot.link*", "render/materials/assignment.html#bpy-types-materialslot-link"), @@ -2590,13 +2651,16 @@ ("bpy.types.shadernodetexwave*", "render/shader_nodes/textures/wave.html#bpy-types-shadernodetexwave"), ("bpy.types.soundsequence.pan*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-soundsequence-pan"), ("bpy.types.spline.use_smooth*", "modeling/curves/properties/active_spline.html#bpy-types-spline-use-smooth"), + ("bpy.types.textcurve.align_x*", "modeling/texts/properties.html#bpy-types-textcurve-align-x"), + ("bpy.types.textcurve.align_y*", "modeling/texts/properties.html#bpy-types-textcurve-align-y"), ("bpy.types.texturenodebricks*", "editors/texture_node/types/patterns/bricks.html#bpy-types-texturenodebricks"), - ("bpy.types.texturenodeinvert*", "editors/texture_node/types/color/invert.html#bpy-types-texturenodeinvert"), + ("bpy.types.texturenodeinvert*", "editors/texture_node/types/color/invert_color.html#bpy-types-texturenodeinvert"), ("bpy.types.texturenodemixrgb*", "editors/texture_node/types/color/mix_rgb.html#bpy-types-texturenodemixrgb"), ("bpy.types.texturenodeoutput*", "editors/texture_node/types/output/output.html#bpy-types-texturenodeoutput"), ("bpy.types.texturenoderotate*", "editors/texture_node/types/distort/rotate.html#bpy-types-texturenoderotate"), ("bpy.types.texturenodeviewer*", "editors/texture_node/types/output/viewer.html#bpy-types-texturenodeviewer"), ("bpy.types.textureslot.scale*", "sculpt_paint/brush/texture.html#bpy-types-textureslot-scale"), + ("bpy.types.themebonecolorset*", "animation/armatures/properties/bone_groups.html#bpy-types-themebonecolorset"), ("bpy.types.tracktoconstraint*", "animation/constraints/tracking/track_to.html#bpy-types-tracktoconstraint"), ("bpy.types.transformsequence*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence"), ("bpy.types.uvprojectmodifier*", "modeling/modifiers/modify/uv_project.html#bpy-types-uvprojectmodifier"), @@ -2604,7 +2668,7 @@ ("bpy.types.viewlayer.use_sky*", "render/layers/introduction.html#bpy-types-viewlayer-use-sky"), ("bpy.types.wireframemodifier*", "modeling/modifiers/generate/wireframe.html#bpy-types-wireframemodifier"), ("bpy.types.worldmistsettings*", "render/cycles/world_settings.html#bpy-types-worldmistsettings"), - ("bpy.ops.anim.channels_move*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-move"), + ("bpy.ops.anim.channels_move*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-move"), ("bpy.ops.armature.subdivide*", "animation/armatures/bones/editing/subdivide.html#bpy-ops-armature-subdivide"), ("bpy.ops.asset.catalog_redo*", "editors/asset_browser.html#bpy-ops-asset-catalog-redo"), ("bpy.ops.asset.catalog_undo*", "editors/asset_browser.html#bpy-ops-asset-catalog-undo"), @@ -2617,7 +2681,7 @@ ("bpy.ops.curve.extrude_move*", "modeling/curves/editing/control_points.html#bpy-ops-curve-extrude-move"), ("bpy.ops.curve.make_segment*", "modeling/curves/editing/control_points.html#bpy-ops-curve-make-segment"), ("bpy.ops.file.directory_new*", "editors/file_browser.html#bpy-ops-file-directory-new"), - ("bpy.ops.graph.euler_filter*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-euler-filter"), + ("bpy.ops.graph.euler_filter*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-euler-filter"), ("bpy.ops.marker.camera_bind*", "animation/markers.html#bpy-ops-marker-camera-bind"), ("bpy.ops.mask.cyclic_toggle*", "movie_clip/masking/editing.html#bpy-ops-mask-cyclic-toggle"), ("bpy.ops.mask.hide_view_set*", "movie_clip/masking/editing.html#bpy-ops-mask-hide-view-set"), @@ -2655,13 +2719,14 @@ ("bpy.ops.screen.repeat_last*", "interface/undo_redo.html#bpy-ops-screen-repeat-last"), ("bpy.ops.sculpt.mask_expand*", "sculpt_paint/sculpting/editing/expand.html#bpy-ops-sculpt-mask-expand"), ("bpy.ops.sculpt.mask_filter*", "sculpt_paint/sculpting/editing/mask.html#bpy-ops-sculpt-mask-filter"), + ("bpy.ops.sculpt.mesh_filter*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-mesh-filter"), ("bpy.ops.transform.tosphere*", "modeling/meshes/editing/mesh/transform/to_sphere.html#bpy-ops-transform-tosphere"), ("bpy.ops.view3d.clip_border*", "editors/3dview/navigate/regions.html#bpy-ops-view3d-clip-border"), ("bpy.ops.view3d.toggle_xray*", "modeling/meshes/selecting/introduction.html#bpy-ops-view3d-toggle-xray"), ("bpy.ops.view3d.view_camera*", "editors/3dview/navigate/camera_view.html#bpy-ops-view3d-view-camera"), ("bpy.ops.view3d.zoom_border*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-zoom-border"), ("bpy.ops.wm.previews_ensure*", "files/blend/previews.html#bpy-ops-wm-previews-ensure"), - ("bpy.ops.wm.properties_edit*", "files/data_blocks.html#bpy-ops-wm-properties-edit"), + ("bpy.ops.wm.properties_edit*", "files/custom_properties.html#bpy-ops-wm-properties-edit"), ("bpy.ops.wm.search_operator*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search-operator"), ("bpy.types.actionconstraint*", "animation/constraints/relationship/action.html#bpy-types-actionconstraint"), ("bpy.types.addonpreferences*", "editors/preferences/addons.html#bpy-types-addonpreferences"), @@ -2710,7 +2775,7 @@ ("bpy.types.sequencemodifier*", "editors/video_sequencer/sequencer/sidebar/modifiers.html#bpy-types-sequencemodifier"), ("bpy.types.shaderfxcolorize*", "grease_pencil/visual_effects/colorize.html#bpy-types-shaderfxcolorize"), ("bpy.types.shaderfxpixelate*", "grease_pencil/visual_effects/pixelate.html#bpy-types-shaderfxpixelate"), - ("bpy.types.shadernodeinvert*", "render/shader_nodes/color/invert.html#bpy-types-shadernodeinvert"), + ("bpy.types.shadernodeinvert*", "render/shader_nodes/color/invert_color.html#bpy-types-shadernodeinvert"), ("bpy.types.shadernodemixrgb*", "modeling/geometry_nodes/utilities/color/mix_rgb.html#bpy-types-shadernodemixrgb"), ("bpy.types.shadernodenormal*", "render/shader_nodes/vector/normal.html#bpy-types-shadernodenormal"), ("bpy.types.shadernodescript*", "render/shader_nodes/osl.html#bpy-types-shadernodescript"), @@ -2730,6 +2795,7 @@ ("bpy.types.spotlight.energy*", "render/lights/light_object.html#bpy-types-spotlight-energy"), ("bpy.types.subtractsequence*", "video_editing/edit/montage/strips/effects/subtract.html#bpy-types-subtractsequence"), ("bpy.types.text.indentation*", "editors/text_editor.html#bpy-types-text-indentation"), + ("bpy.types.textcurve.family*", "modeling/texts/properties.html#bpy-types-textcurve-family"), ("bpy.types.texture.contrast*", "render/materials/legacy_textures/colors.html#bpy-types-texture-contrast"), ("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"), ("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"), @@ -2802,6 +2868,7 @@ ("bpy.types.constraint.name*", "animation/constraints/interface/header.html#bpy-types-constraint-name"), ("bpy.types.curve.eval_time*", "modeling/curves/properties/path_animation.html#bpy-types-curve-eval-time"), ("bpy.types.curve.fill_mode*", "modeling/curves/properties/shape.html#bpy-types-curve-fill-mode"), + ("bpy.types.driver.use_self*", "animation/drivers/drivers_panel.html#bpy-types-driver-use-self"), ("bpy.types.editbone.layers*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-layers"), ("bpy.types.editbone.parent*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-parent"), ("bpy.types.explodemodifier*", "modeling/modifiers/physics/explode.html#bpy-types-explodemodifier"), @@ -2835,6 +2902,8 @@ ("bpy.types.spacetexteditor*", "editors/text_editor.html#bpy-types-spacetexteditor"), ("bpy.types.subsurfmodifier*", "modeling/modifiers/generate/subdivision_surface.html#bpy-types-subsurfmodifier"), ("bpy.types.sunlight.energy*", "render/lights/light_object.html#bpy-types-sunlight-energy"), + ("bpy.types.text.use_module*", "editors/text_editor.html#bpy-types-text-use-module"), + ("bpy.types.textcurve.shear*", "modeling/texts/properties.html#bpy-types-textcurve-shear"), ("bpy.types.texturenodemath*", "editors/texture_node/types/converter/math.html#bpy-types-texturenodemath"), ("bpy.types.volume.filepath*", "modeling/volumes/properties.html#bpy-types-volume-filepath"), ("bpy.ops.asset.tag_remove*", "editors/asset_browser.html#bpy-ops-asset-tag-remove"), @@ -2846,9 +2915,10 @@ ("bpy.ops.fluid.bake_noise*", "physics/fluid/type/domain/gas/noise.html#bpy-ops-fluid-bake-noise"), ("bpy.ops.fluid.free_noise*", "physics/fluid/type/domain/gas/noise.html#bpy-ops-fluid-free-noise"), ("bpy.ops.font.move_select*", "modeling/texts/selecting.html#bpy-ops-font-move-select"), + ("bpy.ops.font.textbox_add*", "modeling/texts/properties.html#bpy-ops-font-textbox-add"), ("bpy.ops.gpencil.dissolve*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-dissolve"), ("bpy.ops.graph.frame_jump*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-frame-jump"), - ("bpy.ops.graph.sound_bake*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-sound-bake"), + ("bpy.ops.graph.sound_bake*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-sound-bake"), ("bpy.ops.marker.duplicate*", "animation/markers.html#bpy-ops-marker-duplicate"), ("bpy.ops.mask.select_less*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-less"), ("bpy.ops.mask.select_more*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-more"), @@ -2898,6 +2968,8 @@ ("bpy.types.curves.surface*", "modeling/curves/primitives.html#bpy-types-curves-surface"), ("bpy.types.curvesmodifier*", "editors/video_sequencer/sequencer/sidebar/modifiers.html#bpy-types-curvesmodifier"), ("bpy.types.ffmpegsettings*", "render/output/properties/output.html#bpy-types-ffmpegsettings"), + ("bpy.types.fmodifier.mute*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifier-mute"), + ("bpy.types.fmodifier.name*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifier-name"), ("bpy.types.fmodifiernoise*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiernoise"), ("bpy.types.image.filepath*", "editors/image/image_settings.html#bpy-types-image-filepath"), ("bpy.types.keyframe.co_ui*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-co-ui"), @@ -2923,6 +2995,7 @@ ("bpy.types.sound.use_mono*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-sound-use-mono"), ("bpy.types.spline.order_u*", "modeling/curves/properties/active_spline.html#bpy-types-spline-order-u"), ("bpy.types.sunlight.angle*", "render/lights/light_object.html#bpy-types-sunlight-angle"), + ("bpy.types.textcurve.size*", "modeling/texts/properties.html#bpy-types-textcurve-size"), ("bpy.types.timelinemarker*", "animation/markers.html#bpy-types-timelinemarker"), ("bpy.types.usersolidlight*", "editors/preferences/lights.html#bpy-types-usersolidlight"), ("bpy.types.uvwarpmodifier*", "modeling/modifiers/modify/uv_warp.html#bpy-types-uvwarpmodifier"), @@ -2963,7 +3036,6 @@ ("bpy.ops.node.links_mute*", "interface/controls/nodes/editing.html#bpy-ops-node-links-mute"), ("bpy.ops.node.parent_set*", "interface/controls/nodes/frame.html#bpy-ops-node-parent-set"), ("bpy.ops.object.armature*", "animation/armatures/index.html#bpy-ops-object-armature"), - ("bpy.ops.object.face_map*", "modeling/meshes/properties/object_data.html#bpy-ops-object-face-map"), ("bpy.ops.object.join_uvs*", "scene_layout/object/editing/link_transfer/copy_uvmaps.html#bpy-ops-object-join-uvs"), ("bpy.ops.object.mode_set*", "editors/3dview/modes.html#bpy-ops-object-mode-set"), ("bpy.ops.outliner.delete*", "editors/outliner/editing.html#bpy-ops-outliner-delete"), @@ -2973,6 +3045,7 @@ ("bpy.ops.rigidbody.world*", "physics/rigid_body/world.html#bpy-ops-rigidbody-world"), ("bpy.ops.sculpt.optimize*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-optimize"), ("bpy.ops.sequencer.split*", "video_editing/edit/montage/editing.html#bpy-ops-sequencer-split"), + ("bpy.ops.text.run_script*", "editors/text_editor.html#bpy-ops-text-run-script"), ("bpy.ops.transform.shear*", "modeling/meshes/editing/mesh/transform/shear.html#bpy-ops-transform-shear"), ("bpy.ops.uv.cube_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-cube-project"), ("bpy.ops.uv.pack_islands*", "modeling/meshes/uv/editing.html#bpy-ops-uv-pack-islands"), @@ -3035,6 +3108,7 @@ ("bpy.types.spacetimeline*", "editors/timeline.html#bpy-types-spacetimeline"), ("bpy.types.spaceuveditor*", "editors/uv/index.html#bpy-types-spaceuveditor"), ("bpy.types.stuccitexture*", "render/materials/legacy_textures/types/stucci.html#bpy-types-stuccitexture"), + ("bpy.types.textbox.width*", "modeling/texts/properties.html#bpy-types-textbox-width"), ("bpy.types.texturenodeat*", "editors/texture_node/types/distort/at.html#bpy-types-texturenodeat"), ("bpy.types.view3doverlay*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay"), ("bpy.types.viewlayer.use*", "render/layers/view_layer.html#bpy-types-viewlayer-use"), @@ -3088,6 +3162,7 @@ ("bpy.types.brush.jitter*", "sculpt_paint/brush/stroke.html#bpy-types-brush-jitter"), ("bpy.types.castmodifier*", "modeling/modifiers/deform/cast.html#bpy-types-castmodifier"), ("bpy.types.curve.offset*", "modeling/curves/properties/geometry.html#bpy-types-curve-offset"), + ("bpy.types.drivertarget*", "animation/drivers/drivers_panel.html#bpy-types-drivertarget"), ("bpy.types.geometrynode*", "modeling/geometry_nodes/index.html#bpy-types-geometrynode"), ("bpy.types.glowsequence*", "video_editing/edit/montage/strips/effects/glow.html#bpy-types-glowsequence"), ("bpy.types.gpencillayer*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer"), @@ -3156,7 +3231,9 @@ ("bpy.ops.wm.debug_menu*", "advanced/operators.html#bpy-ops-wm-debug-menu"), ("bpy.ops.wm.obj_export*", "files/import_export/obj.html#bpy-ops-wm-obj-export"), ("bpy.ops.wm.obj_import*", "files/import_export/obj.html#bpy-ops-wm-obj-import"), - ("bpy.ops.wm.properties*", "files/data_blocks.html#bpy-ops-wm-properties"), + ("bpy.ops.wm.ply_export*", "files/import_export/ply.html#bpy-ops-wm-ply-export"), + ("bpy.ops.wm.ply_import*", "files/import_export/ply.html#bpy-ops-wm-ply-import"), + ("bpy.ops.wm.properties*", "files/custom_properties.html#bpy-ops-wm-properties"), ("bpy.ops.wm.stl_import*", "files/import_export/stl.html#bpy-ops-wm-stl-import"), ("bpy.ops.wm.usd_export*", "files/import_export/usd.html#bpy-ops-wm-usd-export"), ("bpy.types.addsequence*", "video_editing/edit/montage/strips/effects/add.html#bpy-types-addsequence"), @@ -3165,6 +3242,7 @@ ("bpy.types.camera.show*", "render/cameras.html#bpy-types-camera-show"), ("bpy.types.consoleline*", "editors/python_console.html#bpy-types-consoleline"), ("bpy.types.curve.bevel*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel"), + ("bpy.types.driver.type*", "animation/drivers/drivers_panel.html#bpy-types-driver-type"), ("bpy.types.mesh.remesh*", "modeling/meshes/retopology.html#bpy-types-mesh-remesh"), ("bpy.types.meshstatvis*", "modeling/meshes/mesh_analysis.html#bpy-types-meshstatvis"), ("bpy.types.nodesetting*", "interface/controls/nodes/parts.html#bpy-types-nodesetting"), @@ -3192,10 +3270,10 @@ ("bpy.ops.gpencil.copy*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-copy"), ("bpy.ops.graph.delete*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-delete"), ("bpy.ops.graph.mirror*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-mirror"), - ("bpy.ops.graph.reveal*", "editors/graph_editor/channels.html#bpy-ops-graph-reveal"), + ("bpy.ops.graph.reveal*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-reveal"), ("bpy.ops.graph.sample*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-sample"), ("bpy.ops.graph.smooth*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-smooth"), - ("bpy.ops.graph.unbake*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-unbake"), + ("bpy.ops.graph.unbake*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-unbake"), ("bpy.ops.image.invert*", "editors/image/editing.html#bpy-ops-image-invert"), ("bpy.ops.image.reload*", "editors/image/editing.html#bpy-ops-image-reload"), ("bpy.ops.image.resize*", "editors/image/editing.html#bpy-ops-image-resize"), @@ -3205,12 +3283,13 @@ ("bpy.ops.object.empty*", "modeling/empties.html#bpy-ops-object-empty"), ("bpy.ops.object.quick*", "physics/introduction.html#bpy-ops-object-quick"), ("bpy.ops.text.replace*", "editors/text_editor.html#bpy-ops-text-replace"), + ("bpy.ops.text.save_as*", "editors/text_editor.html#bpy-ops-text-save-as"), ("bpy.ops.uv.mark_seam*", "modeling/meshes/uv/unwrapping/seams.html#bpy-ops-uv-mark-seam"), ("bpy.ops.view3d.dolly*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-dolly"), ("bpy.ops.view3d.ruler*", "editors/3dview/toolbar/measure.html#bpy-ops-view3d-ruler"), ("bpy.types.areaspaces*", "interface/window_system/areas.html#bpy-types-areaspaces"), ("bpy.types.bonegroups*", "animation/armatures/properties/bone_groups.html#bpy-types-bonegroups"), - ("bpy.types.bpy_struct*", "files/data_blocks.html#bpy-types-bpy-struct"), + ("bpy.types.bpy_struct*", "files/custom_properties.html#bpy-types-bpy-struct"), ("bpy.types.brush.rate*", "sculpt_paint/brush/stroke.html#bpy-types-brush-rate"), ("bpy.types.brush.size*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-size"), ("bpy.types.collection*", "scene_layout/collections/collections.html#bpy-types-collection"), @@ -3236,7 +3315,9 @@ ("bpy.ops.clip.reload*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-reload"), ("bpy.ops.curve.split*", "modeling/curves/editing/curve.html#bpy-ops-curve-split"), ("bpy.ops.file.cancel*", "editors/file_browser.html#bpy-ops-file-cancel"), + ("bpy.ops.file.delete*", "editors/file_browser.html#bpy-ops-file-delete"), ("bpy.ops.file.parent*", "editors/file_browser.html#bpy-ops-file-parent"), + ("bpy.ops.file.rename*", "editors/file_browser.html#bpy-ops-file-rename"), ("bpy.ops.graph.clean*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-clean"), ("bpy.ops.graph.paste*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-paste"), ("bpy.ops.marker.move*", "animation/markers.html#bpy-ops-marker-move"), @@ -3252,6 +3333,7 @@ ("bpy.ops.object.text*", "modeling/texts/index.html#bpy-ops-object-text"), ("bpy.ops.preferences*", "editors/preferences/index.html#bpy-ops-preferences"), ("bpy.ops.spreadsheet*", "editors/spreadsheet.html#bpy-ops-spreadsheet"), + ("bpy.ops.text.reload*", "editors/text_editor.html#bpy-ops-text-reload"), ("bpy.ops.uv.rip_move*", "modeling/meshes/uv/tools/rip.html#bpy-ops-uv-rip-move"), ("bpy.ops.view3d.snap*", "scene_layout/object/editing/snap.html#bpy-ops-view3d-snap"), ("bpy.ops.view3d.walk*", "editors/3dview/navigate/walk_fly.html#bpy-ops-view3d-walk"), @@ -3271,6 +3353,8 @@ ("bpy.types.nodegroup*", "interface/controls/nodes/groups.html#bpy-types-nodegroup"), ("bpy.types.scene.muv*", "addons/uv/magic_uv.html#bpy-types-scene-muv"), ("bpy.types.spotlight*", "render/lights/light_object.html#bpy-types-spotlight"), + ("bpy.types.textbox.x*", "modeling/texts/properties.html#bpy-types-textbox-x"), + ("bpy.types.textbox.y*", "modeling/texts/properties.html#bpy-types-textbox-y"), ("bpy.types.textcurve*", "modeling/texts/index.html#bpy-types-textcurve"), ("bpy.types.udimtiles*", "modeling/meshes/uv/workflows/udims.html#bpy-types-udimtiles"), ("bpy.types.uipiemenu*", "interface/controls/buttons/menus.html#bpy-types-uipiemenu"), @@ -3282,10 +3366,10 @@ ("bpy.ops.curve.draw*", "modeling/curves/tools/draw.html#bpy-ops-curve-draw"), ("bpy.ops.curve.hide*", "modeling/curves/editing/curve.html#bpy-ops-curve-hide"), ("bpy.ops.curve.spin*", "modeling/surfaces/editing/surface.html#bpy-ops-curve-spin"), - ("bpy.ops.graph.bake*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-bake"), + ("bpy.ops.graph.bake*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-bake"), ("bpy.ops.graph.copy*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-copy"), ("bpy.ops.graph.ease*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-ease"), - ("bpy.ops.graph.hide*", "editors/graph_editor/channels.html#bpy-ops-graph-hide"), + ("bpy.ops.graph.hide*", "editors/graph_editor/channels/editing.html#bpy-ops-graph-hide"), ("bpy.ops.graph.snap*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-snap"), ("bpy.ops.image.flip*", "editors/image/editing.html#bpy-ops-image-flip"), ("bpy.ops.image.open*", "editors/image/editing.html#bpy-ops-image-open"), @@ -3310,7 +3394,6 @@ ("bpy.types.aov.type*", "render/layers/passes.html#bpy-types-aov-type"), ("bpy.types.armature*", "animation/armatures/index.html#bpy-types-armature"), ("bpy.types.editbone*", "animation/armatures/bones/editing/index.html#bpy-types-editbone"), - ("bpy.types.facemaps*", "modeling/meshes/properties/object_data.html#bpy-types-facemaps"), ("bpy.types.keyframe*", "animation/keyframes/index.html#bpy-types-keyframe"), ("bpy.types.linesets*", "render/freestyle/view_layer/line_set.html#bpy-types-linesets"), ("bpy.types.material*", "render/materials/index.html#bpy-types-material"), @@ -3340,6 +3423,8 @@ ("bpy.ops.rigidbody*", "physics/rigid_body/index.html#bpy-ops-rigidbody"), ("bpy.ops.sequencer*", "video_editing/index.html#bpy-ops-sequencer"), ("bpy.ops.text.find*", "editors/text_editor.html#bpy-ops-text-find"), + ("bpy.ops.text.open*", "editors/text_editor.html#bpy-ops-text-open"), + ("bpy.ops.text.save*", "editors/text_editor.html#bpy-ops-text-save"), ("bpy.ops.transform*", "scene_layout/object/editing/transform/index.html#bpy-ops-transform"), ("bpy.ops.uv.reveal*", "modeling/meshes/uv/editing.html#bpy-ops-uv-reveal"), ("bpy.ops.uv.select*", "editors/uv/selecting.html#bpy-ops-uv-select"), @@ -3360,6 +3445,7 @@ ("bpy.ops.nla.swap*", "editors/nla/editing.html#bpy-ops-nla-swap"), ("bpy.ops.outliner*", "editors/outliner/index.html#bpy-ops-outliner"), ("bpy.ops.particle*", "physics/particles/index.html#bpy-ops-particle"), + ("bpy.ops.text.new*", "editors/text_editor.html#bpy-ops-text-new"), ("bpy.ops.uv.align*", "modeling/meshes/uv/editing.html#bpy-ops-uv-align"), ("bpy.ops.uv.paste*", "modeling/meshes/uv/editing.html#bpy-ops-uv-paste"), ("bpy.ops.uv.reset*", "modeling/meshes/editing/uv.html#bpy-ops-uv-reset"), diff --git a/scripts/startup/bl_ui/space_statusbar.py b/scripts/startup/bl_ui/space_statusbar.py index a281492aba85..bad53f8ae529 100644 --- a/scripts/startup/bl_ui/space_statusbar.py +++ b/scripts/startup/bl_ui/space_statusbar.py @@ -25,7 +25,7 @@ def draw(self, context): row.alignment = 'RIGHT' # Stats & Info - row.label(text=context.screen.statusbar_info(), translate=False) + layout.template_status_info() classes = ( diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 40b6ff586d0f..22d949d99987 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once +#include "BLI_utildefines.h" + #ifdef __cplusplus extern "C" { #endif @@ -22,7 +24,7 @@ extern "C" { #define UPBGE_VERSION 36 /* Blender patch version for bugfix releases. */ -#define BLENDER_VERSION_PATCH 1 +#define BLENDER_VERSION_PATCH 2 /** Blender release cycle stage: alpha/beta/rc/release. */ #define BLENDER_VERSION_CYCLE release @@ -39,10 +41,12 @@ extern "C" { #define UPBGE_FILE_SUBVERSION 0 /* 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 - * was written with too new a version. */ -#define BLENDER_FILE_MIN_VERSION 305 -#define BLENDER_FILE_MIN_SUBVERSION 9 + * version. Older Blender versions will test this and cancel loading the file, showing a warning to + * the user. + * + * See https://wiki.blender.org/wiki/Process/Compatibility_Handling for details. */ +#define BLENDER_FILE_MIN_VERSION 303 +#define BLENDER_FILE_MIN_SUBVERSION 06 /** User readable version string. */ const char *BKE_blender_version_string(void); @@ -51,6 +55,19 @@ const char *BKE_upbge_version_string(void); /* Returns true when version cycle is alpha, otherwise (beta, rc) returns false. */ bool BKE_blender_version_is_alpha(void); +/** Fill in given string buffer with user-readable formated file version and subversion (if + * provided). + * + * \param str_buff a char buffer where the formated string is written, minimal recommended size is + * 8, or 16 if subversion is provided. + * + * \param file_subversion the file subversion, if given value < 0, it is ignored, and only the + * `file_version` is used. */ +void BKE_blender_version_blendfile_string_from_values(char *str_buff, + const size_t str_buff_len, + const short file_version, + const short file_subversion); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h index f216ff58ab34..85e44a4bb6e0 100644 --- a/source/blender/blenkernel/BKE_blendfile.h +++ b/source/blender/blenkernel/BKE_blendfile.h @@ -45,6 +45,13 @@ bool BKE_blendfile_library_path_explode(const char *path, char **r_group, char **r_name); +/** + * Check whether a given path is actually a Blender-readable, valid .blend file. + * + * \note Currently does attempt to open and read (part of) the given file. + */ +bool BKE_blendfile_is_readable(const char *path, struct ReportList *reports); + /** * 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_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 360f82cffb17..699f179cac22 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -428,7 +428,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn /** * Swap two items of given custom data, in all available layers. */ -void CustomData_swap(struct CustomData *data, int index_a, int index_b); +void CustomData_swap(struct CustomData *data, int index_a, int index_b, const int totelem); /** * Retrieve a pointer to an element of the active layer of the given \a type, chosen by the diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 75c91600029f..6928359e2109 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -136,6 +136,13 @@ typedef struct Main { short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */ short upbgeversionfile, upbgesubversionfile; /* see UPBGE_FILE_VERSION, UPBGE_FILE_SUBVERSION */ short minversionfile, minsubversionfile; + /** The currently opened .blend file was written from a newer version of Blender, and has forward + * compatibility issues (data loss). + * + * \note: In practice currently this is only based on the version numbers, in the future it + * could try to use more refined detection on load. */ + bool has_forward_compatibility_issues; + /** Commit timestamp from `buildinfo`. */ uint64_t build_commit_timestamp; /** Commit Hash from `buildinfo`. */ @@ -456,6 +463,10 @@ int set_listbasepointers(struct Main *main, struct ListBase *lb[]); ((main)->versionfile < (ver) || \ ((main)->versionfile == (ver) && (main)->subversionfile < (subver))) +#define MAIN_VERSION_FILE_OLDER_OR_EQUAL(main, ver, subver) \ + ((main)->versionfile < (ver) || \ + ((main)->versionfile == (ver) && (main)->subversionfile <= (subver))) + /** * The size of thumbnails (optionally) stored in the `.blend` files header. * diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 137461db2ffb..00e8361d9dda 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -581,6 +581,7 @@ void BKE_mesh_polygon_flip_ex(int poly_offset, int *corner_verts, int *corner_edges, struct CustomData *ldata, + int tot_loop, float (*lnors)[3], struct MDisps *mdisp, bool use_loop_mdisp_flip); @@ -600,6 +601,7 @@ void BKE_mesh_polys_flip(const int *poly_offsets, int *corner_verts, int *corner_edges, struct CustomData *ldata, + int totloop, int totpoly); /** diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index d4450089965c..baf8a205c32b 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -160,6 +160,26 @@ const char *BKE_upbge_version_string() return upbge_version_string; } +void BKE_blender_version_blendfile_string_from_values(char *str_buff, + const size_t str_buff_len, + const short file_version, + const short file_subversion) +{ + const short file_version_major = file_version / 100; + const short file_version_minor = file_version % 100; + if (file_subversion >= 0) { + BLI_snprintf(str_buff, + str_buff_len, + "%d.%d (sub %d)", + file_version_major, + file_version_minor, + file_subversion); + } + else { + BLI_snprintf(str_buff, str_buff_len, "%d.%d", file_version_major, file_version_minor); + } +} + bool BKE_blender_version_is_alpha(void) { bool is_alpha = STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha"); diff --git a/source/blender/blenkernel/intern/blendfile.cc b/source/blender/blenkernel/intern/blendfile.cc index 427f7580aad3..4b8cbf7c224a 100644 --- a/source/blender/blenkernel/intern/blendfile.cc +++ b/source/blender/blenkernel/intern/blendfile.cc @@ -136,6 +136,18 @@ bool BKE_blendfile_library_path_explode(const char *path, return true; } +bool BKE_blendfile_is_readable(const char *path, ReportList *reports) +{ + BlendFileReadReport readfile_reports; + readfile_reports.reports = reports; + BlendHandle *bh = BLO_blendhandle_from_file(path, &readfile_reports); + if (bh != nullptr) { + BLO_blendhandle_close(bh); + return true; + } + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 08458d6d73c8..ef714b1cce5c 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -394,7 +394,6 @@ void BKE_collection_compat_blend_read_expand(struct BlendExpander *expander, void BKE_collection_blend_read_expand(BlendExpander *expander, Collection *collection) { - BLI_assert(collection->runtime.gobject_hash == NULL); LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { BLO_expand(expander, cob->ob); } diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index c644a663e410..c57cfd356acf 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -977,11 +977,11 @@ float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value /* account for clipping */ if (cumap->flag & CUMA_DO_CLIP) { - if (val < cumap->curr.ymin) { - val = cumap->curr.ymin; + if (val < cumap->clipr.ymin) { + val = cumap->clipr.ymin; } - else if (val > cumap->curr.ymax) { - val = cumap->curr.ymax; + else if (val > cumap->clipr.ymax) { + val = cumap->clipr.ymax; } } diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 5422439e1063..065735f6053c 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -3506,7 +3506,7 @@ void CustomData_swap_corners(CustomData *data, const int index, const int *corne } } -void CustomData_swap(CustomData *data, const int index_a, const int index_b) +void CustomData_swap(CustomData *data, const int index_a, const int index_b, const int totelem) { char buff_static[256]; @@ -3515,17 +3515,17 @@ void CustomData_swap(CustomData *data, const int index_a, const int index_b) } for (int i = 0; i < data->totlayer; i++) { - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); + CustomDataLayer &layer = data->layers[i]; + ensure_layer_data_is_mutable(layer, totelem); + const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer.type)); const size_t size = typeInfo->size; const size_t offset_a = size * index_a; const size_t offset_b = size * index_b; void *buff = size <= sizeof(buff_static) ? buff_static : MEM_mallocN(size, __func__); - memcpy(buff, POINTER_OFFSET(data->layers[i].data, offset_a), size); - memcpy(POINTER_OFFSET(data->layers[i].data, offset_a), - POINTER_OFFSET(data->layers[i].data, offset_b), - size); - memcpy(POINTER_OFFSET(data->layers[i].data, offset_b), buff, size); + memcpy(buff, POINTER_OFFSET(layer.data, offset_a), size); + memcpy(POINTER_OFFSET(layer.data, offset_a), POINTER_OFFSET(layer.data, offset_b), size); + memcpy(POINTER_OFFSET(layer.data, offset_b), buff, size); if (buff != buff_static) { MEM_freeN(buff); diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index b740abc1a779..f62bdc0de662 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -48,6 +48,7 @@ #include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_memarena.h" +#include "BLI_set.hh" #include "BLI_string.h" #include "BLI_task.h" #include "BLI_utildefines.h" @@ -71,6 +72,7 @@ #endif static CLG_LogRef LOG = {"bke.liboverride"}; +static CLG_LogRef LOG_RESYNC = {"bke.liboverride_resync"}; static void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst, IDOverrideLibraryProperty *op_src); @@ -1595,8 +1597,14 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int return best_root_id_candidate; } -static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID *id_from) +static void lib_override_root_hierarchy_set( + Main *bmain, ID *id_root, ID *id, ID *id_from, blender::Set &processed_ids) { + if (processed_ids.contains(id)) { + /* This ID has already been checked as having a valid hierarchy root, do not attempt to replace + * it with another one just because it is also used by another liboverride hierarchy. */ + return; + } if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { if (id->override_library->hierarchy_root == id_root) { /* Already set, nothing else to do here, sub-hierarchy is also assumed to be properly set @@ -1666,6 +1674,15 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID } } + CLOG_INFO(&LOG, + 3, + "Modifying library override hierarchy of ID '%s'.\n" + "\tFrom old root '%s' to new root '%s'.", + id->name, + id->override_library->hierarchy_root ? id->override_library->hierarchy_root->name : + "", + id_root->name); + id->override_library->hierarchy_root = id_root; } @@ -1690,7 +1707,7 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID } /* Recursively process the sub-hierarchy. */ - lib_override_root_hierarchy_set(bmain, id_root, to_id, id); + lib_override_root_hierarchy_set(bmain, id_root, to_id, id, processed_ids); } } @@ -1699,9 +1716,11 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) ID *id; BKE_main_relations_create(bmain, 0); + blender::Set processed_ids; FOREACH_MAIN_ID_BEGIN (bmain, id) { if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + processed_ids.add(id); continue; } if (id->override_library->hierarchy_root != nullptr) { @@ -1719,6 +1738,8 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) id->override_library->hierarchy_root = nullptr; } else { + /* This ID is considered as having a valid hierarchy root. */ + processed_ids.add(id); continue; } } @@ -1729,16 +1750,20 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level); if (!ELEM(id_root->override_library->hierarchy_root, id_root, nullptr)) { + /* FIXME This is probably never actually reached with current code? Check above for non-null + * hierarchy root pointer either skip the rest of the loop, or reset it to nullptr. */ CLOG_WARN(&LOG, - "Potential inconsistency in library override hierarchy of ID '%s', detected as " - "part of the hierarchy of '%s', which has a different root '%s'", + "Potential inconsistency in library override hierarchy of ID '%s' (current root " + "%s), detected as part of the hierarchy of '%s' (current root '%s')", id->name, + id->override_library->hierarchy_root->name, id_root->name, id_root->override_library->hierarchy_root->name); + processed_ids.add(id); continue; } - lib_override_root_hierarchy_set(bmain, id_root, id, nullptr); + lib_override_root_hierarchy_set(bmain, id_root, id, nullptr, processed_ids); BLI_assert(id->override_library->hierarchy_root != nullptr); } @@ -1929,7 +1954,7 @@ static bool lib_override_library_resync(Main *bmain, BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_resync_root)); if ((id_resync_root->tag & LIB_TAG_NO_MAIN) != 0) { - CLOG_ERROR(&LOG, + CLOG_ERROR(&LOG_RESYNC, "While dealing with root '%s', resync root ID '%s' (%p) found to be alreaady " "resynced.\n", id_root->name, @@ -2126,7 +2151,7 @@ static bool lib_override_library_resync(Main *bmain, BLI_assert(id_override_old == nullptr || id_override_old->lib == id_override_new->lib); if (id_override_old != nullptr) { BLI_ghash_insert(linkedref_to_old_override, id, id_override_old); - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 2, "Found missing linked old override best-match %s for new linked override %s", id_override_old->name, @@ -2244,6 +2269,30 @@ static bool lib_override_library_resync(Main *bmain, RNA_id_pointer_create(id_override_old, &rnaptr_src); RNA_id_pointer_create(id_override_new, &rnaptr_dst); + /* In case the parent of the liboverride object matches hierarchy-wise the parent of its + * linked reference, also enforce clearing any override of the other related parenting + * settings. + * + * While this may break some rare use-cases, in almost all situations the best behavior here + * is to follow the values from the reference data (especially when it comes to the invert + * parent matrix). */ + bool do_clear_parenting_override = false; + if (GS(id_override_new->name) == ID_OB) { + Object *ob_old = reinterpret_cast(id_override_old); + Object *ob_new = reinterpret_cast(id_override_new); + if (ob_new->parent && ob_new->parent != ob_old->parent && + /* Parent is not a liboverride. */ + (ob_new->parent == + reinterpret_cast(ob_new->id.override_library->reference)->parent || + /* Parent is a hierarchy-matching liboverride. */ + (ID_IS_OVERRIDE_LIBRARY_REAL(ob_new->parent) && + reinterpret_cast(ob_new->parent->id.override_library->reference) == + reinterpret_cast(ob_new->id.override_library->reference)->parent))) + { + do_clear_parenting_override = true; + } + } + /* We remove any operation tagged with `LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE`, * that way the potentially new pointer will be properly kept, when old one is still valid * too (typical case: assigning new ID to some usage, while old one remains used elsewhere @@ -2260,6 +2309,20 @@ static bool lib_override_library_resync(Main *bmain, if (BLI_listbase_is_empty(&op->operations)) { BKE_lib_override_library_property_delete(id_override_new->override_library, op); } + else if (do_clear_parenting_override) { + if (strstr(op->rna_path, "matrix_parent_inverse") || + strstr(op->rna_path, "parent_type") || strstr(op->rna_path, "parent_bone") || + strstr(op->rna_path, "parent_vertices")) + { + CLOG_INFO(&LOG_RESYNC, + 2, + "Deleting liboverride property '%s' from object %s, as its parent pointer " + "matches the reference data hierarchy wise", + id_override_new->name + 2, + op->rna_path); + BKE_lib_override_library_property_delete(id_override_new->override_library, op); + } + } } RNA_struct_override_apply(bmain, @@ -2347,7 +2410,7 @@ static bool lib_override_library_resync(Main *bmain, else if (!BKE_lib_override_library_is_user_edited(id)) { /* If user never edited them, we can delete them. */ do_delete = true; - CLOG_INFO(&LOG, 2, "Old override %s is being deleted", id->name); + CLOG_INFO(&LOG_RESYNC, 2, "Old override %s is being deleted", id->name); } #if 0 else { @@ -2356,15 +2419,16 @@ static bool lib_override_library_resync(Main *bmain, do_delete = false; id_fake_user_set(id); id->flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER; - CLOG_INFO(&LOG, 2, "Old override %s is being kept around as it was user-edited", id->name); + CLOG_INFO(&LOG_RESYNC, 2, "Old override %s is being kept around as it was user-edited", id->name); } #else else { /* Delete them nevertheless, with fat warning, user needs to decide whether they want to * save that version of the file (and accept the loss), or not. */ do_delete = true; - CLOG_WARN( - &LOG, "Old override %s is being deleted even though it was user-edited", id->name); + CLOG_WARN(&LOG_RESYNC, + "Old override %s is being deleted even though it was user-edited", + id->name); user_edited_overrides_deletion_count++; } #endif @@ -2651,8 +2715,11 @@ static void lib_override_resync_tagging_finalize_recurse(Main *bmain, /* This ID (and its whole sub-tree of dependencies) is now considered as processed. If it is * tagged for resync, but its 'calling parent' is not, it is a potential partial resync root. */ - CLOG_INFO( - &LOG, 4, "Potential root for partial resync: %s (%p)", id_root->name, id_root->lib); + CLOG_INFO(&LOG_RESYNC, + 4, + "Potential root for partial resync: %s (%p)", + id_root->name, + id_root->lib); entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_DOIT; } } @@ -2847,7 +2914,7 @@ static void lib_override_resync_tagging_finalize(Main *bmain, { BLI_assert((id_iter->override_library->runtime->tag & LIBOVERRIDE_TAG_RESYNC_ISOLATED_FROM_ROOT) == 0); - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 4, "ID %s (%p) detected as only related to its hierarchy root by 'reversed' " "relationship(s) (e.g. object parenting), tagging it as needing " @@ -2857,7 +2924,7 @@ static void lib_override_resync_tagging_finalize(Main *bmain, } else { CLOG_INFO( - &LOG, + &LOG_RESYNC, 4, "ID %s (%p) detected as 'isolated' from its hierarchy root, tagging it as needing " "resync", @@ -2894,7 +2961,7 @@ static void lib_override_resync_tagging_finalize(Main *bmain, BLI_assert(hierarchy_root->lib == id_iter->lib); if (id_iter != hierarchy_root) { - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 4, "Found root ID '%s' for partial resync root ID '%s'", hierarchy_root->name, @@ -2987,7 +3054,8 @@ static bool lib_override_library_main_resync_on_library_indirect_level( } if (id->tag & LIB_TAG_LIBOVERRIDE_NEED_RESYNC) { - CLOG_INFO(&LOG, 4, "ID %s (%p) was already tagged as needing resync", id->name, id->lib); + CLOG_INFO( + &LOG_RESYNC, 4, "ID %s (%p) was already tagged as needing resync", id->name, id->lib); if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { override_library_runtime_ensure(id->override_library)->tag |= LIBOVERRIDE_TAG_NEED_RESYNC_ORIGINAL; @@ -3009,7 +3077,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( /* Case where this ID pointer was to a linked ID, that now needs to be overridden. */ if (ID_IS_LINKED(id_to) && (id_to->lib != id->lib) && (id_to->tag & LIB_TAG_DOIT) != 0) { - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 3, "ID %s (%p) now tagged as needing resync because they use linked %s (%p) that " "now needs to be overridden", @@ -3039,15 +3107,17 @@ static bool lib_override_library_main_resync_on_library_indirect_level( ID *id_root = static_cast(BLI_ghashIterator_getKey(id_roots_iter)); LinkNodePair *id_resync_roots = static_cast( BLI_ghashIterator_getValue(id_roots_iter)); - CLOG_INFO( - &LOG, 2, "Checking validity of computed TODO data for root '%s'... \n", id_root->name); + CLOG_INFO(&LOG_RESYNC, + 2, + "Checking validity of computed TODO data for root '%s'... \n", + id_root->name); if (id_root->tag & LIB_TAG_LIBOVERRIDE_NEED_RESYNC) { LinkNode *id_resync_root_iter = id_resync_roots->list; ID *id_resync_root = static_cast(id_resync_root_iter->link); if (id_resync_roots->list != id_resync_roots->last_node || id_resync_root != id_root) { - CLOG_ERROR(&LOG, + CLOG_ERROR(&LOG_RESYNC, "Hierarchy root ID is tagged for resync, yet it is not the only partial " "resync roots, this should not happen." "\n\tRoot ID: %s" @@ -3067,7 +3137,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( if (id_resync_root_iter != id_resync_roots->list || id_resync_root_iter != id_resync_roots->last_node) { - CLOG_ERROR(&LOG, + CLOG_ERROR(&LOG_RESYNC, "Resync root ID is same as root ID of the override hierarchy, yet other " "resync root IDs are also defined, this should not happen at this point." "\n\tRoot ID: %s" @@ -3101,7 +3171,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( id_root->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED; } - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 2, "Resyncing all dependencies under root %s (%p), first one being '%s'...", id_root->name, @@ -3117,7 +3187,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( false, false, reports); - CLOG_INFO(&LOG, 2, "\tSuccess: %d", success); + CLOG_INFO(&LOG_RESYNC, 2, "\tSuccess: %d", success); if (success) { reports->count.resynced_lib_overrides++; if (library_indirect_level > 0 && reports->do_resynced_lib_overrides_libraries_list && @@ -3162,7 +3232,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( if (need_resync && is_isolated_from_root) { if (!BKE_lib_override_library_is_user_edited(id)) { CLOG_WARN( - &LOG, + &LOG_RESYNC, "Deleting unused ID override %s from library level %d, still found as needing " "resync, and being isolated from its hierarchy root. This can happen when its " "otherwise unchanged linked reference was moved around in the library file (e.g. if " @@ -3173,7 +3243,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( } else { CLOG_WARN( - &LOG, + &LOG_RESYNC, "Keeping user-edited ID override %s from library level %d still found as " "needing resync, and being isolated from its hierarchy root. This can happen when its " "otherwise unchanged linked reference was moved around in the library file (e.g. if " @@ -3186,7 +3256,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( } else if (need_resync) { if (need_reseync_original) { - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 2, "ID override %s from library level %d still found as needing resync after " "tackling library level %d. Since it was originally tagged as such by " @@ -3203,7 +3273,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( /* If it was only tagged for resync as part of resync process itself, it means it was * originally inside of a resync hierarchy, but not in the matching reference hierarchy * anymore. So it did not actually need to be resynced, simply clear the tag. */ - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 4, "ID override %s from library level %d still found as needing resync after " "tackling library level %d. However, it was not tagged as such by " @@ -3220,7 +3290,7 @@ static bool lib_override_library_main_resync_on_library_indirect_level( } else if (is_isolated_from_root) { CLOG_ERROR( - &LOG, + &LOG_RESYNC, "ID override %s from library level %d still tagged as isolated from its hierarchy root, " "it should have been either properly resynced or removed at that point.", id->name, @@ -3258,7 +3328,7 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data) const int owner_library_indirect_level = ID_IS_LINKED(id_owner) ? id_owner->lib->temp_index : 0; if (owner_library_indirect_level > 100) { - CLOG_ERROR(&LOG, + CLOG_ERROR(&LOG_RESYNC, "Levels of indirect usages of libraries is way too high, there are most likely " "dependency loops, skipping further building loops (involves at least '%s' from " "'%s' and '%s' from '%s')", @@ -3270,7 +3340,7 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data) } if (owner_library_indirect_level > 90) { CLOG_WARN( - &LOG, + &LOG_RESYNC, "Levels of indirect usages of libraries is suspiciously too high, there are most likely " "dependency loops (involves at least '%s' from '%s' and '%s' from '%s')", id_owner->name, @@ -3374,7 +3444,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, level_reprocess_count++; if (level_reprocess_count > 100) { CLOG_WARN( - &LOG, + &LOG_RESYNC, "Need to reprocess resync for library level %d more than %d times, aborting. This is " "either caused by extremely complex liboverride hierarchies, or a bug", library_indirect_level, @@ -3382,7 +3452,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, break; } else { - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 4, "Applying reprocess %d for resyncing at library level %d", level_reprocess_count, @@ -3411,7 +3481,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, LISTBASE_FOREACH (Library *, library, &bmain->libraries) { if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) { - CLOG_INFO(&LOG, + CLOG_INFO(&LOG_RESYNC, 2, "library '%s' contains some linked overrides that required recursive resync, " "consider updating it", @@ -4451,6 +4521,9 @@ void BKE_lib_override_library_id_unused_cleanup(ID *local) BKE_lib_override_library_property_operation_delete(op, opop); } } + if (BLI_listbase_is_empty(&op->operations)) { + BKE_lib_override_library_property_delete(local->override_library, op); + } } } } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index ef3ec26ac788..265fc6cb783b 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -539,6 +539,7 @@ void BKE_mesh_polygon_flip_ex(const int poly_offset, int *corner_verts, int *corner_edges, CustomData *ldata, + int tot_loop, float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip) @@ -577,7 +578,7 @@ void BKE_mesh_polygon_flip_ex(const int poly_offset, if (lnors) { swap_v3_v3(lnors[loopstart], lnors[loopend]); } - CustomData_swap(ldata, loopstart, loopend); + CustomData_swap(ldata, loopstart, loopend, tot_loop); } /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */ if (loopstart == loopend) { @@ -594,11 +595,15 @@ void BKE_mesh_polygon_flip(const int poly_offset, { MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(ldata, CD_MDISPS, totloop); BKE_mesh_polygon_flip_ex( - poly_offset, poly_size, corner_verts, corner_edges, ldata, nullptr, mdisp, true); + poly_offset, poly_size, corner_verts, corner_edges, ldata, totloop, nullptr, mdisp, true); } -void BKE_mesh_polys_flip( - const int *poly_offsets, int *corner_verts, int *corner_edges, CustomData *ldata, int totpoly) +void BKE_mesh_polys_flip(const int *poly_offsets, + int *corner_verts, + int *corner_edges, + CustomData *ldata, + int totloop, + int totpoly) { const blender::OffsetIndices polys(blender::Span(poly_offsets, totpoly + 1)); MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(ldata, CD_MDISPS, totpoly); @@ -608,6 +613,7 @@ void BKE_mesh_polys_flip( corner_verts, corner_edges, ldata, + totloop, nullptr, mdisp, true); diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index e59c45cbbcf7..de60624d520e 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -835,6 +835,13 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, view_layer->mat_override, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(view_layer->id_properties, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); + BKE_view_layer_synced_ensure(scene, view_layer); LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) { BKE_LIB_FOREACHID_PROCESS_IDSUPER( diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 5b4ffa2ef8a1..e2925248329a 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -173,7 +173,7 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_TEXT: { SpaceText *st = (SpaceText *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_USER_ONE); break; } case SPACE_SCRIPT: { diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 694e375a0a30..482585a1d948 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -64,6 +64,7 @@ #include "BKE_anim_data.h" #include "BKE_animsys.h" #include "BKE_asset.h" +#include "BKE_blender_version.h" #include "BKE_collection.h" #include "BKE_global.h" /* for G */ #include "BKE_idprop.h" @@ -413,6 +414,8 @@ void blo_split_main(ListBase *mainlist, Main *main) libmain->curlib = lib; libmain->versionfile = lib->versionfile; libmain->subversionfile = lib->subversionfile; + libmain->has_forward_compatibility_issues = !MAIN_VERSION_FILE_OLDER_OR_EQUAL( + libmain, BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION); BLI_addtail(mainlist, libmain); lib->temp_index = i; lib_main_array[i] = libmain; @@ -432,6 +435,22 @@ void blo_split_main(ListBase *mainlist, Main *main) MEM_freeN(lib_main_array); } +/* Hot-fix file minversion for a specific range of versions. + * + * This is needed for newer LTS releases of 3.6 to be able to properly open files from early + * development versions of 4.0. */ +static void file_global_minversion_hotfix(FileGlobal *fg) +{ + if ((fg->minversion > BLENDER_FILE_VERSION) || + (fg->minversion == BLENDER_FILE_VERSION && fg->minsubversion > BLENDER_FILE_SUBVERSION)) + { + if (fg->minversion < 400 || (fg->minversion == 400 && fg->minsubversion <= 11)) { + fg->minversion = BLENDER_FILE_VERSION; + fg->minsubversion = BLENDER_FILE_SUBVERSION; + } + } +} + static void read_file_version(FileData *fd, Main *main) { BHead *bhead; @@ -440,6 +459,8 @@ static void read_file_version(FileData *fd, Main *main) if (bhead->code == BLO_CODE_GLOB) { FileGlobal *fg = static_cast(read_struct(fd, bhead, "Global")); if (fg) { + file_global_minversion_hotfix(fg); + main->subversionfile = fg->subversion; main->minversionfile = fg->minversion; main->minsubversionfile = fg->minsubversion; @@ -1083,6 +1104,55 @@ static FileData *filedata_new(BlendFileReadReport *reports) return fd; } +/** Check if minversion of the file is older than current Blender, return false if it is not. + * Should only be called after #read_file_dna was successfuly executed. */ +static bool is_minversion_older_than_blender(FileData *fd, ReportList *reports) +{ + BLI_assert(fd->filesdna != nullptr); + for (BHead *bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { + if (bhead->code != BLO_CODE_GLOB) { + continue; + } + + FileGlobal *fg = static_cast(read_struct(fd, bhead, "Global")); + file_global_minversion_hotfix(fg); + + if ((fg->minversion > BLENDER_FILE_VERSION) || + (fg->minversion == BLENDER_FILE_VERSION && fg->minsubversion > BLENDER_FILE_SUBVERSION)) + { + char writer_ver_str[16]; + char min_reader_ver_str[16]; + if (fd->fileversion == fg->minversion) { + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), short(fd->fileversion), fg->subversion); + BKE_blender_version_blendfile_string_from_values( + min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, fg->minsubversion); + } + else { + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), short(fd->fileversion), -1); + BKE_blender_version_blendfile_string_from_values( + min_reader_ver_str, sizeof(min_reader_ver_str), fg->minversion, -1); + } + BKE_reportf(reports, + RPT_ERROR, + TIP_("The file was saved by a newer version, open it with Blender %s or later"), + min_reader_ver_str); + CLOG_WARN(&LOG, + "%s: File saved by a newer version of Blender (%s), Blender %s or later is " + "needed to open it.", + fd->relabase, + writer_ver_str, + min_reader_ver_str); + MEM_freeN(fg); + return true; + } + MEM_freeN(fg); + return false; + } + return false; +} + static FileData *blo_decode_and_check(FileData *fd, ReportList *reports) { decode_blender_header(fd); @@ -1095,6 +1165,10 @@ static FileData *blo_decode_and_check(FileData *fd, ReportList *reports) blo_filedata_free(fd); fd = nullptr; } + if (is_minversion_older_than_blender(fd, reports)) { + blo_filedata_free(fd); + fd = nullptr; + } } else { BKE_reportf( @@ -3433,12 +3507,17 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead) { FileGlobal *fg = static_cast(read_struct(fd, bhead, "Global")); - /* copy to bfd handle */ + /* NOTE: `bfd->main->versionfile` is supposed to have already been set from `fd->fileversion` + * beforehand by calling code. */ bfd->main->subversionfile = fg->subversion; bfd->main->upbgeversionfile = fg->upbgeversion; bfd->main->upbgesubversionfile = fg->upbgesubversion; + bfd->main->has_forward_compatibility_issues = !MAIN_VERSION_FILE_OLDER_OR_EQUAL( + bfd->main, BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION); + bfd->main->minversionfile = fg->minversion; bfd->main->minsubversionfile = fg->minsubversion; + bfd->main->build_commit_timestamp = fg->build_commit_timestamp; STRNCPY(bfd->main->build_hash, fg->build_hash); diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index d2bacbc79961..1680ac197951 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -1767,7 +1767,12 @@ static bool version_seq_fix_broken_sound_strips(Sequence *seq, void * /*user_dat } seq->speed_factor = 1.0f; - seq->startofs = 0.0f; + + /* Broken files do have negative start offset, which should not be present in sound strips. */ + if (seq->startofs < 0) { + seq->startofs = 0.0f; + } + return true; } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert_no_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert_no_geom.glsl index 5dc294e119f7..5316c87fdee5 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert_no_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert_no_geom.glsl @@ -1,14 +1,14 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) -#pragma USE_SSBO_VERTEX_FETCH(TriangleStrip, 10) +#pragma USE_SSBO_VERTEX_FETCH(TriangleList, 24) #define DISCARD_VERTEX \ gl_Position = vec4(0.0); \ finalColor = vec4(0.0); \ return; -void output_line(vec2 offset, vec4 color, vec3 out_world_pos, vec4 out_ndc_pos) +void output_vert(vec2 offset, vec4 color, vec3 out_world_pos, vec4 out_ndc_pos) { finalColor = color; gl_Position = out_ndc_pos; @@ -28,12 +28,12 @@ void main() /* Input prim is LineList. */ /* Index of the input line primitive. */ - int input_line_id = gl_VertexID / 10; + int input_line_id = gl_VertexID / 24; /* Index of output vertex set. Grouped into pairs as outputted by original "output_line" function * in overlay_edit_curve_handle_geom.glsl. */ - int output_prim_id = (gl_VertexID / 2) % 5; - /* ID of vertex within line primitive (0 or 1) for current vertex. */ - int output_prim_vert_id = gl_VertexID % 2; + int output_quad_id = (gl_VertexID / 6) % 4; + /* ID of vertex within generated line segment geometry. */ + int output_prim_vert_id = gl_VertexID % 24; for (int i = 0; i < 2; i++) { in_pos[i] = vertex_fetch_attribute((input_line_id * 2) + i, pos, vec3).xyz; @@ -48,6 +48,7 @@ void main() /* Don't output any edges if we don't show handles */ if (!showCurveHandles && (color_id < 5u)) { + DISCARD_VERTEX return; } @@ -113,51 +114,81 @@ void main() offset.x = 0.0; } - /* Output geometry based on output line ID. */ - switch (output_prim_id) { + /** Each output vertex falls into 10 possible positions to generate 8 output triangles between 5 + * lines. **/ + /* Discard transparent border quads up-front. */ + if (!(is_active_nurb != 0u)) { + if (output_quad_id == 0 || output_quad_id == 3) { + DISCARD_VERTEX + return; + } + } + + switch (output_prim_vert_id) { + /* Top transparent border left (AA). */ case 0: { - /* draw the transparent border (AA). */ - if (is_active_nurb != 0u) { - offset *= 0.75; /* Don't make the active "halo" appear very thick. */ - output_line(offset * 2.0, - vec4(colorActiveSpline.rgb, 0.0), - world_pos[output_prim_vert_id], - ndc_pos[output_prim_vert_id]); - } - else { - DISCARD_VERTEX - } + offset *= 0.75; /* Don't make the active "halo" appear very thick. */ + output_vert(offset * 2.0, vec4(colorActiveSpline.rgb, 0.0), world_pos[0], ndc_pos[0]); break; } - case 1: { - /* draw the outline. */ - output_line( - offset, outer_color, world_pos[output_prim_vert_id], ndc_pos[output_prim_vert_id]); + /* Top transparent border right (AA). */ + case 1: + case 4: { + offset *= 0.75; /* Don't make the active "halo" appear very thick. */ + output_vert(offset * 2.0, vec4(colorActiveSpline.rgb, 0.0), world_pos[1], ndc_pos[1]); break; } - case 2: { - /* draw the core of the line. */ - output_line( - vec2(0.0), inner_color, world_pos[output_prim_vert_id], ndc_pos[output_prim_vert_id]); + /* Top Outline row left point. */ + case 2: + case 3: + case 6: { + output_vert(offset, outer_color, world_pos[0], ndc_pos[0]); break; } - case 3: { - /* draw the outline. */ - output_line( - -offset, outer_color, world_pos[output_prim_vert_id], ndc_pos[output_prim_vert_id]); + /* Top Outline row right point. */ + case 5: + case 7: + case 10: { + output_vert(offset, outer_color, world_pos[1], ndc_pos[1]); break; } - case 4: { - /* draw the transparent border (AA). */ - if (is_active_nurb != 0u) { - output_line(offset * -2.0, - vec4(colorActiveSpline.rgb, 0.0), - world_pos[output_prim_vert_id], - ndc_pos[output_prim_vert_id]); - } + /* Core line left point. */ + case 8: + case 9: + case 12: { + output_vert(vec2(0.0), inner_color, world_pos[0], ndc_pos[0]); break; } - + /* Core line right point. */ + case 11: + case 13: + case 16: { + output_vert(vec2(0.0), inner_color, world_pos[1], ndc_pos[1]); + break; + } + /* Bottom outline left point*/ + case 14: + case 15: + case 18: { + output_vert(-offset, outer_color, world_pos[0], ndc_pos[0]); + break; + } + /* Bottom outline right point*/ + case 17: + case 19: + case 22: { + output_vert(-offset, outer_color, world_pos[1], ndc_pos[1]); + break; + } + /* Bottom transparent border left*/ + case 20: + case 21: { + output_vert(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0), world_pos[0], ndc_pos[0]); + } + /* Bottom transparent border right*/ + case 23: { + output_vert(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0), world_pos[1], ndc_pos[1]); + } default: { DISCARD_VERTEX break; diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 17c2dd1448a2..84688a4de8ef 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -4468,7 +4468,7 @@ void ANIM_channel_draw( /* just skip - drawn as widget now */ offset += ICON_WIDTH; } - else { + else if (!ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { /* A bit of padding when there is no expand widget. */ offset += (short)(0.2f * U.widget_unit); } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 489f2754fc2c..170d6660e3a4 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -422,9 +422,11 @@ void smooth_fcurve_segment(FCurve *fcu, double *kernel) { const int segment_end_index = segment->start_index + segment->length; - const int segment_start_x = fcu->bezt[segment->start_index].vec[1][0]; + const float segment_start_x = fcu->bezt[segment->start_index].vec[1][0]; for (int i = segment->start_index; i < segment_end_index; i++) { - const int sample_index = (int)(fcu->bezt[i].vec[1][0] - segment_start_x) + kernel_size; + /* Using round() instead of (int). The latter would create stepping on x-values that are just + * below a full frame. */ + const int sample_index = round(fcu->bezt[i].vec[1][0] - segment_start_x) + kernel_size; /* Apply the kernel. */ double filter_result = samples[sample_index] * kernel[0]; for (int j = 1; j <= kernel_size; j++) { diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index cc89f54c2fb0..741d24b63656 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -40,6 +40,7 @@ #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_key.h" +#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_nla.h" @@ -1494,6 +1495,11 @@ int insert_keyframe(Main *bmain, return 0; } + if (!BKE_id_is_editable(bmain, id)) { + BKE_reportf(reports, RPT_ERROR, "'%s' on %s is not editable", rna_path, id->name + 2); + return 0; + } + RNA_id_pointer_create(id, &id_ptr); if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { BKE_reportf( diff --git a/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.c b/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.c index 42d2229c93bc..33659347ad3e 100644 --- a/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil_legacy/gpencil_sculpt_paint.c @@ -1427,15 +1427,20 @@ static float gpencil_sculpt_rotation_eval_get(tGP_BrushEditData *gso, } } - if (pt_eval->runtime.idx_orig != 0) { - pt_orig_prev = &gps_orig->points[pt_eval->runtime.idx_orig - 1]; + if (pt_eval->runtime.pt_orig == NULL) { + pt_orig_prev = pt_prev_eval; } else { - if (gps_orig->totpoints > 1) { - pt_orig_prev = &gps_orig->points[pt_eval->runtime.idx_orig + 1]; + if (pt_eval->runtime.idx_orig != 0) { + pt_orig_prev = &gps_orig->points[pt_eval->runtime.idx_orig - 1]; } else { - return 0.0f; + if (gps_orig->totpoints > 1) { + pt_orig_prev = &gps_orig->points[pt_eval->runtime.idx_orig + 1]; + } + else { + return 0.0f; + } } } @@ -1462,7 +1467,6 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; Brush *brush = gso->brush; - char tool = gso->brush->gpencil_sculpt_tool; const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; const bool is_masking = GPENCIL_ANY_SCULPT_MASK(gso->mask); @@ -1541,8 +1545,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, /* To each point individually... */ pt = &gps->points[i]; - if ((i != gps->totpoints - 2) && (pt->runtime.pt_orig == NULL) && - (tool != GPSCULPT_TOOL_GRAB)) { + if ((i != gps->totpoints - 2) && (pt->runtime.pt_orig == NULL)) { continue; } pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h index f6ddb1b3ab6d..8074f6750f94 100644 --- a/source/blender/editors/include/ED_info.h +++ b/source/blender/editors/include/ED_info.h @@ -17,6 +17,10 @@ struct wmWindowManager; /* info_stats.c */ void ED_info_stats_clear(struct wmWindowManager *wm, struct ViewLayer *view_layer); +const char *ED_info_statusbar_string_ex(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer, + const char statusbar_flag); const char *ED_info_statusbar_string(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 52e2c52ee751..d89af9deee50 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -2480,6 +2480,7 @@ void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C); void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C); void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C); void uiTemplateInputStatus(uiLayout *layout, struct bContext *C); +void uiTemplateStatusInfo(uiLayout *layout, struct bContext *C); void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr); bool uiTemplateEventFromKeymapItem(struct uiLayout *layout, diff --git a/source/blender/editors/interface/interface_templates.cc b/source/blender/editors/interface/interface_templates.cc index f5901d03cb3e..3323330834a7 100644 --- a/source/blender/editors/interface/interface_templates.cc +++ b/source/blender/editors/interface/interface_templates.cc @@ -39,6 +39,7 @@ #include "BLT_translation.h" #include "BKE_action.h" +#include "BKE_blender_version.h" #include "BKE_blendfile.h" #include "BKE_cachefile.h" #include "BKE_colorband.h" @@ -70,6 +71,7 @@ #include "DEG_depsgraph_query.h" #include "ED_fileselect.h" +#include "ED_info.h" #include "ED_object.h" #include "ED_render.h" #include "ED_screen.h" @@ -6600,6 +6602,126 @@ void uiTemplateInputStatus(uiLayout *layout, bContext *C) } } +void uiTemplateStatusInfo(uiLayout *layout, bContext *C) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + if (!bmain->has_forward_compatibility_issues) { + const char *status_info_txt = ED_info_statusbar_string(bmain, scene, view_layer); + uiItemL(layout, status_info_txt, ICON_NONE); + return; + } + + /* Blender version part is shown as warning area when there are forward compatibility issues with + * currently loaded .blend file. */ + + const char *status_info_txt = ED_info_statusbar_string_ex( + bmain, scene, view_layer, (U.statusbar_flag & ~STATUSBAR_SHOW_VERSION)); + uiItemL(layout, status_info_txt, ICON_NONE); + + status_info_txt = ED_info_statusbar_string_ex(bmain, scene, view_layer, STATUSBAR_SHOW_VERSION); + + uiBut *but; + + const uiStyle *style = UI_style_get(); + uiLayout *ui_abs = uiLayoutAbsolute(layout, false); + uiBlock *block = uiLayoutGetBlock(ui_abs); + eUIEmbossType previous_emboss = UI_block_emboss_get(block); + + UI_fontstyle_set(&style->widgetlabel); + int width = int( + BLF_width(style->widgetlabel.uifont_id, status_info_txt, strlen(status_info_txt))); + width = max_ii(width, int(10 * UI_SCALE_FAC)); + + UI_block_align_begin(block); + + /* Background for icon. */ + but = uiDefBut(block, + UI_BTYPE_ROUNDBOX, + 0, + "", + 0, + 0, + UI_UNIT_X + (6 * UI_SCALE_FAC), + UI_UNIT_Y, + nullptr, + 0.0f, + 0.0f, + 0, + 0, + ""); + /* UI_BTYPE_ROUNDBOX's bg color is set in but->col. */ + UI_GetThemeColorType4ubv(TH_INFO_WARNING, SPACE_INFO, but->col); + + /* Background for the rest of the message. */ + but = uiDefBut(block, + UI_BTYPE_ROUNDBOX, + 0, + "", + UI_UNIT_X + (6 * UI_SCALE_FAC), + 0, + UI_UNIT_X + width, + UI_UNIT_Y, + nullptr, + 0.0f, + 0.0f, + 0, + 0, + ""); + + /* Use icon background at low opacity to highlight, but still contrasting with area TH_TEXT. */ + UI_GetThemeColorType4ubv(TH_INFO_WARNING, SPACE_INFO, but->col); + but->col[3] = 64; + + UI_block_align_end(block); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + /* The report icon itself. */ + static char compat_error_msg[256]; + char writer_ver_str[12]; + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1); + SNPRINTF(compat_error_msg, + TIP_("File saved by newer Blender\n(%s), expect loss of data"), + writer_ver_str); + but = uiDefIconBut(block, + UI_BTYPE_BUT, + 0, + ICON_ERROR, + int(3 * UI_SCALE_FAC), + 0, + UI_UNIT_X, + UI_UNIT_Y, + nullptr, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + compat_error_msg); + UI_GetThemeColorType4ubv(TH_INFO_WARNING_TEXT, SPACE_INFO, but->col); + but->col[3] = 255; /* This theme color is RBG only, so have to set alpha here. */ + + /* The report message. */ + but = uiDefBut(block, + UI_BTYPE_BUT, + 0, + status_info_txt, + UI_UNIT_X, + 0, + short(width + UI_UNIT_X), + UI_UNIT_Y, + nullptr, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + compat_error_msg); + + UI_block_emboss_set(block, previous_emboss); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index e7032857e283..49b3537a42d8 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -112,7 +112,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object * Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); BKE_object_eval_reset(ob_eval); if (ob->type == OB_MESH) { - Mesh *me_eval = mesh_create_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + Mesh *me_eval = mesh_create_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_DERIVEDMESH); BKE_mesh_eval_delete(me_eval); } else if (ob->type == OB_LATTICE) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 4e21ea78107c..729cb9998923 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4888,6 +4888,8 @@ int ED_screen_animation_play(bContext *C, int sync, int mode) /* Triggers redraw of sequencer preview so that it does not show to fps anymore after stopping * playback. */ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SEQUENCER, scene); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SPREADSHEET, scene); + WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM, scene); } else { BKE_callback_exec_id_depsgraph( diff --git a/source/blender/editors/sculpt_paint/paint_stroke.cc b/source/blender/editors/sculpt_paint/paint_stroke.cc index 8864471e3d9d..4fefec0d9283 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.cc +++ b/source/blender/editors/sculpt_paint/paint_stroke.cc @@ -1606,20 +1606,21 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS redraw = true; } - /* do updates for redraw. if event is in between mouse-move there are more - * coming, so postpone potentially slow redraw updates until all are done */ + /* Don't update the paint cursor in INBETWEEN_MOUSEMOVE events.*/ if (event->type != INBETWEEN_MOUSEMOVE) { wmWindow *window = CTX_wm_window(C); ARegion *region = CTX_wm_region(C); - /* At the very least, invalidate the cursor */ if (region && (p->flags & PAINT_SHOW_BRUSH)) { WM_paint_cursor_tag_redraw(window, region); } + } - if (redraw && stroke->redraw) { - stroke->redraw(C, stroke, false); - } + /* Draw for all events (even in between) otherwise updating the brush + * display is noticeably delayed. + */ + if (redraw && stroke->redraw) { + stroke->redraw(C, stroke, false); } return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/space_file/file_draw.cc b/source/blender/editors/space_file/file_draw.cc index c147b2564be5..e439f67a8e35 100644 --- a/source/blender/editors/space_file/file_draw.cc +++ b/source/blender/editors/space_file/file_draw.cc @@ -25,6 +25,7 @@ #include "BKE_blendfile.h" #include "BKE_context.h" +#include "BKE_report.h" #include "BLT_translation.h" @@ -1168,12 +1169,11 @@ void file_draw_list(const bContext *C, ARegion *region) layout->curr_size = params->thumbnail_size; } -static void file_draw_invalid_library_hint(const bContext *C, - const SpaceFile *sfile, - ARegion *region) +static void file_draw_invalid_asset_library_hint(const bContext *C, + const SpaceFile *sfile, + ARegion *region, + FileAssetSelectParams *asset_params) { - const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); - char library_ui_path[PATH_MAX]; file_path_to_ui_path(asset_params->base_params.dir, library_ui_path, sizeof(library_ui_path)); @@ -1228,21 +1228,112 @@ static void file_draw_invalid_library_hint(const bContext *C, } } -bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region) +static void file_draw_invalid_library_hint(const bContext * /*C*/, + const SpaceFile *sfile, + ARegion *region, + const char *blendfile_path, + ReportList *reports) { - FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); - /* Only for asset browser. */ - if (!ED_fileselect_is_asset_browser(sfile)) { - return false; - } - /* Check if the library exists. */ - if ((asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) || - filelist_is_dir(sfile->files, asset_params->base_params.dir)) + uchar text_col[4]; + UI_GetThemeColor4ubv(TH_TEXT, text_col); + + const View2D *v2d = ®ion->v2d; + const int pad = sfile->layout->tile_border_x; + const int width = BLI_rctf_size_x(&v2d->tot) - (2 * pad); + const int line_height = sfile->layout->textheight; + int sx = v2d->tot.xmin + pad; + /* For some reason no padding needed. */ + int sy = v2d->tot.ymax; + { - return false; + const char *message = TIP_("Unreadable Blender library file:"); + file_draw_string_multiline(sx, sy, message, width, line_height, text_col, nullptr, &sy); + + sy -= line_height; + file_draw_string(sx, sy, blendfile_path, width, line_height, UI_STYLE_TEXT_LEFT, text_col); } - file_draw_invalid_library_hint(C, sfile, region); + /* Separate a bit further. */ + sy -= line_height * 2.2f; + + LISTBASE_FOREACH (Report *, report, &reports->list) { + const short report_type = report->type; + if (report_type <= RPT_INFO) { + continue; + } + + int icon = ICON_INFO; + if (report_type > RPT_WARNING) { + icon = ICON_ERROR; + } + UI_icon_draw(sx, sy - UI_UNIT_Y, icon); + + file_draw_string_multiline(sx + UI_UNIT_X, + sy, + TIP_(report->message), + width - UI_UNIT_X, + line_height, + text_col, + nullptr, + &sy); + sy -= line_height; + } +} + +bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region) +{ + char blendfile_path[FILE_MAX_LIBEXTRA]; + const bool is_asset_browser = ED_fileselect_is_asset_browser(sfile); + const bool is_library_browser = !is_asset_browser && + filelist_islibrary(sfile->files, blendfile_path, nullptr); + + if (is_asset_browser) { + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + + /* Check if the asset library exists. */ + if (!((asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) || + filelist_is_dir(sfile->files, asset_params->base_params.dir))) + { + file_draw_invalid_asset_library_hint(C, sfile, region, asset_params); + return true; + } + } + + /* Check if the blendfile library is valid (has entries). */ + if (is_library_browser) { + if (!filelist_is_ready(sfile->files)) { + return false; + } + + const int numfiles = filelist_files_num_entries(sfile->files); + if (numfiles > 0) { + return false; + } + + /* This could all be part of the file-list loading: + * - When loading fails this could be saved in the file-list, e.g. when + * `BLO_blendhandle_from_file()` returns null in `filelist_readjob_list_lib()`, a + * `FL_HAS_INVALID_LIBRARY` file-list flag could be set. + * - Reports from it could also be stored in `FileList` rather than being ignored + * (`RPT_STORE` must be set!). + * - Then we could just check for `is_library_browser` and the `FL_HAS_INVALID_LIBRARY` flag + * here, and draw the hint with the reports in the file-list. (We would not draw a hint for + * recursive loading, even if the file-list has the "has invalid library" flag set, which + * seems like the wanted behavior.) + * - The call to BKE_blendfile_is_readable() would not be needed then. + */ + if (!sfile->runtime->is_blendfile_status_set) { + BKE_reports_clear(&sfile->runtime->is_blendfile_readable_reports); + sfile->runtime->is_blendfile_readable = BKE_blendfile_is_readable( + blendfile_path, &sfile->runtime->is_blendfile_readable_reports); + sfile->runtime->is_blendfile_status_set = true; + } + if (!sfile->runtime->is_blendfile_readable) { + file_draw_invalid_library_hint( + C, sfile, region, blendfile_path, &sfile->runtime->is_blendfile_readable_reports); + return true; + } + } - return true; + return false; } diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index e11244d0214a..12e2b8ab0e80 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -8,6 +8,7 @@ #pragma once #include "DNA_space_types.h" +#include "DNA_windowmanager_types.h" #ifdef __cplusplus extern "C" { @@ -179,6 +180,12 @@ typedef struct SpaceFile_Runtime { * Use file_on_reload_callback_register() to register a callback. */ onReloadFn on_reload; onReloadFnData on_reload_custom_data; + + /* Indicates, if the current filepath is a blendfile library one, if its status has been checked, + * and if it is readable. */ + bool is_blendfile_status_set; + bool is_blendfile_readable; + ReportList is_blendfile_readable_reports; } SpaceFile_Runtime; /** diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc index 1013af8ac290..41444cb5e26f 100644 --- a/source/blender/editors/space_file/filelist.cc +++ b/source/blender/editors/space_file/filelist.cc @@ -1933,6 +1933,11 @@ BlendHandle *filelist_lib(FileList *filelist) return filelist->libfiledata; } +int filelist_files_num_entries(FileList *filelist) +{ + return filelist->filelist.entries_num; +} + static const char *fileentry_uiname(const char *root, FileListInternEntry *entry, char *buff) { if (entry->asset) { diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 6cc89967d79a..b7a951d8c07a 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -205,6 +205,10 @@ struct BlendHandle *filelist_lib(struct FileList *filelist); bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group); void filelist_freelib(struct FileList *filelist); +/** Return the total raw number of entries listed in the given `filelist`, whether they are + * filtered out or not. */ +int filelist_files_num_entries(struct FileList *filelist); + void filelist_readjob_start(struct FileList *filelist, int space_notifier, const struct bContext *C); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 29f6adbfbb55..7bb280882924 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -19,6 +19,7 @@ #include "BKE_global.h" #include "BKE_lib_remap.h" #include "BKE_main.h" +#include "BKE_report.h" #include "BKE_screen.h" #include "RNA_access.h" @@ -125,6 +126,9 @@ static void file_free(SpaceLink *sl) MEM_SAFE_FREE(sfile->params); MEM_SAFE_FREE(sfile->asset_params); + if (sfile->runtime != NULL) { + BKE_reports_clear(&sfile->runtime->is_blendfile_readable_reports); + } MEM_SAFE_FREE(sfile->runtime); MEM_SAFE_FREE(sfile->layout); @@ -141,6 +145,7 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area) if (sfile->runtime == NULL) { sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__); + BKE_reports_init(&sfile->runtime->is_blendfile_readable_reports, RPT_STORE); } /* Validate the params right after file read. */ fileselect_refresh_params(sfile); @@ -203,6 +208,10 @@ static void file_refresh(const bContext *C, ScrArea *area) fileselect_refresh_params(sfile); folder_history_list_ensure_for_active_browse_mode(sfile); + if (sfile->runtime != NULL) { + sfile->runtime->is_blendfile_status_set = false; + } + if (sfile->files && (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES) && filelist_needs_reset_on_main_changes(sfile->files)) { diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index ae1e9600e375..5bfecc26417b 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -677,8 +677,8 @@ static void image_main_region_draw(const bContext *C, ARegion *region) BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y); UI_view2d_view_to_region(®ion->v2d, 0.0f, 0.0f, &x, &y); ED_region_image_metadata_draw(x, y, ibuf, &frame, zoomx, zoomy); - ED_space_image_release_buffer(sima, ibuf, lock); } + ED_space_image_release_buffer(sima, ibuf, lock); } /* sample line */ diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index 74b2437047e4..47145fa35c24 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -599,10 +599,10 @@ static void get_stats_string(char *info, info + *ofs, len - *ofs, TIP_(" | Objects:%s/%s"), stats_fmt->totobjsel, stats_fmt->totobj); } -static const char *info_statusbar_string(Main *bmain, - Scene *scene, - ViewLayer *view_layer, - char statusbar_flag) +const char *ED_info_statusbar_string_ex(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + const char statusbar_flag) { char formatted_mem[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE]; size_t ofs = 0; @@ -686,7 +686,7 @@ static const char *info_statusbar_string(Main *bmain, const char *ED_info_statusbar_string(Main *bmain, Scene *scene, ViewLayer *view_layer) { - return info_statusbar_string(bmain, scene, view_layer, U.statusbar_flag); + return ED_info_statusbar_string_ex(bmain, scene, view_layer, U.statusbar_flag); } const char *ED_info_statistics_string(Main *bmain, Scene *scene, ViewLayer *view_layer) @@ -696,7 +696,7 @@ const char *ED_info_statistics_string(Main *bmain, Scene *scene, ViewLayer *view STATUSBAR_SHOW_VERSION | STATUSBAR_SHOW_SCENE_DURATION; - return info_statusbar_string(bmain, scene, view_layer, statistics_status_bar_flag); + return ED_info_statusbar_string_ex(bmain, scene, view_layer, statistics_status_bar_flag); } static void stats_row(int col1, diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index a72af23bfb78..914889326306 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -892,6 +892,9 @@ static void ui_node_draw_input( split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX); break; } + case SOCK_CUSTOM: + input.typeinfo->draw(&C, sub, &inputptr, &nodeptr, input.name); + break; default: add_dummy_decorator = true; } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 74419afd416c..865644fd9be2 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1850,9 +1850,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) if ((seq->flag & SELECT) && (seq->type == SEQ_TYPE_IMAGE) && (seq->len > 1)) { Sequence *seq_next; - /* Remove seq so overlap tests don't conflict, - * see seq_free_sequence below for the real freeing. */ - BLI_remlink(seqbase, seq); /* TODO: remove f-curve and assign to split image strips. * The old animation system would remove the user of `seq->ipo`. */ diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 921ade101c7e..f9e80725cfc3 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -98,6 +98,7 @@ typedef struct { float ob_dims_orig[3]; float ob_scale_orig[3]; float ob_dims[3]; + float active_vertex_weight; /* Floats only (treated as an array). */ TransformMedian ve_median, median; bool tag_for_update; @@ -1310,6 +1311,18 @@ static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt)) return false; } +static void update_active_vertex_weight(struct bContext *C, void *arg1, void *UNUSED(arg2)) +{ + View3D *v3d = CTX_wm_view3d(C); + TransformProperties *tfp = v3d_transform_props_ensure(v3d); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = BKE_view_layer_active_object_get(view_layer); + MDeformVert *dv = ED_mesh_active_dvert_get_only(ob); + const int vertex_group_index = POINTER_AS_INT(arg1); + MDeformWeight *dw = BKE_defvert_find_index(dv, vertex_group_index); + dw->weight = tfp->active_vertex_weight; +} + static void view3d_panel_vgroup(const bContext *C, Panel *panel) { uiBlock *block = uiLayoutAbsoluteBlock(panel->layout); @@ -1317,6 +1330,8 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel) 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); + View3D *v3d = CTX_wm_view3d(C); + TransformProperties *tfp = v3d_transform_props_ensure(v3d); MDeformVert *dv; @@ -1390,6 +1405,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel) /* The weight group value */ /* To be reworked still */ + tfp->active_vertex_weight = dw->weight; but = uiDefButF(block, UI_BTYPE_NUM, B_VGRP_PNL_EDIT_SINGLE + i, @@ -1398,7 +1414,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel) yco, (x = UI_UNIT_X * 4), UI_UNIT_Y, - &dw->weight, + &tfp->active_vertex_weight, 0.0, 1.0, 0, @@ -1407,6 +1423,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel) UI_but_number_step_size_set(but, 1); UI_but_number_precision_set(but, 3); UI_but_drawflag_enable(but, UI_BUT_TEXT_LEFT); + UI_but_func_set(but, update_active_vertex_weight, POINTER_FROM_INT(i), NULL); if (locked) { lock_count++; } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 73938f1d9599..f2bb4faff402 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -636,7 +636,9 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) return false; } if (value == TFM_MODAL_RESIZE && t->mode == TFM_RESIZE) { - return false; + /* The tracking transform in MovieClip has an alternate resize that only affects the + * tracker size and not the search area. */ + return t->data_type == &TransConvertType_Tracking; } if (value == TFM_MODAL_VERT_EDGE_SLIDE && (t->data_type != &TransConvertType_Mesh || diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c index 1d9ec136ae16..5701a88eda3d 100644 --- a/source/blender/editors/transform/transform_convert_tracking.c +++ b/source/blender/editors/transform/transform_convert_tracking.c @@ -475,7 +475,7 @@ static void flushTransTracking(TransInfo *t) if (t->flag & T_ALT_TRANSFORM) { if (t->mode == TFM_RESIZE) { - if (tdt->area != TRACK_AREA_PAT) { + if (tdt->area != TRACK_AREA_PAT && !(t->state == TRANS_CANCEL)) { continue; } } diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 89cf5f799ea3..9c1f77edeb44 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -2778,8 +2778,19 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; transpose_m4_m4(tobmat, obmat); - for (int i = sctx->runtime.clip_plane_len; i--;) { - mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]); + float(*clip_planes)[4] = sctx->runtime.clip_plane; + int clip_plane_len = sctx->runtime.clip_plane_len; + + if (sctx->runtime.has_occlusion_plane && XRAY_FLAG_ENABLED(sctx->runtime.v3d)) { + /* #XRAY_ENABLED can return false even with the XRAY flag enabled, this happens because the + * alpha is 1.0 in this case. But even with the alpha being 1.0, the edit mesh is still not + * occluded. */ + clip_planes++; + clip_plane_len--; + } + + for (int i = clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, clip_planes[i]); } if (sod->bvhtree[0] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) { @@ -2790,7 +2801,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, sctx->runtime.win_size, sctx->runtime.mval, clip_planes_local, - sctx->runtime.clip_plane_len, + clip_plane_len, &nearest, cb_snap_vert, &nearest2d); @@ -2806,7 +2817,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, sctx->runtime.win_size, sctx->runtime.mval, clip_planes_local, - sctx->runtime.clip_plane_len, + clip_plane_len, &nearest, cb_snap_edge, &nearest2d); diff --git a/source/blender/geometry/intern/subdivide_curves.cc b/source/blender/geometry/intern/subdivide_curves.cc index 54aaf1cae3e1..360215cef60b 100644 --- a/source/blender/geometry/intern/subdivide_curves.cc +++ b/source/blender/geometry/intern/subdivide_curves.cc @@ -300,6 +300,10 @@ bke::CurvesGeometry subdivide_curves( const VArray &cuts, const bke::AnonymousAttributePropagationInfo &propagation_info) { + if (src_curves.points_num() == 0) { + return src_curves; + } + const OffsetIndices src_points_by_curve = src_curves.points_by_curve(); /* Cyclic is accessed a lot, it's probably worth it to make sure it's a span. */ const VArraySpan cyclic{src_curves.cyclic()}; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index c4b6d3ca213d..3e65a4ad9fa6 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1723,7 +1723,8 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */ prop = RNA_def_enum( - srna, "flag", override_library_property_flag_items, 0, "Flags", "Optional flags (NOT USED)"); + srna, "flag", override_library_property_flag_items, 0, "Flags", "Status flags"); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */ prop = RNA_def_string(srna, diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 218679f8bdd6..3991584cd0c4 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -986,7 +986,54 @@ bool RNA_struct_override_store(Main *bmain, return changed; } -static void rna_porperty_override_collection_subitem_lookup( +static void rna_property_override_collection_subitem_name_index_lookup( + PointerRNA *ptr, + PropertyRNA *prop, + const char *item_name, + const int item_index, + PointerRNA *r_ptr_item_name, + PointerRNA *r_ptr_item_index) +{ + RNA_POINTER_INVALIDATE(r_ptr_item_name); + RNA_POINTER_INVALIDATE(r_ptr_item_index); + + /* First, lookup by index, but only validate if name also matches (or if there is no given name). + */ + if (item_index != -1) { + if (RNA_property_collection_lookup_int(ptr, prop, item_index, r_ptr_item_index)) { + if (item_name != NULL) { + PropertyRNA *nameprop = r_ptr_item_index->type->nameproperty; + char name[256], *nameptr; + int keylen = (int)strlen(item_name); + int namelen; + + nameptr = RNA_property_string_get_alloc( + r_ptr_item_index, nameprop, name, sizeof(name), &namelen); + + if (keylen == namelen && STREQ(nameptr, item_name)) { + /* Index and name both match. */ + *r_ptr_item_name = *r_ptr_item_index; + return; + } + } + } + } + + if (item_name == NULL) { + return; + } + + /* Then, lookup by name only. */ + if (RNA_property_collection_lookup_string(ptr, prop, item_name, r_ptr_item_name)) { + RNA_POINTER_INVALIDATE(r_ptr_item_index); + return; + } + + /* If name lookup failed, `r_ptr_item_name` is invalidated, so if index lookup was sucessful it + * will be the only valid return value. */ +} + +static void rna_property_override_collection_subitem_lookup( PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage, @@ -1016,68 +1063,122 @@ static void rna_porperty_override_collection_subitem_lookup( if (prop_storage != NULL) { RNA_POINTER_INVALIDATE(private_ptr_item_storage); } - if (opop->subitem_local_name != NULL) { - RNA_property_collection_lookup_string( - ptr_src, prop_src, opop->subitem_local_name, private_ptr_item_src); - if (opop->subitem_reference_name != NULL && - RNA_property_collection_lookup_string( - ptr_dst, prop_dst, opop->subitem_reference_name, private_ptr_item_dst)) - { - /* This is rather fragile, but the fact that local override IDs may have a different name - * than their linked reference makes it necessary. - * Basically, here we are considering that if we cannot find the original linked ID in - * the local override we are (re-)applying the operations, then it may be because some of - * those operations have already been applied, and we may already have the local ID - * pointer we want to set. - * This happens e.g. during re-sync of an override, since we have already remapped all ID - * pointers to their expected values. - * In that case we simply try to get the property from the local expected name. */ + + PointerRNA ptr_item_dst_name, ptr_item_dst_index; + PointerRNA ptr_item_src_name, ptr_item_src_index; + PointerRNA ptr_item_storage_name, ptr_item_storage_index; + rna_property_override_collection_subitem_name_index_lookup(ptr_src, + prop_src, + opop->subitem_local_name, + opop->subitem_local_index, + &ptr_item_src_name, + &ptr_item_src_index); + rna_property_override_collection_subitem_name_index_lookup(ptr_dst, + prop_dst, + opop->subitem_reference_name, + opop->subitem_reference_index, + &ptr_item_dst_name, + &ptr_item_dst_index); + /* This is rather fragile, but the fact that local override IDs may have a different name + * than their linked reference makes it necessary. + * Basically, here we are considering that if we cannot find the original linked ID in + * the local override we are (re-)applying the operations, then it may be because some of + * those operations have already been applied, and we may already have the local ID + * pointer we want to set. + * This happens e.g. during re-sync of an override, since we have already remapped all ID + * pointers to their expected values. + * In that case we simply try to get the property from the local expected name. */ + if (opop->subitem_reference_name != NULL && opop->subitem_local_name != NULL && + ptr_item_dst_name.type == NULL) + { + rna_property_override_collection_subitem_name_index_lookup( + ptr_dst, + prop_dst, + opop->subitem_local_name, + opop->subitem_reference_index != -1 ? opop->subitem_reference_index : + opop->subitem_local_index, + &ptr_item_dst_name, + &ptr_item_dst_index); + } + + /* For historical compatibility reasons, we fallback to reference if no local item info is given, + * and vice-versa. */ + if (opop->subitem_reference_name == NULL && opop->subitem_local_name != NULL) { + rna_property_override_collection_subitem_name_index_lookup( + ptr_dst, + prop_dst, + opop->subitem_local_name, + opop->subitem_reference_index != -1 ? opop->subitem_reference_index : + opop->subitem_local_index, + &ptr_item_dst_name, + &ptr_item_dst_index); + } + else if (opop->subitem_reference_name != NULL && opop->subitem_local_name == NULL) { + rna_property_override_collection_subitem_name_index_lookup(ptr_src, + prop_src, + opop->subitem_reference_name, + opop->subitem_local_index != -1 ? + opop->subitem_local_index : + opop->subitem_reference_index, + &ptr_item_src_name, + &ptr_item_src_index); + } + if (opop->subitem_reference_index == -1 && opop->subitem_local_index != -1) { + rna_property_override_collection_subitem_name_index_lookup(ptr_dst, + prop_dst, + NULL, + opop->subitem_local_index, + &ptr_item_dst_name, + &ptr_item_dst_index); + } + else if (opop->subitem_reference_index != -1 && opop->subitem_local_index == -1) { + rna_property_override_collection_subitem_name_index_lookup(ptr_src, + prop_src, + NULL, + opop->subitem_reference_index, + &ptr_item_src_name, + &ptr_item_src_index); + } + + /* For storage, simply lookup by name first, and fallback to indices. */ + if (prop_storage != NULL) { + rna_property_override_collection_subitem_name_index_lookup(ptr_storage, + prop_storage, + opop->subitem_local_name, + opop->subitem_local_index, + &ptr_item_storage_name, + &ptr_item_storage_index); + if (ptr_item_storage_name.data == NULL) { + rna_property_override_collection_subitem_name_index_lookup(ptr_storage, + prop_storage, + opop->subitem_reference_name, + opop->subitem_reference_index, + &ptr_item_storage_name, + &ptr_item_storage_index); } - else { - RNA_property_collection_lookup_string( - ptr_dst, prop_dst, opop->subitem_local_name, private_ptr_item_dst); + if (ptr_item_storage_name.data == NULL && ptr_item_storage_index.data == NULL) { + rna_property_override_collection_subitem_name_index_lookup(ptr_storage, + prop_storage, + NULL, + opop->subitem_local_index, + &ptr_item_storage_name, + &ptr_item_storage_index); } } - else if (opop->subitem_reference_name != NULL) { - RNA_property_collection_lookup_string( - ptr_src, prop_src, opop->subitem_reference_name, private_ptr_item_src); - RNA_property_collection_lookup_string( - ptr_dst, prop_dst, opop->subitem_reference_name, private_ptr_item_dst); - } - else if (opop->subitem_local_index != -1) { - RNA_property_collection_lookup_int( - ptr_src, prop_src, opop->subitem_local_index, private_ptr_item_src); - if (opop->subitem_reference_index != -1) { - RNA_property_collection_lookup_int( - ptr_dst, prop_dst, opop->subitem_reference_index, private_ptr_item_dst); - } - else { - RNA_property_collection_lookup_int( - ptr_dst, prop_dst, opop->subitem_local_index, private_ptr_item_dst); + + /* Final selection. both matches have to be based on names, or indices, but not a mix of both. */ + if (ptr_item_src_name.type != NULL && ptr_item_dst_name.type != NULL) { + *private_ptr_item_src = ptr_item_src_name; + *private_ptr_item_dst = ptr_item_dst_name; + if (prop_storage != NULL) { + *private_ptr_item_storage = ptr_item_storage_name; } } - else if (opop->subitem_reference_index != -1) { - RNA_property_collection_lookup_int( - ptr_src, prop_src, opop->subitem_reference_index, private_ptr_item_src); - RNA_property_collection_lookup_int( - ptr_dst, prop_dst, opop->subitem_reference_index, private_ptr_item_dst); - } - if (prop_storage != NULL) { - if (opop->subitem_local_name != NULL) { - RNA_property_collection_lookup_string( - ptr_storage, prop_storage, opop->subitem_local_name, private_ptr_item_storage); - } - else if (opop->subitem_reference_name != NULL) { - RNA_property_collection_lookup_string( - ptr_storage, prop_storage, opop->subitem_reference_name, private_ptr_item_storage); - } - else if (opop->subitem_local_index != -1) { - RNA_property_collection_lookup_int( - ptr_storage, prop_storage, opop->subitem_local_index, private_ptr_item_storage); - } - else if (opop->subitem_reference_index != -1) { - RNA_property_collection_lookup_int( - ptr_storage, prop_storage, opop->subitem_reference_index, private_ptr_item_storage); + else if (ptr_item_src_index.type != NULL && ptr_item_dst_index.type != NULL) { + *private_ptr_item_src = ptr_item_src_index; + *private_ptr_item_dst = ptr_item_dst_index; + if (prop_storage != NULL) { + *private_ptr_item_storage = ptr_item_storage_index; } } *r_ptr_item_dst = private_ptr_item_dst; @@ -1160,7 +1261,21 @@ static void rna_property_override_check_resync(Main *bmain, if (ID_IS_LINKED(id_owner_src)) { id_owner_src->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED; } - CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", id_owner_dst->name); + CLOG_INFO(&LOG, + 3, + "Local override %s detected as needing resync due to mismatch in its used IDs", + id_owner_dst->name); + } + if ((id_owner_src->override_library->reference->tag & LIB_TAG_LIBOVERRIDE_NEED_RESYNC) != 0) { + id_owner_dst->tag |= LIB_TAG_LIBOVERRIDE_NEED_RESYNC; + if (ID_IS_LINKED(id_owner_src)) { + id_owner_src->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED; + } + CLOG_INFO(&LOG, + 3, + "Local override %s detected as needing resync as its liboverride reference is " + "already tagged for resync", + id_owner_dst->name); } } @@ -1196,7 +1311,7 @@ static void rna_property_override_apply_ex(Main *bmain, * Note that here, src is the local saved ID, and dst is a copy of the linked ID (since we use * local ID as storage to apply local changes on top of a clean copy of the linked data). */ PointerRNA private_ptr_item_dst, private_ptr_item_src, private_ptr_item_storage; - rna_porperty_override_collection_subitem_lookup(ptr_dst, + rna_property_override_collection_subitem_lookup(ptr_dst, ptr_src, ptr_storage, prop_dst, @@ -1232,6 +1347,79 @@ static void rna_property_override_apply_ex(Main *bmain, } } +/* Workaround for broken overrides, non-matching ID pointers override operations that replace a + * non-NULL value are then assumed as 'mistakes', and ignored (not applied). */ +static bool override_apply_property_check_skip(Main *bmain, + PointerRNA *ptr_dst, + PointerRNA *ptr_src, + PointerRNA *data_dst, + PointerRNA *data_src, + PropertyRNA *prop_dst, + PropertyRNA *prop_src, + IDOverrideLibraryProperty *op, + const eRNAOverrideApplyFlag flag) +{ + UNUSED_VARS_NDEBUG(bmain, ptr_src, data_src, prop_src); + + if ((flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) == 0) { + return false; + } + + if (!RNA_struct_is_ID(RNA_property_pointer_type(data_dst, prop_dst))) { + BLI_assert(!RNA_struct_is_ID(RNA_property_pointer_type(data_src, prop_src))); + return false; + } + + /* IDProperties case. */ + if (prop_dst->magic != RNA_MAGIC) { + CLOG_INFO(&LOG, + 2, + "%s: Ignoring local override on ID pointer custom property '%s', as requested by " + "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag", + ptr_dst->owner_id->name, + op->rna_path); + return true; + } + + switch (op->rna_prop_type) { + case PROP_POINTER: { + if ((((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag & + LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) + { + BLI_assert(ptr_src->owner_id == + rna_property_override_property_real_id_owner(bmain, data_src, NULL, NULL)); + BLI_assert(ptr_dst->owner_id == + rna_property_override_property_real_id_owner(bmain, data_dst, NULL, NULL)); + + CLOG_INFO(&LOG, + 2, + "%s: Ignoring local override on ID pointer property '%s', as requested by " + "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag", + ptr_dst->owner_id->name, + op->rna_path); + return true; + } + break; + } + case PROP_COLLECTION: { + /* For collections of ID pointers just completely skip the override ops here... A tad brutal, + * but this is a backup 'fix the mess' tool, and in practice this should never be an issue. + * Can always be refined later if needed. */ + CLOG_INFO(&LOG, + 2, + "%s: Ignoring all local override on ID pointer collection property '%s', as " + "requested by RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag", + ptr_dst->owner_id->name, + op->rna_path); + return true; + } + default: + break; + } + + return false; +} + void RNA_struct_override_apply(Main *bmain, PointerRNA *ptr_dst, PointerRNA *ptr_src, @@ -1321,8 +1509,8 @@ void RNA_struct_override_apply(Main *bmain, PointerRNA *ptr_item_dst, *ptr_item_src; PointerRNA private_ptr_item_dst, private_ptr_item_src; - rna_porperty_override_collection_subitem_lookup(ptr_dst, - ptr_src, + rna_property_override_collection_subitem_lookup(&data_dst, + &data_src, NULL, prop_dst, prop_src, @@ -1343,38 +1531,10 @@ void RNA_struct_override_apply(Main *bmain, } } - /* Workaround for older broken overrides, we then assume that non-matching ID pointers - * override operations that replace a non-NULL value are 'mistakes', and ignore (do not - * apply) them. */ - if ((flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) != 0 && - op->rna_prop_type == PROP_POINTER && - (((IDOverrideLibraryPropertyOperation *)op->operations.first)->flag & - LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) + if (override_apply_property_check_skip( + bmain, ptr_dst, ptr_src, &data_dst, &data_src, prop_dst, prop_src, op, flag)) { - BLI_assert(ptr_src->owner_id == - rna_property_override_property_real_id_owner(bmain, &data_src, NULL, NULL)); - BLI_assert(ptr_dst->owner_id == - rna_property_override_property_real_id_owner(bmain, &data_dst, NULL, NULL)); - - PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst); - if (prop_ptr_dst.type != NULL && RNA_struct_is_ID(prop_ptr_dst.type)) { -#ifndef NDEBUG - PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src); - BLI_assert(prop_ptr_src.type == NULL || RNA_struct_is_ID(prop_ptr_src.type)); -#endif - ID *id_dst = rna_property_override_property_real_id_owner( - bmain, &prop_ptr_dst, NULL, NULL); - - if (id_dst != NULL) { - CLOG_INFO(&LOG, - 4, - "%s: Ignoring local override on ID pointer property '%s', as requested by " - "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag", - ptr_dst->owner_id->name, - op->rna_path); - continue; - } - } + continue; } rna_property_override_apply_ex(bmain, diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index de8a0ba2f058..42600d0bde02 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -175,6 +175,7 @@ static void rna_Mesh_flip_normals(Mesh *mesh) BKE_mesh_corner_verts_for_write(mesh), BKE_mesh_corner_edges_for_write(mesh), &mesh->ldata, + mesh->totloop, mesh->totpoly); BKE_mesh_tessface_clear(mesh); BKE_mesh_runtime_clear_geometry(mesh); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 6ec3e72e5746..5586369a0649 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -707,6 +707,41 @@ static void rna_Object_parent_type_set(PointerRNA *ptr, int value) ED_object_parent(ob, ob->parent, value, ob->parsubstr); } +static bool rna_Object_parent_type_override_apply(Main *bmain, + PointerRNA *ptr_dst, + PointerRNA *ptr_src, + PointerRNA *ptr_storage, + PropertyRNA *prop_dst, + PropertyRNA *prop_src, + PropertyRNA *UNUSED(prop_storage), + const int len_dst, + const int len_src, + const int len_storage, + PointerRNA *UNUSED(ptr_item_dst), + PointerRNA *UNUSED(ptr_item_src), + PointerRNA *UNUSED(ptr_item_storage), + IDOverrideLibraryPropertyOperation *opop) +{ + BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0); + BLI_assert(opop->operation == LIBOVERRIDE_OP_REPLACE && + "Unsupported RNA override operation on object parent pointer"); + UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop); + + /* We need a special handling here because setting parent resets invert parent matrix, + * which is evil in our case. */ + Object *ob = (Object *)(ptr_dst->data); + const int parent_type_dst = RNA_property_int_get(ptr_dst, prop_dst); + const int parent_type_src = RNA_property_int_get(ptr_src, prop_src); + + if (parent_type_dst == parent_type_src) { + return false; + } + + ob->partype = parent_type_src; + RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst); + return true; +} + static const EnumPropertyItem *rna_Object_parent_type_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), @@ -786,6 +821,43 @@ static void rna_Object_parent_bone_set(PointerRNA *ptr, const char *value) ED_object_parent(ob, ob->parent, ob->partype, value); } +static bool rna_Object_parent_bone_override_apply(Main *bmain, + PointerRNA *ptr_dst, + PointerRNA *ptr_src, + PointerRNA *ptr_storage, + PropertyRNA *prop_dst, + PropertyRNA *prop_src, + PropertyRNA *UNUSED(prop_storage), + const int len_dst, + const int len_src, + const int len_storage, + PointerRNA *UNUSED(ptr_item_dst), + PointerRNA *UNUSED(ptr_item_src), + PointerRNA *UNUSED(ptr_item_storage), + IDOverrideLibraryPropertyOperation *opop) +{ + BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0); + BLI_assert(opop->operation == LIBOVERRIDE_OP_REPLACE && + "Unsupported RNA override operation on object parent bone property"); + UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop); + + /* We need a special handling here because setting parent resets invert parent matrix, + * which is evil in our case. */ + Object *ob = (Object *)(ptr_dst->data); + char parent_bone_dst[MAX_ID_NAME - 2]; + RNA_property_string_get(ptr_dst, prop_dst, parent_bone_dst); + char parent_bone_src[MAX_ID_NAME - 2]; + RNA_property_string_get(ptr_src, prop_src, parent_bone_src); + + if (STREQ(parent_bone_src, parent_bone_dst)) { + return false; + } + + STRNCPY(ob->parsubstr, parent_bone_src); + RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst); + return true; +} + static const EnumPropertyItem *rna_Object_instance_type_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), @@ -4096,6 +4168,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_enum_items(prop, parent_type_items); RNA_def_property_enum_funcs( prop, NULL, "rna_Object_parent_type_set", "rna_Object_parent_type_itemf"); + RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_parent_type_override_apply"); RNA_def_property_ui_text(prop, "Parent Type", "Type of parent relation"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update"); @@ -4109,6 +4182,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "parent_bone", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "parsubstr"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Object_parent_bone_set"); + RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_parent_bone_override_apply"); RNA_def_property_ui_text( prop, "Parent Bone", "Name of parent bone in case of a bone parenting relation"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update"); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 6e7de7115c27..906527c22501 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1578,6 +1578,18 @@ static int rna_property_override_diff_propptr(Main *bmain, flags, r_report_flag); + /* Regardless of whether the data from both pointers matches or not, a potentially existing + * operation on current extended rna path should be removed. This is done by tagging said + * operation as unused, while clearing the property tag (see also + * #RNA_struct_override_matches handling of #LIBOVERRIDE_PROP_OP_TAG_UNUSED). Note that a + * property with no operations will also be cleared by + * #BKE_lib_override_library_id_unused_cleanup. */ + IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, + extended_rna_path); + if (op != NULL) { + op->tag &= ~LIBOVERRIDE_PROP_OP_TAG_UNUSED; + } + if (!ELEM(extended_rna_path, extended_rna_path_buffer, rna_path)) { MEM_freeN(extended_rna_path); } diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index a9ea378194b5..44d25ff6f203 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -1769,6 +1769,9 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "template_input_status", "uiTemplateInputStatus"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); + func = RNA_def_function(srna, "template_status_info", "uiTemplateStatusInfo"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "ntree", "NodeTree", "", ""); diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index 3782f8701582..22a88adf651f 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -209,6 +209,7 @@ static bool polygons_check_flip(blender::MutableSpan corner_verts, corner_verts.data(), corner_edges.data(), ldata, + corner_edges.size(), reinterpret_cast(nos), mdisp, true); diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 2dbf2fd5a804..7939a6790d79 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -62,6 +62,7 @@ #include "BKE_appdir.h" #include "BKE_autoexec.h" #include "BKE_blender.h" +#include "BKE_blender_version.h" #include "BKE_blendfile.h" #include "BKE_callbacks.h" #include "BKE_context.h" @@ -676,7 +677,9 @@ struct wmFileReadPost_Params { * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ -static void wm_file_read_post(bContext *C, const struct wmFileReadPost_Params *params) +static void wm_file_read_post(bContext *C, + const char *filepath, + const struct wmFileReadPost_Params *params) { wmWindowManager *wm = CTX_wm_manager(C); @@ -761,6 +764,13 @@ 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); + + /* Load-post must run before evaluating drivers & depsgraph, see: #109720. + * On failure, the caller handles #BKE_CB_EVT_LOAD_POST_FAIL. */ + if (params->success) { + BKE_callback_exec_string(bmain, BKE_CB_EVT_LOAD_POST, filepath); + } + if (is_factory_startup) { BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST); } @@ -835,8 +845,11 @@ static void wm_read_callback_post_wrapper(bContext *C, const char *filepath, con wmWindow *win = static_cast(wm->windows.first); CTX_wm_window_set(C, win); } - BKE_callback_exec_string( - bmain, success ? BKE_CB_EVT_LOAD_POST : BKE_CB_EVT_LOAD_POST_FAIL, filepath); + + /* On success: #BKE_CB_EVT_LOAD_POST runs from #wm_file_read_post. */ + if (success == false) { + BKE_callback_exec_string(bmain, BKE_CB_EVT_LOAD_POST_FAIL, filepath); + } /* This function should leave the window null when the function entered. */ if (!has_window) { @@ -1053,7 +1066,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) 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); + wm_file_read_post(C, filepath, &read_file_post_params); bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole; file_read_reports_finalize(&bf_reports); @@ -1481,10 +1494,11 @@ void wm_homefile_read(bContext *C, 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); + const char *filepath = ""; + wm_file_read_post(C, filepath, params_file_read_post); if (params_file_read_post->use_data) { - wm_read_callback_post_wrapper(C, "", params_file_read_post->success); + wm_read_callback_post_wrapper(C, filepath, params_file_read_post->success); } if (params_file_read_post->is_alloc) { @@ -3282,6 +3296,12 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (!is_save_as) { + /* If saved as current file, there are technically no more compatibility issues, the file on + * disk now matches the currently opened data version-wise. */ + bmain->has_forward_compatibility_issues = false; + } + WM_event_add_notifier(C, NC_WM | ND_FILESAVE, nullptr); if (!is_save_as && RNA_boolean_get(op->ptr, "exit")) { @@ -3386,7 +3406,13 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent * } if (blendfile_path[0] != '\0') { - ret = wm_save_as_mainfile_exec(C, op); + if (CTX_data_main(C)->has_forward_compatibility_issues) { + wm_save_file_forwardcompat_dialog(C, op); + ret = OPERATOR_INTERFACE; + } + else { + ret = wm_save_as_mainfile_exec(C, op); + } } else { WM_event_add_fileselect(C, op); @@ -3665,6 +3691,206 @@ void wm_test_autorun_warning(bContext *C) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Save File Forward Compatibility Dialog + * \{ */ + +static void free_post_file_close_action(void *arg) +{ + wmGenericCallback *action = (wmGenericCallback *)arg; + WM_generic_callback_free(action); +} + +static void wm_free_operator_properties_callback(void *user_data) +{ + IDProperty *properties = (IDProperty *)user_data; + IDP_FreeProperty(properties); +} + +static const char *save_file_forwardcompat_dialog_name = "save_file_forwardcompat_popup"; + +static void file_forwardcompat_detailed_info_show(uiLayout *parent_layout, Main *bmain) +{ + uiLayout *layout = uiLayoutColumn(parent_layout, true); + /* Trick to make both lines of text below close enough to look like they are part of a same + * block. */ + uiLayoutSetScaleY(layout, 0.70f); + + char writer_ver_str[16]; + char current_ver_str[16]; + if (bmain->versionfile == BLENDER_VERSION) { + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile); + BKE_blender_version_blendfile_string_from_values( + current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION); + } + else { + BKE_blender_version_blendfile_string_from_values( + writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1); + BKE_blender_version_blendfile_string_from_values( + current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1); + } + + char message_line1[256]; + char message_line2[256]; + SNPRINTF(message_line1, + TIP_("This file was saved by a newer version of Blender (%s)"), + writer_ver_str); + SNPRINTF(message_line2, + TIP_("Saving it with this Blender (%s) may cause loss of data"), + current_ver_str); + uiItemL(layout, message_line1, ICON_NONE); + uiItemL(layout, message_line2, ICON_NONE); +} + +static void save_file_forwardcompat_cancel(bContext *C, void *arg_block, void * /*arg_data*/) +{ + wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, static_cast(arg_block)); +} + +static void save_file_forwardcompat_cancel_button(uiBlock *block, wmGenericCallback *post_action) +{ + uiBut *but = uiDefIconTextBut( + block, UI_BTYPE_BUT, 0, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, nullptr, 0, 0, 0, 0, ""); + UI_but_func_set(but, save_file_forwardcompat_cancel, block, post_action); + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); +} + +static void save_file_forwardcompat_overwrite(bContext *C, void *arg_block, void *arg_data) +{ + wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, static_cast(arg_block)); + + /* Re-use operator properties as defined for the initial 'save' operator, which triggered this + * 'forward compat' popup. */ + wmGenericCallback *callback = WM_generic_callback_steal( + static_cast(arg_data)); + PointerRNA operator_propptr = {}; + PointerRNA *operator_propptr_p = &operator_propptr; + IDProperty *operator_idproperties = static_cast(callback->user_data); + WM_operator_properties_alloc(&operator_propptr_p, &operator_idproperties, "WM_OT_save_mainfile"); + + WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, operator_propptr_p, nullptr); + + WM_generic_callback_free(callback); +} + +static void save_file_forwardcompat_overwrite_button(uiBlock *block, + wmGenericCallback *post_action) +{ + uiBut *but = uiDefIconTextBut( + block, UI_BTYPE_BUT, 0, 0, IFACE_("Overwrite"), 0, 0, 0, UI_UNIT_Y, nullptr, 0, 0, 0, 0, ""); + UI_but_func_set(but, save_file_forwardcompat_overwrite, block, post_action); + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); + UI_but_flag_enable(but, UI_BUT_REDALERT); +} + +static void save_file_forwardcompat_saveas(bContext *C, void *arg_block, void * /*arg_data*/) +{ + wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, static_cast(arg_block)); + + WM_operator_name_call(C, "WM_OT_save_as_mainfile", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); +} + +static void save_file_forwardcompat_saveas_button(uiBlock *block, wmGenericCallback *post_action) +{ + uiBut *but = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + 0, + IFACE_("Save As..."), + 0, + 0, + 0, + UI_UNIT_Y, + nullptr, + 0, + 0, + 0, + 0, + ""); + UI_but_func_set(but, save_file_forwardcompat_saveas, block, post_action); + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); + UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); +} + +static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C, + ARegion *region, + void *arg1) +{ + wmGenericCallback *post_action = static_cast(arg1); + Main *bmain = CTX_data_main(C); + + uiBlock *block = UI_block_begin(C, region, save_file_forwardcompat_dialog_name, UI_EMBOSS); + UI_block_flag_enable( + block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); + UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); + + uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_WARNING); + + /* Title. */ + uiItemL_ex( + layout, TIP_("Overwrite file with an older Blender version?"), ICON_NONE, true, false); + + /* Filename. */ + const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C)); + char filename[FILE_MAX]; + if (blendfile_path[0] != '\0') { + BLI_path_split_file_part(blendfile_path, filename, sizeof(filename)); + } + else { + SNPRINTF(filename, "%s.blend", DATA_("untitled")); + /* Since this dialog should only be shown when re-saving an existing file, current filepath + * should never be empty. */ + BLI_assert_unreachable(); + } + uiItemL(layout, filename, ICON_NONE); + + /* Detailed message info. */ + file_forwardcompat_detailed_info_show(layout, bmain); + + uiItemS_ex(layout, 4.0f); + + /* Buttons. */ + + uiLayout *split = uiLayoutSplit(layout, 0.3f, true); + uiLayoutSetScaleY(split, 1.2f); + + uiLayoutColumn(split, false); + save_file_forwardcompat_overwrite_button(block, post_action); + + uiLayout *split_right = uiLayoutSplit(split, 0.1f, true); + + uiLayoutColumn(split_right, false); + /* Empty space. */ + + uiLayoutColumn(split_right, false); + save_file_forwardcompat_cancel_button(block, post_action); + + uiLayoutColumn(split_right, false); + save_file_forwardcompat_saveas_button(block, post_action); + + UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC); + return block; +} + +void wm_save_file_forwardcompat_dialog(bContext *C, wmOperator *op) +{ + if (!UI_popup_block_name_exists(CTX_wm_screen(C), save_file_forwardcompat_dialog_name)) { + wmGenericCallback *callback = MEM_cnew(__func__); + callback->exec = nullptr; + callback->user_data = IDP_CopyProperty(op->properties); + callback->free_user_data = wm_free_operator_properties_callback; + + UI_popup_block_invoke( + C, block_create_save_file_forwardcompat_dialog, callback, free_post_file_close_action); + } +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Close File Dialog * \{ */ @@ -3715,11 +3941,23 @@ static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_dat bool file_has_been_saved_before = BKE_main_blendfile_path(bmain)[0] != '\0'; if (file_has_been_saved_before) { - if (WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, nullptr, nullptr) & - OPERATOR_CANCELLED) - { + if (bmain->has_forward_compatibility_issues) { + /* Need to invoke to get the filebrowser and choose where to save the new file. + * This also makes it impossible to keep on going with current operation, which is why + * callback cannot be executed anymore. + * + * This is the same situation as what happens when the file has never been saved before + * (outer `else` statement, below). */ + WM_operator_name_call(C, "WM_OT_save_as_mainfile", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); execute_callback = false; } + else { + if (WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, nullptr, nullptr) & + OPERATOR_CANCELLED) + { + execute_callback = false; + } + } } else { WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); @@ -3748,10 +3986,27 @@ static void wm_block_file_close_discard_button(uiBlock *block, wmGenericCallback UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); } -static void wm_block_file_close_save_button(uiBlock *block, wmGenericCallback *post_action) +static void wm_block_file_close_save_button(uiBlock *block, + wmGenericCallback *post_action, + const bool has_forwardcompat_issues) { uiBut *but = uiDefIconTextBut( - block, UI_BTYPE_BUT, 0, 0, IFACE_("Save"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, ""); + block, + UI_BTYPE_BUT, + 0, + 0, + /* Forward compatibility issues force using 'save as' operator instead of 'save' one. */ + has_forwardcompat_issues ? IFACE_("Save As...") : IFACE_("Save"), + 0, + 0, + 0, + UI_UNIT_Y, + nullptr, + 0, + 0, + 0, + 0, + ""); UI_but_func_set(but, wm_block_file_close_save, block, post_action); UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); @@ -3779,6 +4034,8 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION); + const bool has_forwardcompat_issues = bmain->has_forward_compatibility_issues; + /* Title. */ uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false); @@ -3793,6 +4050,11 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, } uiItemL(layout, filename, ICON_NONE); + /* Potential forward compatibility issues message. */ + if (has_forwardcompat_issues) { + file_forwardcompat_detailed_info_show(layout, bmain); + } + /* Image Saving Warnings. */ ReportList reports; BKE_reports_init(&reports, RPT_STORE); @@ -3899,7 +4161,7 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, uiLayoutSetScaleY(split, 1.2f); uiLayoutColumn(split, false); - wm_block_file_close_save_button(block, post_action); + wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues); uiLayoutColumn(split, false); wm_block_file_close_discard_button(block, post_action); @@ -3925,19 +4187,13 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, wm_block_file_close_cancel_button(block, post_action); uiLayoutColumn(split_right, false); - wm_block_file_close_save_button(block, post_action); + wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues); } UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC); return block; } -static void free_post_file_close_action(void *arg) -{ - wmGenericCallback *action = (wmGenericCallback *)arg; - WM_generic_callback_free(action); -} - void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action) { if (!UI_popup_block_name_exists(CTX_wm_screen(C), close_file_dialog_name)) { @@ -3949,12 +4205,6 @@ void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action) } } -static void wm_free_operator_properties_callback(void *user_data) -{ - IDProperty *properties = (IDProperty *)user_data; - IDP_FreeProperty(properties); -} - bool wm_operator_close_file_dialog_if_needed(bContext *C, wmOperator *op, wmGenericCallbackFn post_action_fn) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 41f0dcfb867c..88001f8d646a 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1258,24 +1258,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt break; } case GHOST_kEventWindowActivate: { - -#ifdef WIN32 - /* NOTE(@ideasman42): Alt-Tab on Windows-10 (22H2) can deactivate the window, - * then (in rare cases - approx 1 in 20) immediately call `WM_ACTIVATE` on the window - * (which isn't active) and doesn't receive modifier release events. - * This looks like a bug in MS-Windows, searching online other apps - * have run into similar issues although it's not clear exactly which. - * - * - Therefor activation must always clear modifiers - * or Alt-Tab can occasionally get stuck, see: #105381. - * - Unfortunately modifiers that are held before - * the window is active are ignored, see: #40059. - */ - wm_window_update_eventstate_modifiers_clear(wm, win); -#else /* Ensure the event state matches modifiers (window was inactive). */ wm_window_update_eventstate_modifiers(wm, win); -#endif /* Entering window, update mouse position (without sending an event). */ wm_window_update_eventstate(win); diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 225589d996ac..7b7c21ade6b2 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -88,6 +88,13 @@ bool wm_operator_close_file_dialog_if_needed(bContext *C, * Check if there is data that would be lost when closing the current file without saving. */ bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm); +/** + * Confirmation dialog when user is about to save the current blend file, and it was prviously + * created by a newer version of Blender. + * + * Important to ask confirmation, as this is a very common scenario of data loss. + */ +void wm_save_file_forwardcompat_dialog(bContext *C, wmOperator *op); void WM_OT_save_homefile(struct wmOperatorType *ot); void WM_OT_save_userpref(struct wmOperatorType *ot); diff --git a/tests/python/bl_blendfile_library_overrides.py b/tests/python/bl_blendfile_library_overrides.py index e9cc8d4629cd..9e3f7f53cbfa 100644 --- a/tests/python/bl_blendfile_library_overrides.py +++ b/tests/python/bl_blendfile_library_overrides.py @@ -181,120 +181,638 @@ def test_permissive_template(self): assert operation.operation == 'NOOP' -class TestLibraryOverridesResync(TestHelper, unittest.TestCase): +class TestLibraryOverridesComplex(TestHelper, unittest.TestCase): + # Test resync, recursive resync, overrides of overrides, ID names collision handling, and multiple overrides. + DATA_NAME_CONTAINER = "LibCollection" DATA_NAME_RIGGED = "LibRigged" DATA_NAME_RIG = "LibRig" DATA_NAME_CONTROLLER_1 = "LibController1" DATA_NAME_CONTROLLER_2 = "LibController2" + DATA_NAME_SAMENAME_CONTAINER = "LibCube" + DATA_NAME_SAMENAME_0 = "LibCube" + DATA_NAME_SAMENAME_1 = "LibCube.001" + DATA_NAME_SAMENAME_2 = "LibCube.002" + DATA_NAME_SAMENAME_3 = "LibCube.003" def __init__(self, args): self.args = args output_dir = pathlib.Path(self.args.output_dir) self.ensure_path(str(output_dir)) - self.output_path = output_dir / "blendlib_overrides.blend" + self.lib_output_path = output_dir / "blendlib_overrides_lib.blend" self.test_output_path = output_dir / "blendlib_overrides_test.blend" + self.test_output_path_recursive = output_dir / "blendlib_overrides_test_recursive.blend" + def reset(self): bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) - collection_container = bpy.data.collections.new(TestLibraryOverridesResync.DATA_NAME_CONTAINER) + def init_lib_data(self, custom_cb=None): + self.reset() + + collection_container = bpy.data.collections.new(self.__class__.DATA_NAME_CONTAINER) bpy.context.collection.children.link(collection_container) - mesh = bpy.data.meshes.new(TestLibraryOverridesResync.DATA_NAME_RIGGED) - obj_child = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_RIGGED, object_data=mesh) + mesh = bpy.data.meshes.new(self.__class__.DATA_NAME_RIGGED) + obj_child = bpy.data.objects.new(self.__class__.DATA_NAME_RIGGED, object_data=mesh) collection_container.objects.link(obj_child) - armature = bpy.data.armatures.new(TestLibraryOverridesResync.DATA_NAME_RIG) - obj_armature = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_RIG, object_data=armature) + armature = bpy.data.armatures.new(self.__class__.DATA_NAME_RIG) + obj_armature = bpy.data.objects.new(self.__class__.DATA_NAME_RIG, object_data=armature) obj_child.parent = obj_armature collection_container.objects.link(obj_armature) obj_child_modifier = obj_child.modifiers.new("", 'ARMATURE') obj_child_modifier.object = obj_armature - obj_ctrl1 = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_CONTROLLER_1, object_data=None) + obj_ctrl1 = bpy.data.objects.new(self.__class__.DATA_NAME_CONTROLLER_1, object_data=None) collection_container.objects.link(obj_ctrl1) obj_armature_constraint = obj_armature.constraints.new('COPY_LOCATION') obj_armature_constraint.target = obj_ctrl1 - collection_sub = bpy.data.collections.new(TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2) + collection_sub = bpy.data.collections.new(self.__class__.DATA_NAME_CONTROLLER_2) collection_container.children.link(collection_sub) - obj_ctrl2 = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2, object_data=None) + obj_ctrl2 = bpy.data.objects.new(self.__class__.DATA_NAME_CONTROLLER_2, object_data=None) collection_sub.objects.link(obj_ctrl2) - bpy.ops.wm.save_as_mainfile(filepath=str(self.output_path), check_existing=False, compress=False) + collection_sub = bpy.data.collections.new(self.__class__.DATA_NAME_SAMENAME_CONTAINER) + collection_container.children.link(collection_sub) + # 'Samename' objects are purposedly not added to the collection here. - def test_link_and_override_resync(self): - bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) - bpy.data.orphans_purge() + if custom_cb is not None: + custom_cb(self) + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.lib_output_path), + check_existing=False, + compress=False, + relative_remap=False, + ) - link_dir = self.output_path / "Collection" + def edit_lib_data(self, custom_cb): + bpy.ops.wm.open_mainfile(filepath=str(self.lib_output_path)) + custom_cb(self) + bpy.ops.wm.save_as_mainfile( + filepath=str(self.lib_output_path), + check_existing=False, + compress=False, + relative_remap=False, + ) + + def link_lib_data(self, num_collections, num_objects, num_meshes, num_armatures): + link_dir = self.lib_output_path / "Collection" bpy.ops.wm.link( directory=str(link_dir), - filename=TestLibraryOverridesResync.DATA_NAME_CONTAINER, + filename=self.__class__.DATA_NAME_CONTAINER, instance_collections=False, + relative_path=False, ) - linked_collection_container = bpy.data.collections[TestLibraryOverridesResync.DATA_NAME_CONTAINER] + linked_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER] + assert linked_collection_container.library is not None assert linked_collection_container.override_library is None - assert len(bpy.data.collections) == 2 + assert len(bpy.data.collections) == num_collections + assert all(id_.library is not None for id_ in bpy.data.collections) + assert len(bpy.data.objects) == num_objects + assert all(id_.library is not None for id_ in bpy.data.objects) + assert len(bpy.data.meshes) == num_meshes + assert all(id_.library is not None for id_ in bpy.data.meshes) + assert len(bpy.data.armatures) == num_armatures + assert all(id_.library is not None for id_ in bpy.data.armatures) + + return linked_collection_container + + def link_liboverride_data(self, num_collections, num_objects, num_meshes, num_armatures): + link_dir = self.test_output_path / "Collection" + bpy.ops.wm.link( + directory=str(link_dir), + filename=self.__class__.DATA_NAME_CONTAINER, + instance_collections=False, + relative_path=False, + ) + + linked_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER, str(self.test_output_path)] + assert linked_collection_container.library is not None + assert linked_collection_container.override_library is not None + assert len(bpy.data.collections) == num_collections assert all(id_.library is not None for id_ in bpy.data.collections) - assert len(bpy.data.objects) == 4 + assert len(bpy.data.objects) == num_objects assert all(id_.library is not None for id_ in bpy.data.objects) - assert len(bpy.data.meshes) == 1 + assert len(bpy.data.meshes) == num_meshes assert all(id_.library is not None for id_ in bpy.data.meshes) - assert len(bpy.data.armatures) == 1 + assert len(bpy.data.armatures) == num_armatures assert all(id_.library is not None for id_ in bpy.data.armatures) + self.liboverride_hierarchy_validate(linked_collection_container) + + return linked_collection_container + + @staticmethod + def liboverride_hierarchy_validate(root_collection): + def liboverride_systemoverrideonly_hierarchy_validate(id_, id_root): + if not id_.override_library: + return + assert id_.override_library.hierarchy_root == id_root + for op in id_.override_library.properties: + for opop in op.operations: + assert 'IDPOINTER_MATCH_REFERENCE' in opop.flag + + for coll_ in root_collection.children_recursive: + liboverride_systemoverrideonly_hierarchy_validate(coll_, root_collection) + for ob_ in root_collection.all_objects: + liboverride_systemoverrideonly_hierarchy_validate(ob_, root_collection) + + def test_link_and_override_resync(self): + self.init_lib_data() + self.reset() + + # NOTE: All counts below are in the form `local_ids + linked_ids`. + linked_collection_container = self.link_lib_data( + num_collections=0 + 3, + num_objects=0 + 4, + num_meshes=0 + 1, + num_armatures=0 + 1) + override_collection_container = linked_collection_container.override_hierarchy_create( bpy.context.scene, bpy.context.view_layer, ) assert override_collection_container.library is None assert override_collection_container.override_library is not None + # Objects and collections are duplicated as overrides (except for empty collection), + # but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 2 + 3 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]) + assert len(bpy.data.objects) == 4 + 4 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + self.liboverride_hierarchy_validate(override_collection_container) + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path), + check_existing=False, + compress=False, + relative_remap=False, + ) + + # Create linked liboverrides file (for recursive resync). + self.reset() + + self.link_liboverride_data( + num_collections=0 + 5, + num_objects=0 + 8, + num_meshes=0 + 1, + num_armatures=0 + 1) + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path_recursive), + check_existing=False, + compress=False, + relative_remap=False, + ) + + # Re-open the lib file, and change its ID relationships. + bpy.ops.wm.open_mainfile(filepath=str(self.lib_output_path)) + + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG] + obj_armature_constraint = obj_armature.constraints[0] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2] + obj_armature_constraint.target = obj_ctrl2 + + bpy.ops.wm.save_as_mainfile(filepath=str(self.lib_output_path), check_existing=False, compress=False) + + # Re-open the main file, and check that automatic resync did its work correctly, remapping the target of the + # armature constraint to controller 2, without creating unexpected garbage IDs along the line. + bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path)) + + override_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER] + assert override_collection_container.library is None + assert override_collection_container.override_library is not None + assert len(bpy.data.collections) == 2 + 3 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]) + assert len(bpy.data.objects) == 4 + 4 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2] + assert obj_armature.library is None and obj_armature.override_library is not None + assert obj_ctrl2.library is None and obj_ctrl2.override_library is not None + assert obj_armature.constraints[0].target == obj_ctrl2 + + self.liboverride_hierarchy_validate(override_collection_container) + + # Re-open the 'recursive resync' file, and check that automatic recursive resync did its work correctly, + # remapping the target of the linked liboverride armature constraint to controller 2, without creating + # unexpected garbage IDs along the line. + bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path_recursive)) + + override_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER, str(self.test_output_path)] + assert override_collection_container.library is not None + assert override_collection_container.override_library is not None + test_output_path_lib = override_collection_container.library + assert len(bpy.data.collections) == 0 + 5 + assert all((id_.override_library is not None) for id_ in bpy.data.collections if id_.library == test_output_path_lib) + assert len(bpy.data.objects) == 0 + 8 + assert all((id_.override_library is not None) for id_ in bpy.data.objects if id_.library == test_output_path_lib) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG, str(self.test_output_path)] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2, str(self.test_output_path)] + assert obj_armature.override_library is not None + assert obj_ctrl2.override_library is not None + assert obj_armature.constraints[0].target == obj_ctrl2 + + self.liboverride_hierarchy_validate(override_collection_container) + + def test_link_and_override_multiple(self): + self.init_lib_data() + self.reset() + + # NOTE: All counts below are in the form `local_ids + linked_ids`. + linked_collection_container = self.link_lib_data( + num_collections=0 + 3, + num_objects=0 + 4, + num_meshes=0 + 1, + num_armatures=0 + 1) + + override_collection_containers = [linked_collection_container.override_hierarchy_create( + bpy.context.scene, + bpy.context.view_layer, + ) for i in range(3)] + for override_container in override_collection_containers: + assert override_container.library is None + assert override_container.override_library is not None + self.liboverride_hierarchy_validate(override_container) + + # Objects and collections are duplicated as overrides (except for empty collection), + # but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 3 * 2 + 3 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:3 * 2]) + assert len(bpy.data.objects) == 3 * 4 + 4 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:3 * 4]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path), + check_existing=False, + compress=False, + relative_remap=False, + ) + + # Create linked liboverrides file (for recursive resync). + self.reset() + + self.link_liboverride_data( + num_collections=0 + 5, + num_objects=0 + 8, + num_meshes=0 + 1, + num_armatures=0 + 1) + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path_recursive), + check_existing=False, + compress=False, + relative_remap=False, + ) + + # Change the lib's ID relationships. + def edit_lib_cb(self): + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG] + obj_armature_constraint = obj_armature.constraints[0] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2] + obj_armature_constraint.target = obj_ctrl2 + self.edit_lib_data(edit_lib_cb) + + # Re-open the main file, and check that automatic resync did its work correctly, remapping the target of the + # armature constraint to controller 2, without creating unexpected garbage IDs along the line. + bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path)) + + override_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER] + assert override_collection_container.library is None + assert override_collection_container.override_library is not None + # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 3 * 2 + 3 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:3 * 2]) + assert len(bpy.data.objects) == 3 * 4 + 4 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:3 * 4]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2] + assert obj_armature.library is None and obj_armature.override_library is not None + assert obj_ctrl2.library is None and obj_ctrl2.override_library is not None + assert obj_armature.constraints[0].target == obj_ctrl2 + + override_collection_containers = [ + bpy.data.collections[self.__class__.DATA_NAME_CONTAINER], + bpy.data.collections[self.__class__.DATA_NAME_CONTAINER + ".001"], + bpy.data.collections[self.__class__.DATA_NAME_CONTAINER + ".002"], + ] + for override_container in override_collection_containers: + assert override_container.library is None + assert override_container.override_library is not None + self.liboverride_hierarchy_validate(override_container) + + # Re-open the 'recursive resync' file, and check that automatic recursive resync did its work correctly, + # remapping the target of the linked liboverride armature constraint to controller 2, without creating + # unexpected garbage IDs along the line. + bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path_recursive)) + + linked_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER, str(self.test_output_path)] + assert linked_collection_container.library is not None + assert linked_collection_container.override_library is not None + test_output_path_lib = linked_collection_container.library # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data. - assert len(bpy.data.collections) == 4 + assert len(bpy.data.collections) == 0 + 5 + assert all((id_.override_library is not None) for id_ in bpy.data.collections if id_.library == test_output_path_lib) + assert len(bpy.data.objects) == 0 + 8 + assert all((id_.override_library is not None) for id_ in bpy.data.objects if id_.library == test_output_path_lib) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG, str(self.test_output_path)] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2, str(self.test_output_path)] + assert obj_armature.override_library is not None + assert obj_ctrl2.override_library is not None + assert obj_armature.constraints[0].target == obj_ctrl2 + + self.liboverride_hierarchy_validate(linked_collection_container) + + def test_link_and_override_of_override(self): + self.init_lib_data() + self.reset() + + # NOTE: All counts below are in the form `local_ids + linked_ids`. + linked_collection_container = self.link_lib_data( + num_collections=0 + 3, + num_objects=0 + 4, + num_meshes=0 + 1, + num_armatures=0 + 1) + + override_collection_container = linked_collection_container.override_hierarchy_create( + bpy.context.scene, + bpy.context.view_layer, + ) + assert override_collection_container.library is None + assert override_collection_container.override_library is not None + + # Objects and collections are duplicated as overrides (except for empty collection), + # but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 2 + 3 assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]) - assert len(bpy.data.objects) == 8 + assert len(bpy.data.objects) == 4 + 4 assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]) - assert len(bpy.data.meshes) == 1 - assert len(bpy.data.armatures) == 1 + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + self.liboverride_hierarchy_validate(override_collection_container) + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path), + check_existing=False, + compress=False, + relative_remap=False, + ) - bpy.ops.wm.save_as_mainfile(filepath=str(self.test_output_path), check_existing=False, compress=False) + # Create liboverrides of liboverrides file. + self.reset() + + linked_collection_container = self.link_liboverride_data( + num_collections=0 + 5, + num_objects=0 + 8, + num_meshes=0 + 1, + num_armatures=0 + 1) + + override_collection_container = linked_collection_container.override_hierarchy_create( + bpy.context.scene, + bpy.context.view_layer, + ) + assert override_collection_container.library is None + assert override_collection_container.override_library is not None + + # Objects and collections are duplicated as overrides (except for empty collection), + # but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 2 + 5 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]) + assert len(bpy.data.objects) == 4 + 8 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + self.liboverride_hierarchy_validate(override_collection_container) + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path_recursive), + check_existing=False, + compress=False, + relative_remap=False, + ) # Re-open the lib file, and change its ID relationships. - bpy.ops.wm.open_mainfile(filepath=str(self.output_path)) + bpy.ops.wm.open_mainfile(filepath=str(self.lib_output_path)) - obj_armature = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_RIG] + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG] obj_armature_constraint = obj_armature.constraints[0] - obj_ctrl2 = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2] obj_armature_constraint.target = obj_ctrl2 - bpy.ops.wm.save_as_mainfile(filepath=str(self.output_path), check_existing=False, compress=False) + bpy.ops.wm.save_as_mainfile(filepath=str(self.lib_output_path), check_existing=False, compress=False) # Re-open the main file, and check that automatic resync did its work correctly, remapping the target of the # armature constraint to controller 2, without creating unexpected garbage IDs along the line. bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path)) - override_collection_container = bpy.data.collections[TestLibraryOverridesResync.DATA_NAME_CONTAINER] + override_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER] assert override_collection_container.library is None assert override_collection_container.override_library is not None # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data. - assert len(bpy.data.collections) == 4 + assert len(bpy.data.collections) == 2 + 3 assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]) - assert len(bpy.data.objects) == 8 + assert len(bpy.data.objects) == 4 + 4 assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]) - assert len(bpy.data.meshes) == 1 - assert len(bpy.data.armatures) == 1 + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 - obj_armature = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_RIG] - obj_ctrl2 = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2] + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2] assert obj_armature.library is None and obj_armature.override_library is not None assert obj_ctrl2.library is None and obj_ctrl2.override_library is not None assert obj_armature.constraints[0].target == obj_ctrl2 + self.liboverride_hierarchy_validate(override_collection_container) + + # Re-open the 'recursive resync' file, and check that automatic recursive resync did its work correctly, + # remapping the target of the linked liboverride armature constraint to controller 2, without creating + # unexpected garbage IDs along the line. + bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path_recursive)) + + override_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER] + assert override_collection_container.library is None + assert override_collection_container.override_library is not None + # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 2 + 5 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]) + assert len(bpy.data.objects) == 4 + 8 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + obj_armature = bpy.data.objects[self.__class__.DATA_NAME_RIG] + obj_ctrl2 = bpy.data.objects[self.__class__.DATA_NAME_CONTROLLER_2] + assert obj_armature.override_library is not None + assert obj_ctrl2.override_library is not None + assert obj_armature.constraints[0].target == obj_ctrl2 + + self.liboverride_hierarchy_validate(override_collection_container) + + def test_link_and_override_idnames_conflict(self): + def init_lib_cb(self): + # Add some 'samename' objects to the library. + collection_sub = bpy.data.collections[self.__class__.DATA_NAME_SAMENAME_CONTAINER] + obj_samename_0 = bpy.data.objects.new(self.__class__.DATA_NAME_SAMENAME_0, object_data=None) + collection_sub.objects.link(obj_samename_0) + obj_samename_3 = bpy.data.objects.new(self.__class__.DATA_NAME_SAMENAME_3, object_data=None) + collection_sub.objects.link(obj_samename_3) + self.init_lib_data(init_lib_cb) + self.reset() + + # NOTE: All counts below are in the form `local_ids + linked_ids`. + linked_collection_container = self.link_lib_data( + num_collections=0 + 3, + num_objects=0 + 6, + num_meshes=0 + 1, + num_armatures=0 + 1) + + override_collection_containers = [linked_collection_container.override_hierarchy_create( + bpy.context.scene, + bpy.context.view_layer, + ) for i in range(3)] + for override_container in override_collection_containers: + assert override_container.library is None + assert override_container.override_library is not None + self.liboverride_hierarchy_validate(override_container) + + # Objects and collections are duplicated as overrides (except for empty collection), + # but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 3 * 3 + 3 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:3 * 3]) + assert len(bpy.data.objects) == 3 * 6 + 6 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:3 * 6]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + bpy.data.objects[self.__class__.DATA_NAME_SAMENAME_0].override_library.reference.name == self.__class__.DATA_NAME_SAMENAME_0 + bpy.data.objects[self.__class__.DATA_NAME_SAMENAME_3].override_library.reference.name == self.__class__.DATA_NAME_SAMENAME_3 + # These names will be used by the second created liboverride, due to how naming is currently handled when original name is already used. + bpy.data.objects[self.__class__.DATA_NAME_SAMENAME_1].override_library.reference.name == self.__class__.DATA_NAME_SAMENAME_0 + bpy.data.objects[self.__class__.DATA_NAME_SAMENAME_2].override_library.reference.name == self.__class__.DATA_NAME_SAMENAME_3 + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path), + check_existing=False, + compress=False, + relative_remap=False, + ) + + # Create liboverrides of liboverrides file. + self.reset() + + linked_collection_container = self.link_liboverride_data( + num_collections=0 + 6, + num_objects=0 + 12, + num_meshes=0 + 1, + num_armatures=0 + 1) + + override_collection_container = linked_collection_container.override_hierarchy_create( + bpy.context.scene, + bpy.context.view_layer, + ) + assert override_collection_container.library is None + assert override_collection_container.override_library is not None + + # Objects and collections are duplicated as overrides (except for empty collection), + # but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 3 + 6 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:3]) + assert len(bpy.data.objects) == 6 + 12 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:6]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + self.liboverride_hierarchy_validate(override_collection_container) + + bpy.ops.wm.save_as_mainfile( + filepath=str(self.test_output_path_recursive), + check_existing=False, + compress=False, + relative_remap=False, + ) + + # Modify the names of 'samename' objects in the library to generate ID name collisions. + def edit_lib_cb(self): + obj_samename_0 = bpy.data.objects[self.__class__.DATA_NAME_SAMENAME_0] + obj_samename_3 = bpy.data.objects[self.__class__.DATA_NAME_SAMENAME_3] + obj_samename_0.name = self.__class__.DATA_NAME_SAMENAME_2 + obj_samename_3.name = self.__class__.DATA_NAME_SAMENAME_1 + self.edit_lib_data(edit_lib_cb) + + # Re-open the main file, and check that automatic resync did its work correctly, remapping the target of the + # armature constraint to controller 2, without creating unexpected garbage IDs along the line. + bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path)) + + override_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER] + assert override_collection_container.library is None + assert override_collection_container.override_library is not None + # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 3 * 3 + 3 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:3 * 3]) + # Note that the 'missing' renamed objects from the library are still here as empty placeholders, + # hence the 8 linked ones instead of 6. + assert len(bpy.data.objects) == 3 * 6 + 8 + assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:3 * 6]) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + override_collection_containers = [ + bpy.data.collections[self.__class__.DATA_NAME_CONTAINER], + bpy.data.collections[self.__class__.DATA_NAME_CONTAINER + ".001"], + bpy.data.collections[self.__class__.DATA_NAME_CONTAINER + ".002"], + ] + for override_container in override_collection_containers: + assert override_container.library is None + assert override_container.override_library is not None + self.liboverride_hierarchy_validate(override_container) + + # Re-open the 'recursive resync' file, and check that automatic recursive resync did its work correctly, + # remapping the target of the linked liboverride armature constraint to controller 2, without creating + # unexpected garbage IDs along the line. + bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path_recursive)) + + linked_collection_container = bpy.data.collections[self.__class__.DATA_NAME_CONTAINER, str(self.test_output_path)] + assert linked_collection_container.library is not None + assert linked_collection_container.override_library is not None + + test_output_path_lib = linked_collection_container.library + # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data. + assert len(bpy.data.collections) == 3 + 6 + assert all((id_.override_library is not None) for id_ in bpy.data.collections if id_.library == test_output_path_lib) + # Note that the 'missing' renamed objects from the library are still here as empty placeholders, + # hence the 8 + 6 linked ones instead of 6 + 6. + assert len(bpy.data.objects) == 6 + 14 + assert all((id_.override_library is not None) for id_ in bpy.data.objects if id_.library == test_output_path_lib) + assert len(bpy.data.meshes) == 0 + 1 + assert len(bpy.data.armatures) == 0 + 1 + + self.liboverride_hierarchy_validate(linked_collection_container) + class TestLibraryOverridesFromProxies(TestHelper, unittest.TestCase): # Very basic test, could be improved/extended. @@ -325,7 +843,7 @@ def test_open_linked_proxy_file(self): TESTS = ( TestLibraryOverrides, TestLibraryTemplate, - TestLibraryOverridesResync, + TestLibraryOverridesComplex, TestLibraryOverridesFromProxies, )