diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2022-08-01 17:29:52 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2022-08-01 17:29:52 +0300 |
commit | be0449cfcae25ff64540e3859232481826f675fb (patch) | |
tree | 80f663b543f27c97e39f6265ea119abc512b6c6a | |
parent | 49bccd7740622d287f82e4c9b73bfc81d9a22584 (diff) | |
parent | 3393b7137e247383477eb38d938239fbb9221680 (diff) |
Merge branch 'master' into sculpt_curve_collisionssculpt_curve_collisions
303 files changed, 6466 insertions, 4508 deletions
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 2441b9ad89b..4ffdbf2d162 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -478,7 +478,7 @@ OCIO_FORCE_BUILD=false OCIO_FORCE_REBUILD=false OCIO_SKIP=false -IMATH_VERSION="3.1.4" +IMATH_VERSION="3.1.5" IMATH_VERSION_SHORT="3.1" IMATH_VERSION_MIN="3.0" IMATH_VERSION_MEX="4.0" @@ -487,7 +487,7 @@ IMATH_FORCE_REBUILD=false IMATH_SKIP=false _with_built_imath=false -OPENEXR_VERSION="3.1.4" +OPENEXR_VERSION="3.1.5" OPENEXR_VERSION_SHORT="3.1" OPENEXR_VERSION_MIN="3.0" OPENEXR_VERSION_MEX="4.0" @@ -627,6 +627,9 @@ WEBP_DEV="" VPX_USE=false VPX_VERSION_MIN=0.9.7 VPX_DEV="" +AOM_USE=false +AOM_VERSION_MIN=3.3.0 +AOM_DEV="" OPUS_USE=false OPUS_VERSION_MIN=1.1.1 OPUS_DEV="" @@ -1209,7 +1212,7 @@ You may also want to build them yourself (optional ones are [between brackets]): ** [NumPy $PYTHON_NUMPY_VERSION] (use pip). * Boost $BOOST_VERSION (from $BOOST_SOURCE, modules: $BOOST_BUILD_MODULES). * TBB $TBB_VERSION (from $TBB_SOURCE). - * [FFMpeg $FFMPEG_VERSION (needs libvorbis, libogg, libtheora, libx264, libmp3lame, libxvidcore, libvpx, libwebp, ...)] (from $FFMPEG_SOURCE). + * [FFMpeg $FFMPEG_VERSION (needs libvorbis, libogg, libtheora, libx264, libmp3lame, libxvidcore, libvpx, libaom, libwebp, ...)] (from $FFMPEG_SOURCE). * [OpenColorIO $OCIO_VERSION] (from $OCIO_SOURCE). * Imath $IMATH_VERSION (from $IMATH_SOURCE). * OpenEXR $OPENEXR_VERSION (from $OPENEXR_SOURCE). @@ -3000,7 +3003,7 @@ compile_ALEMBIC() { fi # To be changed each time we make edits that would modify the compiled result! - alembic_magic=2 + alembic_magic=3 _init_alembic # Force having own builds for the dependencies. @@ -3048,7 +3051,7 @@ compile_ALEMBIC() { fi if [ "$_with_built_openexr" = true ]; then cmake_d="$cmake_d -D USE_ARNOLD=OFF" - cmake_d="$cmake_d -D USE_BINARIES=OFF" + cmake_d="$cmake_d -D USE_BINARIES=ON" # Tests use some Alembic binaries... cmake_d="$cmake_d -D USE_EXAMPLES=OFF" cmake_d="$cmake_d -D USE_HDF5=OFF" cmake_d="$cmake_d -D USE_MAYA=OFF" @@ -3634,7 +3637,7 @@ compile_FFmpeg() { fi # To be changed each time we make edits that would modify the compiled result! - ffmpeg_magic=5 + ffmpeg_magic=6 _init_ffmpeg # Force having own builds for the dependencies. @@ -3687,6 +3690,10 @@ compile_FFmpeg() { extra="$extra --enable-libvpx" fi + if [ "$AOM_USE" = true ]; then + extra="$extra --enable-libaom" + fi + if [ "$WEBP_USE" = true ]; then extra="$extra --enable-libwebp" fi @@ -4140,30 +4147,34 @@ install_DEB() { WEBP_USE=true fi - if [ "$WITH_ALL" = true ]; then - XVID_DEV="libxvidcore-dev" - check_package_DEB $XVID_DEV - if [ $? -eq 0 ]; then - XVID_USE=true - fi + XVID_DEV="libxvidcore-dev" + check_package_DEB $XVID_DEV + if [ $? -eq 0 ]; then + XVID_USE=true + fi - MP3LAME_DEV="libmp3lame-dev" - check_package_DEB $MP3LAME_DEV - if [ $? -eq 0 ]; then - MP3LAME_USE=true - fi + MP3LAME_DEV="libmp3lame-dev" + check_package_DEB $MP3LAME_DEV + if [ $? -eq 0 ]; then + MP3LAME_USE=true + fi - VPX_DEV="libvpx-dev" - check_package_version_ge_DEB $VPX_DEV $VPX_VERSION_MIN - if [ $? -eq 0 ]; then - VPX_USE=true - fi + VPX_DEV="libvpx-dev" + check_package_version_ge_DEB $VPX_DEV $VPX_VERSION_MIN + if [ $? -eq 0 ]; then + VPX_USE=true + fi - OPUS_DEV="libopus-dev" - check_package_version_ge_DEB $OPUS_DEV $OPUS_VERSION_MIN - if [ $? -eq 0 ]; then - OPUS_USE=true - fi + AOM_DEV="libaom-dev" + check_package_version_ge_DEB $AOM_DEV $AOM_VERSION_MIN + if [ $? -eq 0 ]; then + AOM_USE=true + fi + + OPUS_DEV="libopus-dev" + check_package_version_ge_DEB $OPUS_DEV $OPUS_VERSION_MIN + if [ $? -eq 0 ]; then + OPUS_USE=true fi # Check cmake version and disable features for older distros. @@ -4546,6 +4557,9 @@ install_DEB() { if [ "$VPX_USE" = true ]; then _packages="$_packages $VPX_DEV" fi + if [ "$AOM_USE" = true ]; then + _packages="$_packages $AOM_DEV" + fi if [ "$OPUS_USE" = true ]; then _packages="$_packages $OPUS_DEV" fi @@ -4846,21 +4860,27 @@ install_RPM() { WEBP_USE=true fi - if [ "$WITH_ALL" = true ]; then - VPX_DEV="libvpx-devel" - check_package_version_ge_RPM $VPX_DEV $VPX_VERSION_MIN - if [ $? -eq 0 ]; then - VPX_USE=true - fi + VPX_DEV="libvpx-devel" + check_package_version_ge_RPM $VPX_DEV $VPX_VERSION_MIN + if [ $? -eq 0 ]; then + VPX_USE=true + fi + + AOM_DEV="libaom-devel" + check_package_version_ge_RPM $AOM_DEV $AOM_VERSION_MIN + if [ $? -eq 0 ]; then + AOM_USE=true + fi + + OPUS_DEV="libopus-devel" + check_package_version_ge_RPM $OPUS_DEV $OPUS_VERSION_MIN + if [ $? -eq 0 ]; then + OPUS_USE=true + fi + if [ "$WITH_ALL" = true ]; then PRINT "" install_packages_RPM libspnav-devel - - OPUS_DEV="libopus-devel" - check_package_version_ge_RPM $OPUS_DEV $OPUS_VERSION_MIN - if [ $? -eq 0 ]; then - OPUS_USE=true - fi fi PRINT "" @@ -5245,6 +5265,9 @@ install_RPM() { if [ "$VPX_USE" = true ]; then _packages="$_packages $VPX_DEV" fi + if [ "$AOM_USE" = true ]; then + _packages="$_packages $AOM_DEV" + fi if [ "$OPUS_USE" = true ]; then _packages="$_packages $OPUS_DEV" fi @@ -5434,30 +5457,34 @@ install_ARCH() { WEBP_USE=true fi - if [ "$WITH_ALL" = true ]; then - XVID_DEV="xvidcore" - check_package_ARCH $XVID_DEV - if [ $? -eq 0 ]; then - XVID_USE=true - fi + XVID_DEV="xvidcore" + check_package_ARCH $XVID_DEV + if [ $? -eq 0 ]; then + XVID_USE=true + fi - MP3LAME_DEV="lame" - check_package_ARCH $MP3LAME_DEV - if [ $? -eq 0 ]; then - MP3LAME_USE=true - fi + MP3LAME_DEV="lame" + check_package_ARCH $MP3LAME_DEV + if [ $? -eq 0 ]; then + MP3LAME_USE=true + fi - VPX_DEV="libvpx" - check_package_version_ge_ARCH $VPX_DEV $VPX_VERSION_MIN - if [ $? -eq 0 ]; then - VPX_USE=true - fi + VPX_DEV="libvpx" + check_package_version_ge_ARCH $VPX_DEV $VPX_VERSION_MIN + if [ $? -eq 0 ]; then + VPX_USE=true + fi - OPUS_DEV="opus" - check_package_version_ge_ARCH $OPUS_DEV $OPUS_VERSION_MIN - if [ $? -eq 0 ]; then - OPUS_USE=true - fi + AOM_DEV="libaom" + check_package_version_ge_ARCH $AOM_DEV $AOM_VERSION_MIN + if [ $? -eq 0 ]; then + AOM_USE=true + fi + + OPUS_DEV="opus" + check_package_version_ge_ARCH $OPUS_DEV $OPUS_VERSION_MIN + if [ $? -eq 0 ]; then + OPUS_USE=true fi @@ -5835,6 +5862,9 @@ install_ARCH() { if [ "$VPX_USE" = true ]; then _packages="$_packages $VPX_DEV" fi + if [ "$AOM_USE" = true ]; then + _packages="$_packages $AOM_DEV" + fi if [ "$OPUS_USE" = true ]; then _packages="$_packages $OPUS_DEV" fi diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 3c77a28d55f..f84be3c5238 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -470,8 +470,9 @@ string(APPEND CMAKE_CXX_FLAGS " -ftemplate-depth=1024") # Avoid conflicts with Luxrender, and other plug-ins that may use the same # libraries as Blender with a different version or build options. +set(PLATFORM_SYMBOLS_MAP ${CMAKE_SOURCE_DIR}/source/creator/symbols_apple.map) string(APPEND PLATFORM_LINKFLAGS - " -Wl,-unexported_symbols_list,'${CMAKE_SOURCE_DIR}/source/creator/osx_locals.map'" + " -Wl,-unexported_symbols_list,'${PLATFORM_SYMBOLS_MAP}'" ) string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++") diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index d22cf437e59..f6e233a0c86 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -888,8 +888,9 @@ unset(_IS_LINKER_DEFAULT) # Avoid conflicts with Mesa llvmpipe, Luxrender, and other plug-ins that may # use the same libraries as Blender with a different version or build options. +set(PLATFORM_SYMBOLS_MAP ${CMAKE_SOURCE_DIR}/source/creator/symbols_unix.map) set(PLATFORM_LINKFLAGS - "${PLATFORM_LINKFLAGS} -Wl,--version-script='${CMAKE_SOURCE_DIR}/source/creator/blender.map'" + "${PLATFORM_LINKFLAGS} -Wl,--version-script='${PLATFORM_SYMBOLS_MAP}'" ) # Don't use position independent executable for portable install since file diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h index 5cc18452ac1..0ad4ca6fe83 100644 --- a/intern/cycles/blender/sync.h +++ b/intern/cycles/blender/sync.h @@ -7,6 +7,7 @@ #include "MEM_guardedalloc.h" #include "RNA_access.h" #include "RNA_blender_cpp.h" +#include "RNA_path.h" #include "RNA_types.h" #include "blender/id_map.h" diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 8ecdac6ee27..dfcd75a135e 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -355,8 +355,6 @@ set(SRC_UTIL_HEADERS ../util/types_uint4.h ../util/types_uint4_impl.h ../util/types_ushort4.h - ../util/types_vector3.h - ../util/types_vector3_impl.h ) set(LIB diff --git a/intern/cycles/kernel/device/cpu/compat.h b/intern/cycles/kernel/device/cpu/compat.h index 631e55e0d42..1e3e790ca1f 100644 --- a/intern/cycles/kernel/device/cpu/compat.h +++ b/intern/cycles/kernel/device/cpu/compat.h @@ -33,38 +33,4 @@ CCL_NAMESPACE_BEGIN #define kernel_assert(cond) assert(cond) -/* Macros to handle different memory storage on different devices */ - -#ifdef __KERNEL_SSE2__ -typedef vector3<sseb> sse3b; -typedef vector3<ssef> sse3f; -typedef vector3<ssei> sse3i; - -ccl_device_inline void print_sse3b(const char *label, sse3b &a) -{ - print_sseb(label, a.x); - print_sseb(label, a.y); - print_sseb(label, a.z); -} - -ccl_device_inline void print_sse3f(const char *label, sse3f &a) -{ - print_ssef(label, a.x); - print_ssef(label, a.y); - print_ssef(label, a.z); -} - -ccl_device_inline void print_sse3i(const char *label, sse3i &a) -{ - print_ssei(label, a.x); - print_ssei(label, a.y); - print_ssei(label, a.z); -} - -# if defined(__KERNEL_AVX__) || defined(__KERNEL_AVX2__) -typedef vector3<avxf> avx3f; -# endif - -#endif - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/device/oneapi/compat.h b/intern/cycles/kernel/device/oneapi/compat.h index 1b25259bcf5..ccd141aa892 100644 --- a/intern/cycles/kernel/device/oneapi/compat.h +++ b/intern/cycles/kernel/device/oneapi/compat.h @@ -149,25 +149,13 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \ /* clang-format on */ /* Types */ + /* It's not possible to use sycl types like sycl::float3, sycl::int3, etc - * because these types have different interfaces from blender version */ + * because these types have different interfaces from blender version. */ using uchar = unsigned char; using sycl::half; -struct float3 { - float x, y, z; -}; - -ccl_always_inline float3 make_float3(float x, float y, float z) -{ - return {x, y, z}; -} -ccl_always_inline float3 make_float3(float x) -{ - return {x, x, x}; -} - /* math functions */ #define fabsf(x) sycl::fabs((x)) #define copysignf(x, y) sycl::copysign((x), (y)) diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index 9bc9f00e142..b33bad79e6c 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -129,8 +129,6 @@ set(SRC_HEADERS types_uint4.h types_uint4_impl.h types_ushort4.h - types_vector3.h - types_vector3_impl.h unique_ptr.h vector.h version.h diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h index 2631304c84b..f6400cb879f 100644 --- a/intern/cycles/util/math.h +++ b/intern/cycles/util/math.h @@ -953,7 +953,11 @@ ccl_device_inline uint prev_power_of_two(uint x) ccl_device_inline uint32_t reverse_integer_bits(uint32_t x) { /* Use a native instruction if it exists. */ -#if defined(__aarch64__) || defined(_M_ARM64) +#if defined(__KERNEL_CUDA__) + return __brev(x); +#elif defined(__KERNEL_METAL__) + return reverse_bits(x); +#elif defined(__aarch64__) || defined(_M_ARM64) /* Assume the rbit is always available on 64bit ARM architecture. */ __asm__("rbit %w0, %w1" : "=r"(x) : "r"(x)); return x; @@ -962,10 +966,6 @@ ccl_device_inline uint32_t reverse_integer_bits(uint32_t x) * This 32-bit Thumb instruction is available in ARMv6T2 and above. */ __asm__("rbit %0, %1" : "=r"(x) : "r"(x)); return x; -#elif defined(__KERNEL_CUDA__) - return __brev(x); -#elif defined(__KERNEL_METAL__) - return reverse_bits(x); #elif __has_builtin(__builtin_bitreverse32) return __builtin_bitreverse32(x); #else diff --git a/intern/cycles/util/types.h b/intern/cycles/util/types.h index 031c2f7c4c1..26031d9e0fd 100644 --- a/intern/cycles/util/types.h +++ b/intern/cycles/util/types.h @@ -12,6 +12,7 @@ #if !defined(__KERNEL_GPU__) # include <stdint.h> +# include <stdio.h> #endif #include "util/defines.h" @@ -70,6 +71,12 @@ ccl_device_inline bool is_power_of_two(size_t x) CCL_NAMESPACE_END +/* Most GPU APIs matching native vector types, so we only need to implement them for + * CPU and oneAPI. */ +#if defined(__KERNEL_GPU__) && !defined(__KERNEL_ONEAPI__) +# define __KERNEL_NATIVE_VECTOR_TYPES__ +#endif + /* Vectorized types declaration. */ #include "util/types_uchar2.h" #include "util/types_uchar3.h" @@ -90,8 +97,6 @@ CCL_NAMESPACE_END #include "util/types_float4.h" #include "util/types_float8.h" -#include "util/types_vector3.h" - /* Vectorized types implementation. */ #include "util/types_uchar2_impl.h" #include "util/types_uchar3_impl.h" @@ -110,8 +115,6 @@ CCL_NAMESPACE_END #include "util/types_float4_impl.h" #include "util/types_float8_impl.h" -#include "util/types_vector3_impl.h" - /* SSE types. */ #ifndef __KERNEL_GPU__ # include "util/sseb.h" diff --git a/intern/cycles/util/types_float2.h b/intern/cycles/util/types_float2.h index 07b9ec0986b..f37aa1b4ad2 100644 --- a/intern/cycles/util/types_float2.h +++ b/intern/cycles/util/types_float2.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_FLOAT2_H__ -#define __UTIL_TYPES_FLOAT2_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,18 +9,18 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct float2 { float x, y; +# ifndef __KERNEL_GPU__ __forceinline float operator[](int i) const; __forceinline float &operator[](int i); +# endif }; ccl_device_inline float2 make_float2(float x, float y); ccl_device_inline void print_float2(const char *label, const float2 &a); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT2_H__ */ diff --git a/intern/cycles/util/types_float2_impl.h b/intern/cycles/util/types_float2_impl.h index 45fc90c52bd..9d1820fe17d 100644 --- a/intern/cycles/util/types_float2_impl.h +++ b/intern/cycles/util/types_float2_impl.h @@ -1,20 +1,16 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_FLOAT2_IMPL_H__ -#define __UTIL_TYPES_FLOAT2_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." #endif -#ifndef __KERNEL_GPU__ -# include <cstdio> -#endif - CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ __forceinline float float2::operator[](int i) const { util_assert(i >= 0); @@ -28,6 +24,7 @@ __forceinline float &float2::operator[](int i) util_assert(i < 2); return *(&x + i); } +# endif ccl_device_inline float2 make_float2(float x, float y) { @@ -39,8 +36,6 @@ ccl_device_inline void print_float2(const char *label, const float2 &a) { printf("%s: %.8f %.8f\n", label, (double)a.x, (double)a.y); } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT2_IMPL_H__ */ diff --git a/intern/cycles/util/types_float3.h b/intern/cycles/util/types_float3.h index c7900acaa69..4e43e928657 100644 --- a/intern/cycles/util/types_float3.h +++ b/intern/cycles/util/types_float3.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_FLOAT3_H__ -#define __UTIL_TYPES_FLOAT3_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,17 +9,28 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct ccl_try_align(16) float3 { -# ifdef __KERNEL_SSE__ +# ifdef __KERNEL_GPU__ + /* Compact structure for GPU. */ + float x, y, z; +# else + /* SIMD aligned structure for CPU. */ +# ifdef __KERNEL_SSE__ union { __m128 m128; struct { float x, y, z, w; }; }; +# else + float x, y, z, w; +# endif +# endif +# ifdef __KERNEL_SSE__ + /* Convenient constructors and operators for SIMD, otherwise default is enough. */ __forceinline float3(); __forceinline float3(const float3 &a); __forceinline explicit float3(const __m128 &a); @@ -29,18 +39,18 @@ struct ccl_try_align(16) float3 __forceinline operator __m128 &(); __forceinline float3 &operator=(const float3 &a); -# else /* __KERNEL_SSE__ */ - float x, y, z, w; -# endif /* __KERNEL_SSE__ */ +# endif +# ifndef __KERNEL_GPU__ __forceinline float operator[](int i) const; __forceinline float &operator[](int i); +# endif }; ccl_device_inline float3 make_float3(float f); ccl_device_inline float3 make_float3(float x, float y, float z); ccl_device_inline void print_float3(const char *label, const float3 &a); -#endif /* !defined(__KERNEL_GPU__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ /* Smaller float3 for storage. For math operations this must be converted to float3, so that on the * CPU SIMD instructions can be used. */ @@ -78,5 +88,3 @@ struct packed_float3 { static_assert(sizeof(packed_float3) == 12, "packed_float3 expected to be exactly 12 bytes"); CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT3_H__ */ diff --git a/intern/cycles/util/types_float3_impl.h b/intern/cycles/util/types_float3_impl.h index 2e6e864c8ea..cbd3f76dae4 100644 --- a/intern/cycles/util/types_float3_impl.h +++ b/intern/cycles/util/types_float3_impl.h @@ -1,20 +1,15 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_FLOAT3_IMPL_H__ -#define __UTIL_TYPES_FLOAT3_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." #endif -#ifndef __KERNEL_GPU__ -# include <cstdio> -#endif - CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ # ifdef __KERNEL_SSE__ __forceinline float3::float3() { @@ -45,6 +40,7 @@ __forceinline float3 &float3::operator=(const float3 &a) } # endif /* __KERNEL_SSE__ */ +# ifndef __KERNEL_GPU__ __forceinline float float3::operator[](int i) const { util_assert(i >= 0); @@ -58,23 +54,32 @@ __forceinline float &float3::operator[](int i) util_assert(i < 3); return *(&x + i); } +# endif ccl_device_inline float3 make_float3(float f) { -# ifdef __KERNEL_SSE__ - float3 a(_mm_set1_ps(f)); +# ifdef __KERNEL_GPU__ + float3 a = {f, f, f}; # else +# ifdef __KERNEL_SSE__ + float3 a(_mm_set1_ps(f)); +# else float3 a = {f, f, f, f}; +# endif # endif return a; } ccl_device_inline float3 make_float3(float x, float y, float z) { -# ifdef __KERNEL_SSE__ - float3 a(_mm_set_ps(0.0f, z, y, x)); +# ifdef __KERNEL_GPU__ + float3 a = {x, y, z}; # else +# ifdef __KERNEL_SSE__ + float3 a(_mm_set_ps(0.0f, z, y, x)); +# else float3 a = {x, y, z, 0.0f}; +# endif # endif return a; } @@ -83,8 +88,6 @@ ccl_device_inline void print_float3(const char *label, const float3 &a) { printf("%s: %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z); } -#endif /* !defined(__KERNEL_GPU__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT3_IMPL_H__ */ diff --git a/intern/cycles/util/types_float4.h b/intern/cycles/util/types_float4.h index 27453bf39e4..6b301c47362 100644 --- a/intern/cycles/util/types_float4.h +++ b/intern/cycles/util/types_float4.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_FLOAT4_H__ -#define __UTIL_TYPES_FLOAT4_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,7 +9,7 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct int4; struct ccl_try_align(16) float4 @@ -35,16 +34,16 @@ struct ccl_try_align(16) float4 float x, y, z, w; # endif /* __KERNEL_SSE__ */ +# ifndef __KERNEL_GPU__ __forceinline float operator[](int i) const; __forceinline float &operator[](int i); +# endif }; ccl_device_inline float4 make_float4(float f); ccl_device_inline float4 make_float4(float x, float y, float z, float w); ccl_device_inline float4 make_float4(const int4 &i); ccl_device_inline void print_float4(const char *label, const float4 &a); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT4_H__ */ diff --git a/intern/cycles/util/types_float4_impl.h b/intern/cycles/util/types_float4_impl.h index d7858f744e3..77b4fbff788 100644 --- a/intern/cycles/util/types_float4_impl.h +++ b/intern/cycles/util/types_float4_impl.h @@ -1,20 +1,15 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_FLOAT4_IMPL_H__ -#define __UTIL_TYPES_FLOAT4_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." #endif -#ifndef __KERNEL_GPU__ -# include <cstdio> -#endif - CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ # ifdef __KERNEL_SSE__ __forceinline float4::float4() { @@ -41,6 +36,7 @@ __forceinline float4 &float4::operator=(const float4 &a) } # endif /* __KERNEL_SSE__ */ +# ifndef __KERNEL_GPU__ __forceinline float float4::operator[](int i) const { util_assert(i >= 0); @@ -54,6 +50,7 @@ __forceinline float &float4::operator[](int i) util_assert(i < 4); return *(&x + i); } +# endif ccl_device_inline float4 make_float4(float f) { @@ -89,8 +86,6 @@ ccl_device_inline void print_float4(const char *label, const float4 &a) { printf("%s: %.8f %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z, (double)a.w); } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT4_IMPL_H__ */ diff --git a/intern/cycles/util/types_float8.h b/intern/cycles/util/types_float8.h index bb9798932ac..29fd632f08e 100644 --- a/intern/cycles/util/types_float8.h +++ b/intern/cycles/util/types_float8.h @@ -2,8 +2,7 @@ * Original code Copyright 2017, Intel Corporation * Modifications Copyright 2018-2022 Blender Foundation. */ -#ifndef __UTIL_TYPES_FLOAT8_H__ -#define __UTIL_TYPES_FLOAT8_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -12,7 +11,7 @@ CCL_NAMESPACE_BEGIN /* float8 is a reserved type in Metal that has not been implemented. For - * that reason this is named float8_t. */ + * that reason this is named float8_t and not using native vector types. */ #ifdef __KERNEL_GPU__ struct float8_t @@ -52,5 +51,3 @@ ccl_device_inline float8_t make_float8_t(float a, float b, float c, float d, float e, float f, float g, float h); CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT8_H__ */ diff --git a/intern/cycles/util/types_float8_impl.h b/intern/cycles/util/types_float8_impl.h index 2ab464a791b..e8576cdaf70 100644 --- a/intern/cycles/util/types_float8_impl.h +++ b/intern/cycles/util/types_float8_impl.h @@ -2,17 +2,12 @@ * Original code Copyright 2017, Intel Corporation * Modifications Copyright 2018-2022 Blender Foundation. */ -#ifndef __UTIL_TYPES_FLOAT8_IMPL_H__ -#define __UTIL_TYPES_FLOAT8_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." #endif -#ifndef __KERNEL_GPU__ -# include <cstdio> -#endif - CCL_NAMESPACE_BEGIN #ifdef __KERNEL_AVX2__ @@ -83,5 +78,3 @@ make_float8_t(float a, float b, float c, float d, float e, float f, float g, flo } CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_FLOAT8_IMPL_H__ */ diff --git a/intern/cycles/util/types_int2.h b/intern/cycles/util/types_int2.h index bf69cddc653..604713dffcd 100644 --- a/intern/cycles/util/types_int2.h +++ b/intern/cycles/util/types_int2.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_INT2_H__ -#define __UTIL_TYPES_INT2_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,17 +9,17 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct int2 { int x, y; +# ifndef __KERNEL_GPU__ __forceinline int operator[](int i) const; __forceinline int &operator[](int i); +# endif }; ccl_device_inline int2 make_int2(int x, int y); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_INT2_H__ */ diff --git a/intern/cycles/util/types_int2_impl.h b/intern/cycles/util/types_int2_impl.h index 7bdc77369ee..f48c6f46729 100644 --- a/intern/cycles/util/types_int2_impl.h +++ b/intern/cycles/util/types_int2_impl.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_INT2_IMPL_H__ -#define __UTIL_TYPES_INT2_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,7 +9,8 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ int int2::operator[](int i) const { util_assert(i >= 0); @@ -24,14 +24,13 @@ int &int2::operator[](int i) util_assert(i < 2); return *(&x + i); } +# endif ccl_device_inline int2 make_int2(int x, int y) { int2 a = {x, y}; return a; } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_INT2_IMPL_H__ */ diff --git a/intern/cycles/util/types_int3.h b/intern/cycles/util/types_int3.h index f88ff22ac35..3196b158ee9 100644 --- a/intern/cycles/util/types_int3.h +++ b/intern/cycles/util/types_int3.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_INT3_H__ -#define __UTIL_TYPES_INT3_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,10 +9,15 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct ccl_try_align(16) int3 { -# ifdef __KERNEL_SSE__ +# ifdef __KERNEL_GPU__ + /* Compact structure on the GPU. */ + int x, y, z; +# else + /* SIMD aligned structure for CPU. */ +# ifdef __KERNEL_SSE__ union { __m128i m128; struct { @@ -29,19 +33,20 @@ struct ccl_try_align(16) int3 __forceinline operator __m128i &(); __forceinline int3 &operator=(const int3 &a); -# else /* __KERNEL_SSE__ */ +# else /* __KERNEL_SSE__ */ int x, y, z, w; -# endif /* __KERNEL_SSE__ */ +# endif /* __KERNEL_SSE__ */ +# endif +# ifndef __KERNEL_GPU__ __forceinline int operator[](int i) const; __forceinline int &operator[](int i); +# endif }; ccl_device_inline int3 make_int3(int i); ccl_device_inline int3 make_int3(int x, int y, int z); ccl_device_inline void print_int3(const char *label, const int3 &a); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_INT3_H__ */ diff --git a/intern/cycles/util/types_int3_impl.h b/intern/cycles/util/types_int3_impl.h index 1c49e97ad32..abc0f4e4309 100644 --- a/intern/cycles/util/types_int3_impl.h +++ b/intern/cycles/util/types_int3_impl.h @@ -1,20 +1,15 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_INT3_IMPL_H__ -#define __UTIL_TYPES_INT3_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." #endif -#ifndef __KERNEL_GPU__ -# include <cstdio> -#endif - CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ # ifdef __KERNEL_SSE__ __forceinline int3::int3() { @@ -45,6 +40,7 @@ __forceinline int3 &int3::operator=(const int3 &a) } # endif /* __KERNEL_SSE__ */ +# ifndef __KERNEL_GPU__ __forceinline int int3::operator[](int i) const { util_assert(i >= 0); @@ -58,25 +54,33 @@ __forceinline int &int3::operator[](int i) util_assert(i < 3); return *(&x + i); } +# endif ccl_device_inline int3 make_int3(int i) { -# ifdef __KERNEL_SSE__ - int3 a(_mm_set1_epi32(i)); +# ifdef __KERNEL_GPU__ + int3 a = {i, i, i}; # else +# ifdef __KERNEL_SSE__ + int3 a(_mm_set1_epi32(i)); +# else int3 a = {i, i, i, i}; +# endif # endif return a; } ccl_device_inline int3 make_int3(int x, int y, int z) { -# ifdef __KERNEL_SSE__ - int3 a(_mm_set_epi32(0, z, y, x)); +# ifdef __KERNEL_GPU__ + int3 a = {x, y, z}; # else +# ifdef __KERNEL_SSE__ + int3 a(_mm_set_epi32(0, z, y, x)); +# else int3 a = {x, y, z, 0}; +# endif # endif - return a; } @@ -84,8 +88,6 @@ ccl_device_inline void print_int3(const char *label, const int3 &a) { printf("%s: %d %d %d\n", label, a.x, a.y, a.z); } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_INT3_IMPL_H__ */ diff --git a/intern/cycles/util/types_int4.h b/intern/cycles/util/types_int4.h index 9d557c01344..0ac53ffc09c 100644 --- a/intern/cycles/util/types_int4.h +++ b/intern/cycles/util/types_int4.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_INT4_H__ -#define __UTIL_TYPES_INT4_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,7 +9,7 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct float3; struct float4; @@ -37,8 +36,10 @@ struct ccl_try_align(16) int4 int x, y, z, w; # endif /* __KERNEL_SSE__ */ +# ifndef __KERNEL_GPU__ __forceinline int operator[](int i) const; __forceinline int &operator[](int i); +# endif }; ccl_device_inline int4 make_int4(int i); @@ -46,8 +47,6 @@ ccl_device_inline int4 make_int4(int x, int y, int z, int w); ccl_device_inline int4 make_int4(const float3 &f); ccl_device_inline int4 make_int4(const float4 &f); ccl_device_inline void print_int4(const char *label, const int4 &a); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_INT4_H__ */ diff --git a/intern/cycles/util/types_int4_impl.h b/intern/cycles/util/types_int4_impl.h index 11e1ede6705..2aab29df941 100644 --- a/intern/cycles/util/types_int4_impl.h +++ b/intern/cycles/util/types_int4_impl.h @@ -1,20 +1,15 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_INT4_IMPL_H__ -#define __UTIL_TYPES_INT4_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." #endif -#ifndef __KERNEL_GPU__ -# include <cstdio> -#endif - CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ # ifdef __KERNEL_SSE__ __forceinline int4::int4() { @@ -45,6 +40,7 @@ __forceinline int4 &int4::operator=(const int4 &a) } # endif /* __KERNEL_SSE__ */ +# ifndef __KERNEL_GPU__ __forceinline int int4::operator[](int i) const { util_assert(i >= 0); @@ -58,6 +54,7 @@ __forceinline int &int4::operator[](int i) util_assert(i < 4); return *(&x + i); } +# endif ccl_device_inline int4 make_int4(int i) { @@ -105,8 +102,6 @@ ccl_device_inline void print_int4(const char *label, const int4 &a) { printf("%s: %d %d %d %d\n", label, a.x, a.y, a.z, a.w); } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_INT4_IMPL_H__ */ diff --git a/intern/cycles/util/types_uchar2.h b/intern/cycles/util/types_uchar2.h index 0b3c9bd0331..ce617248e6e 100644 --- a/intern/cycles/util/types_uchar2.h +++ b/intern/cycles/util/types_uchar2.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UCHAR2_H__ -#define __UTIL_TYPES_UCHAR2_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,17 +9,17 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct uchar2 { uchar x, y; +# ifndef __KERNEL_GPU__ __forceinline uchar operator[](int i) const; __forceinline uchar &operator[](int i); +# endif }; ccl_device_inline uchar2 make_uchar2(uchar x, uchar y); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UCHAR2_H__ */ diff --git a/intern/cycles/util/types_uchar2_impl.h b/intern/cycles/util/types_uchar2_impl.h index a7254d5eaf2..9f3f3a4efb9 100644 --- a/intern/cycles/util/types_uchar2_impl.h +++ b/intern/cycles/util/types_uchar2_impl.h @@ -10,7 +10,8 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ uchar uchar2::operator[](int i) const { util_assert(i >= 0); @@ -24,13 +25,14 @@ uchar &uchar2::operator[](int i) util_assert(i < 2); return *(&x + i); } +# endif ccl_device_inline uchar2 make_uchar2(uchar x, uchar y) { uchar2 a = {x, y}; return a; } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/util/types_uchar3.h b/intern/cycles/util/types_uchar3.h index fc213502ada..aed04c4775e 100644 --- a/intern/cycles/util/types_uchar3.h +++ b/intern/cycles/util/types_uchar3.h @@ -10,16 +10,18 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct uchar3 { uchar x, y, z; +# ifndef __KERNEL_GPU__ __forceinline uchar operator[](int i) const; __forceinline uchar &operator[](int i); +# endif }; ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/util/types_uchar3_impl.h b/intern/cycles/util/types_uchar3_impl.h index 0c24ffb488a..83eb3c99b3c 100644 --- a/intern/cycles/util/types_uchar3_impl.h +++ b/intern/cycles/util/types_uchar3_impl.h @@ -10,7 +10,8 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ uchar uchar3::operator[](int i) const { util_assert(i >= 0); @@ -24,13 +25,14 @@ uchar &uchar3::operator[](int i) util_assert(i < 3); return *(&x + i); } +# endif ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z) { uchar3 a = {x, y, z}; return a; } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/util/types_uchar4.h b/intern/cycles/util/types_uchar4.h index a2a2c945aaa..fb13a98875e 100644 --- a/intern/cycles/util/types_uchar4.h +++ b/intern/cycles/util/types_uchar4.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UCHAR4_H__ -#define __UTIL_TYPES_UCHAR4_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,17 +9,17 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct uchar4 { uchar x, y, z, w; +# ifndef __KERNEL_GPU__ __forceinline uchar operator[](int i) const; __forceinline uchar &operator[](int i); +# endif }; ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UCHAR4_H__ */ diff --git a/intern/cycles/util/types_uchar4_impl.h b/intern/cycles/util/types_uchar4_impl.h index 8ec6213a37d..244bb98f883 100644 --- a/intern/cycles/util/types_uchar4_impl.h +++ b/intern/cycles/util/types_uchar4_impl.h @@ -10,7 +10,8 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ uchar uchar4::operator[](int i) const { util_assert(i >= 0); @@ -24,13 +25,14 @@ uchar &uchar4::operator[](int i) util_assert(i < 4); return *(&x + i); } +# endif ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w) { uchar4 a = {x, y, z, w}; return a; } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/util/types_uint2.h b/intern/cycles/util/types_uint2.h index faa0955f903..4d76b628088 100644 --- a/intern/cycles/util/types_uint2.h +++ b/intern/cycles/util/types_uint2.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UINT2_H__ -#define __UTIL_TYPES_UINT2_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,17 +9,17 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct uint2 { uint x, y; +# ifndef __KERNEL_GPU__ __forceinline uint operator[](uint i) const; __forceinline uint &operator[](uint i); +# endif }; ccl_device_inline uint2 make_uint2(uint x, uint y); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UINT2_H__ */ diff --git a/intern/cycles/util/types_uint2_impl.h b/intern/cycles/util/types_uint2_impl.h index cac0ba6b531..b508aaf2543 100644 --- a/intern/cycles/util/types_uint2_impl.h +++ b/intern/cycles/util/types_uint2_impl.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UINT2_IMPL_H__ -#define __UTIL_TYPES_UINT2_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,7 +9,8 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ __forceinline uint uint2::operator[](uint i) const { util_assert(i < 2); @@ -22,14 +22,13 @@ __forceinline uint &uint2::operator[](uint i) util_assert(i < 2); return *(&x + i); } +# endif ccl_device_inline uint2 make_uint2(uint x, uint y) { uint2 a = {x, y}; return a; } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UINT2_IMPL_H__ */ diff --git a/intern/cycles/util/types_uint3.h b/intern/cycles/util/types_uint3.h index 3ff87bfc791..b1571716fc7 100644 --- a/intern/cycles/util/types_uint3.h +++ b/intern/cycles/util/types_uint3.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UINT3_H__ -#define __UTIL_TYPES_UINT3_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,17 +9,17 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct uint3 { uint x, y, z; +# ifndef __KERNEL_GPU__ __forceinline uint operator[](uint i) const; __forceinline uint &operator[](uint i); +# endif }; ccl_device_inline uint3 make_uint3(uint x, uint y, uint z); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UINT3_H__ */ diff --git a/intern/cycles/util/types_uint3_impl.h b/intern/cycles/util/types_uint3_impl.h index 221883a1adb..d36c9f52de9 100644 --- a/intern/cycles/util/types_uint3_impl.h +++ b/intern/cycles/util/types_uint3_impl.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UINT3_IMPL_H__ -#define __UTIL_TYPES_UINT3_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,7 +9,8 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ __forceinline uint uint3::operator[](uint i) const { util_assert(i < 3); @@ -22,14 +22,13 @@ __forceinline uint &uint3::operator[](uint i) util_assert(i < 3); return *(&x + i); } +# endif ccl_device_inline uint3 make_uint3(uint x, uint y, uint z) { uint3 a = {x, y, z}; return a; } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UINT3_IMPL_H__ */ diff --git a/intern/cycles/util/types_uint4.h b/intern/cycles/util/types_uint4.h index 504095b2383..4982b30f577 100644 --- a/intern/cycles/util/types_uint4.h +++ b/intern/cycles/util/types_uint4.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UINT4_H__ -#define __UTIL_TYPES_UINT4_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,17 +9,17 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct uint4 { uint x, y, z, w; +# ifndef __KERNEL_GPU__ __forceinline uint operator[](uint i) const; __forceinline uint &operator[](uint i); +# endif }; ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w); -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UINT4_H__ */ diff --git a/intern/cycles/util/types_uint4_impl.h b/intern/cycles/util/types_uint4_impl.h index d78db944a1f..1cfdb9e0992 100644 --- a/intern/cycles/util/types_uint4_impl.h +++ b/intern/cycles/util/types_uint4_impl.h @@ -1,8 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#ifndef __UTIL_TYPES_UINT4_IMPL_H__ -#define __UTIL_TYPES_UINT4_IMPL_H__ +#pragma once #ifndef __UTIL_TYPES_H__ # error "Do not include this file directly, include util/types.h instead." @@ -10,7 +9,8 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifndef __KERNEL_GPU__ __forceinline uint uint4::operator[](uint i) const { util_assert(i < 3); @@ -22,14 +22,13 @@ __forceinline uint &uint4::operator[](uint i) util_assert(i < 3); return *(&x + i); } +# endif ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w) { uint4 a = {x, y, z, w}; return a; } -#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */ +#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */ CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_UINT4_IMPL_H__ */ diff --git a/intern/cycles/util/types_ushort4.h b/intern/cycles/util/types_ushort4.h index 9a6e12095ba..aef36f63285 100644 --- a/intern/cycles/util/types_ushort4.h +++ b/intern/cycles/util/types_ushort4.h @@ -10,7 +10,7 @@ CCL_NAMESPACE_BEGIN -#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) +#ifndef __KERNEL_NATIVE_VECTOR_TYPES__ struct ushort4 { uint16_t x, y, z, w; diff --git a/intern/cycles/util/types_vector3.h b/intern/cycles/util/types_vector3.h deleted file mode 100644 index 2e0d68e1bd0..00000000000 --- a/intern/cycles/util/types_vector3.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -#ifndef __UTIL_TYPES_VECTOR3_H__ -#define __UTIL_TYPES_VECTOR3_H__ - -#ifndef __UTIL_TYPES_H__ -# error "Do not include this file directly, include util/types.h instead." -#endif - -CCL_NAMESPACE_BEGIN - -#ifndef __KERNEL_GPU__ -template<typename T> class vector3 { - public: - T x, y, z; - - __forceinline vector3(); - __forceinline vector3(const T &a); - __forceinline vector3(const T &x, const T &y, const T &z); -}; -#endif /* __KERNEL_GPU__ */ - -CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_VECTOR3_H__ */ diff --git a/intern/cycles/util/types_vector3_impl.h b/intern/cycles/util/types_vector3_impl.h deleted file mode 100644 index a765780e2d3..00000000000 --- a/intern/cycles/util/types_vector3_impl.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -#ifndef __UTIL_TYPES_VECTOR3_IMPL_H__ -#define __UTIL_TYPES_VECTOR3_IMPL_H__ - -#ifndef __UTIL_TYPES_H__ -# error "Do not include this file directly, include util/types.h instead." -#endif - -CCL_NAMESPACE_BEGIN - -#ifndef __KERNEL_GPU__ -template<typename T> ccl_always_inline vector3<T>::vector3() -{ -} - -template<typename T> ccl_always_inline vector3<T>::vector3(const T &a) : x(a), y(a), z(a) -{ -} - -template<typename T> -ccl_always_inline vector3<T>::vector3(const T &x, const T &y, const T &z) : x(x), y(y), z(z) -{ -} -#endif /* __KERNEL_GPU__ */ - -CCL_NAMESPACE_END - -#endif /* __UTIL_TYPES_VECTOR3_IMPL_H__ */ diff --git a/release/datafiles/fonts/DejaVuSans.woff2 b/release/datafiles/fonts/DejaVuSans.woff2 Binary files differnew file mode 100644 index 00000000000..a391596a421 --- /dev/null +++ b/release/datafiles/fonts/DejaVuSans.woff2 diff --git a/release/datafiles/fonts/DejaVuSansMono.woff2 b/release/datafiles/fonts/DejaVuSansMono.woff2 Binary files differnew file mode 100644 index 00000000000..cf200e12fff --- /dev/null +++ b/release/datafiles/fonts/DejaVuSansMono.woff2 diff --git a/release/datafiles/fonts/MaterialIcons-Variable.woff2 b/release/datafiles/fonts/MaterialIcons-Variable.woff2 Binary files differnew file mode 100644 index 00000000000..048802a6454 --- /dev/null +++ b/release/datafiles/fonts/MaterialIcons-Variable.woff2 diff --git a/release/datafiles/fonts/Noto Sans CJK Regular.woff2 b/release/datafiles/fonts/Noto Sans CJK Regular.woff2 Binary files differnew file mode 100644 index 00000000000..5d3854b6bf7 --- /dev/null +++ b/release/datafiles/fonts/Noto Sans CJK Regular.woff2 diff --git a/release/datafiles/fonts/NotoEmoji-VariableFont_wght.woff2 b/release/datafiles/fonts/NotoEmoji-VariableFont_wght.woff2 Binary files differnew file mode 100644 index 00000000000..4d019787bca --- /dev/null +++ b/release/datafiles/fonts/NotoEmoji-VariableFont_wght.woff2 diff --git a/release/datafiles/fonts/NotoSansArabic-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansArabic-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..8ee78b73e72 --- /dev/null +++ b/release/datafiles/fonts/NotoSansArabic-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansArmenian-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansArmenian-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..c6c1ed5c2cf --- /dev/null +++ b/release/datafiles/fonts/NotoSansArmenian-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansBengali-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansBengali-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..cdac12cc8e8 --- /dev/null +++ b/release/datafiles/fonts/NotoSansBengali-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansDevanagari-Regular.woff2 b/release/datafiles/fonts/NotoSansDevanagari-Regular.woff2 Binary files differnew file mode 100644 index 00000000000..2cb157b2c51 --- /dev/null +++ b/release/datafiles/fonts/NotoSansDevanagari-Regular.woff2 diff --git a/release/datafiles/fonts/NotoSansEthiopic-Regular.woff2 b/release/datafiles/fonts/NotoSansEthiopic-Regular.woff2 Binary files differnew file mode 100644 index 00000000000..dc272d98964 --- /dev/null +++ b/release/datafiles/fonts/NotoSansEthiopic-Regular.woff2 diff --git a/release/datafiles/fonts/NotoSansGeorgian-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansGeorgian-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..4ebc52f0b59 --- /dev/null +++ b/release/datafiles/fonts/NotoSansGeorgian-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansGujarati-Regular.woff2 b/release/datafiles/fonts/NotoSansGujarati-Regular.woff2 Binary files differnew file mode 100644 index 00000000000..6e66a15b1cd --- /dev/null +++ b/release/datafiles/fonts/NotoSansGujarati-Regular.woff2 diff --git a/release/datafiles/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..e752468775f --- /dev/null +++ b/release/datafiles/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansHebrew-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansHebrew-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..4f6033c916f --- /dev/null +++ b/release/datafiles/fonts/NotoSansHebrew-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansJavanese-Regular.woff2 b/release/datafiles/fonts/NotoSansJavanese-Regular.woff2 Binary files differnew file mode 100644 index 00000000000..aeb0bbe8dab --- /dev/null +++ b/release/datafiles/fonts/NotoSansJavanese-Regular.woff2 diff --git a/release/datafiles/fonts/NotoSansKannada-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansKannada-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..56fbd8d8bce --- /dev/null +++ b/release/datafiles/fonts/NotoSansKannada-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansMalayalam-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansMalayalam-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..bdbce8a0b76 --- /dev/null +++ b/release/datafiles/fonts/NotoSansMalayalam-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansMath-Regular.woff2 b/release/datafiles/fonts/NotoSansMath-Regular.woff2 Binary files differnew file mode 100644 index 00000000000..bb3baafeb7a --- /dev/null +++ b/release/datafiles/fonts/NotoSansMath-Regular.woff2 diff --git a/release/datafiles/fonts/NotoSansMyanmar-Regular.woff2 b/release/datafiles/fonts/NotoSansMyanmar-Regular.woff2 Binary files differnew file mode 100644 index 00000000000..f18edac80ed --- /dev/null +++ b/release/datafiles/fonts/NotoSansMyanmar-Regular.woff2 diff --git a/release/datafiles/fonts/NotoSansSymbols-VariableFont_wght.woff2 b/release/datafiles/fonts/NotoSansSymbols-VariableFont_wght.woff2 Binary files differnew file mode 100644 index 00000000000..98f940b813e --- /dev/null +++ b/release/datafiles/fonts/NotoSansSymbols-VariableFont_wght.woff2 diff --git a/release/datafiles/fonts/NotoSansSymbols2-Regular.woff2 b/release/datafiles/fonts/NotoSansSymbols2-Regular.woff2 Binary files differnew file mode 100644 index 00000000000..cefcc2d9c0d --- /dev/null +++ b/release/datafiles/fonts/NotoSansSymbols2-Regular.woff2 diff --git a/release/datafiles/fonts/NotoSansTamil-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansTamil-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..a3541942429 --- /dev/null +++ b/release/datafiles/fonts/NotoSansTamil-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansTelugu-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansTelugu-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..790235d3a71 --- /dev/null +++ b/release/datafiles/fonts/NotoSansTelugu-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/NotoSansThai-VariableFont_wdth,wght.woff2 b/release/datafiles/fonts/NotoSansThai-VariableFont_wdth,wght.woff2 Binary files differnew file mode 100644 index 00000000000..507255e6b5c --- /dev/null +++ b/release/datafiles/fonts/NotoSansThai-VariableFont_wdth,wght.woff2 diff --git a/release/datafiles/fonts/bmonofont-i18n.ttf b/release/datafiles/fonts/bmonofont-i18n.ttf Binary files differdeleted file mode 100644 index 08b3f723d61..00000000000 --- a/release/datafiles/fonts/bmonofont-i18n.ttf +++ /dev/null diff --git a/release/datafiles/fonts/droidsans.ttf b/release/datafiles/fonts/droidsans.ttf Binary files differdeleted file mode 100644 index b03e47f087e..00000000000 --- a/release/datafiles/fonts/droidsans.ttf +++ /dev/null diff --git a/release/datafiles/fonts/lastresort.woff2 b/release/datafiles/fonts/lastresort.woff2 Binary files differnew file mode 100644 index 00000000000..e5ad6f353f5 --- /dev/null +++ b/release/datafiles/fonts/lastresort.woff2 diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py index df4ca9ef170..ff9b5a06fb7 100644 --- a/release/scripts/startup/bl_operators/node.py +++ b/release/scripts/startup/bl_operators/node.py @@ -149,37 +149,6 @@ class NODE_OT_add_node(NodeAddOperator, Operator): bl_options = {'REGISTER', 'UNDO'} -# Add a node and link it to an existing socket -class NODE_OT_add_and_link_node(NodeAddOperator, Operator): - '''Add a node to the active tree and link to an existing socket''' - bl_idname = "node.add_and_link_node" - bl_label = "Add and Link Node" - bl_options = {'REGISTER', 'UNDO'} - - link_socket_index: IntProperty( - name="Link Socket Index", - description="Index of the socket to link", - ) - - def execute(self, context): - space = context.space_data - ntree = space.edit_tree - - node = self.create_node(context) - if not node: - return {'CANCELLED'} - - to_socket = getattr(context, "link_to_socket", None) - if to_socket: - ntree.links.new(node.outputs[self.link_socket_index], to_socket) - - from_socket = getattr(context, "link_from_socket", None) - if from_socket: - ntree.links.new(from_socket, node.inputs[self.link_socket_index]) - - return {'FINISHED'} - - class NODE_OT_add_search(NodeAddOperator, Operator): '''Add a node to the active tree''' bl_idname = "node.add_search" @@ -306,7 +275,6 @@ class NODE_OT_tree_path_parent(Operator): classes = ( NodeSetting, - NODE_OT_add_and_link_node, NODE_OT_add_node, NODE_OT_add_search, NODE_OT_collapse_hide_unused_toggle, diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index e031b32247a..062476f2624 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -162,6 +162,35 @@ class RENDER_PT_eevee_motion_blur(RenderButtonsPanel, Panel): col.prop(props, "motion_blur_steps", text="Steps") +class RENDER_PT_eevee_next_motion_blur(RenderButtonsPanel, Panel): + bl_label = "Motion Blur" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE_NEXT'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_motion_blur", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene + props = scene.eevee + + layout.active = props.use_motion_blur + col = layout.column() + col.prop(props, "motion_blur_position", text="Position") + col.prop(props, "motion_blur_shutter") + col.separator() + col.prop(props, "motion_blur_depth_scale") + col.prop(props, "motion_blur_steps", text="Steps") + + class RENDER_PT_eevee_depth_of_field(RenderButtonsPanel, Panel): bl_label = "Depth of Field" bl_options = {'DEFAULT_CLOSED'} @@ -756,6 +785,7 @@ classes = ( RENDER_PT_eevee_film, RENDER_PT_eevee_next_sampling, + RENDER_PT_eevee_next_motion_blur, RENDER_PT_eevee_next_film, RENDER_PT_gpencil, diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 01bd0adc8df..78aec096510 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -79,6 +79,7 @@ class VIEWLAYER_PT_eevee_next_layer_passes_data(ViewLayerButtonsPanel, Panel): layout.use_property_split = True layout.use_property_decorate = False + scene = context.scene view_layer = context.view_layer col = layout.column() @@ -87,7 +88,9 @@ class VIEWLAYER_PT_eevee_next_layer_passes_data(ViewLayerButtonsPanel, Panel): col.prop(view_layer, "use_pass_mist") col.prop(view_layer, "use_pass_normal") col.prop(view_layer, "use_pass_position") - col.prop(view_layer, "use_pass_vector") + sub = col.column() + sub.active = not scene.eevee.use_motion_blur + sub.prop(view_layer, "use_pass_vector") class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel): diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 83ca9158efc..75824ae056f 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -18,10 +18,10 @@ extern "C" { #define BLF_DATAFILES_FONTS_DIR "fonts" /* File name of the default variable-width font. */ -#define BLF_DEFAULT_PROPORTIONAL_FONT "droidsans.ttf" +#define BLF_DEFAULT_PROPORTIONAL_FONT "DejaVuSans.woff2" /* File name of the default fixed-pitch font. */ -#define BLF_DEFAULT_MONOSPACED_FONT "bmonofont-i18n.ttf" +#define BLF_DEFAULT_MONOSPACED_FONT "DejaVuSansMono.woff2" /* enable this only if needed (unused circa 2016) */ #define BLF_BLUR_ENABLE 0 @@ -351,6 +351,8 @@ enum { BLF_DEFAULT = 1 << 14, /** Must only be used as last font in the stack. */ BLF_LAST_RESORT = 1 << 15, + /** Failure to load this font. Don't try again. */ + BLF_BAD_FONT = 1 << 16, }; #define BLF_DRAW_STR_DUMMY_MAX 1024 diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 038e73cc928..eb974f33994 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -18,8 +18,9 @@ #include FT_FREETYPE_H #include FT_GLYPH_H -#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */ #include FT_MULTIPLE_MASTERS_H /* Variable font support. */ +#include FT_TRUETYPE_IDS_H /* Codepoint coverage constants. */ +#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */ #include "MEM_guardedalloc.h" @@ -28,6 +29,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_math_color_blend.h" +#include "BLI_path_util.h" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_string_utf8.h" @@ -836,7 +838,7 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, size_t i = 0, i_curr; rcti gbox_px; - if (str_len == 0) { + if (str_len == 0 || str[0] == 0) { /* early output. */ return; } @@ -1157,7 +1159,7 @@ int blf_font_ascender(FontBLF *font) char *blf_display_name(FontBLF *font) { - if (!font->face->family_name) { + if (!blf_ensure_face(font) || !font->face->family_name) { return NULL; } return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name); @@ -1244,14 +1246,28 @@ static void blf_font_fill(FontBLF *font) font->glyph_cache_mutex = &blf_glyph_cache_mutex; } -FontBLF *blf_font_new(const char *name, const char *filepath) +/** + * Create an FT_Face for this font if not already existing. + */ +bool blf_ensure_face(FontBLF *font) { - FontBLF *font; + if (font->face) { + return true; + } + + if (font->flags & BLF_BAD_FONT) { + return false; + } + FT_Error err; - char *mfile; - font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); - err = FT_New_Face(ft_lib, filepath, 0, &font->face); + if (font->filepath) { + err = FT_New_Face(ft_lib, font->filepath, 0, &font->face); + } + if (font->mem) { + err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face); + } + if (err) { if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) { printf("Format of this font file is not supported\n"); @@ -1259,8 +1275,8 @@ FontBLF *blf_font_new(const char *name, const char *filepath) else { printf("Error encountered while opening font file\n"); } - MEM_freeN(font); - return NULL; + font->flags |= BLF_BAD_FONT; + return false; } err = FT_Select_Charmap(font->face, FT_ENCODING_UNICODE); @@ -1272,28 +1288,28 @@ FontBLF *blf_font_new(const char *name, const char *filepath) } if (err) { printf("Can't set a character map!\n"); - FT_Done_Face(font->face); - MEM_freeN(font); - return NULL; + font->flags |= BLF_BAD_FONT; + return false; } - mfile = blf_dir_metrics_search(filepath); - if (mfile) { - err = FT_Attach_File(font->face, mfile); - if (err) { - fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filepath, (int)err); + if (font->filepath) { + char *mfile = blf_dir_metrics_search(font->filepath); + if (mfile) { + err = FT_Attach_File(font->face, mfile); + if (err) { + fprintf(stderr, + "FT_Attach_File failed to load '%s' with error %d\n", + font->filepath, + (int)err); + } + MEM_freeN(mfile); } - MEM_freeN(mfile); } if (FT_HAS_MULTIPLE_MASTERS(font->face)) { FT_Get_MM_Var(font->face, &(font->variations)); } - font->name = BLI_strdup(name); - font->filepath = BLI_strdup(filepath); - blf_font_fill(font); - /* Save TrueType table with bits to quickly test most unicode block coverage. */ TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2); if (os2_table) { @@ -1303,17 +1319,11 @@ FontBLF *blf_font_new(const char *name, const char *filepath) font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4; } - /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ - if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU && - font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) { - font->flags |= BLF_LAST_RESORT; - } - if (FT_IS_FIXED_WIDTH(font->face)) { font->flags |= BLF_MONOSPACED; } - if (FT_HAS_KERNING(font->face)) { + if (FT_HAS_KERNING(font->face) && !font->kerning_cache) { /* Create kerning cache table and fill with value indicating "unset". */ font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__); for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { @@ -1323,49 +1333,114 @@ FontBLF *blf_font_new(const char *name, const char *filepath) } } - return font; + return true; } -void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size) +typedef struct eFaceDetails { + char name[50]; + unsigned int coverage1; + unsigned int coverage2; + unsigned int coverage3; + unsigned int coverage4; +} eFaceDetails; + +/* Details about the fallback fonts we ship, so that we can load only when needed. */ +static const eFaceDetails static_face_details[] = { + {"lastresort.woff2", UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}, + {"Noto Sans CJK Regular.woff2", 0x30000083L, 0x2BDF3C10L, 0x16L, 0}, + {"NotoEmoji-VariableFont_wght.woff2", 0x80000003L, 0x241E4ACL, 0x14000000L, 0x4000000L}, + {"NotoSansArabic-VariableFont_wdth,wght.woff2", TT_UCR_ARABIC, 0, 0, 0}, + {"NotoSansArmenian-VariableFont_wdth,wght.woff2", + TT_UCR_ARMENIAN, + TT_UCR_ALPHABETIC_PRESENTATION_FORMS, + 0, + 0}, + {"NotoSansBengali-VariableFont_wdth,wght.woff2", TT_UCR_BENGALI, 0, 0, 0}, + {"NotoSansDevanagari-Regular.woff2", TT_UCR_DEVANAGARI, 0, 0, 0}, + {"NotoSansEthiopic-Regular.woff2", 0, 0, TT_UCR_ETHIOPIC, 0}, + {"NotoSansGeorgian-VariableFont_wdth,wght.woff2", TT_UCR_GEORGIAN, 0, 0, 0}, + {"NotoSansGujarati-Regular.woff2", TT_UCR_GUJARATI, 0, 0, 0}, + {"NotoSansGurmukhi-VariableFont_wdth,wght.woff2", TT_UCR_GURMUKHI, 0, 0, 0}, + {"NotoSansHebrew-VariableFont_wdth,wght.woff2", TT_UCR_HEBREW, 0, 0, 0}, + {"NotoSansJavanese-Regular.woff2", 0x80000003L, 0x2000L, 0, 0}, + {"NotoSansKannada-VariableFont_wdth,wght.woff2", TT_UCR_KANNADA, 0, 0, 0}, + {"NotoSansMalayalam-VariableFont_wdth,wght.woff2", TT_UCR_MALAYALAM, 0, 0, 0}, + {"NotoSansMath-Regular.woff2", 0, TT_UCR_MATHEMATICAL_OPERATORS, 0, 0}, + {"NotoSansMyanmar-Regular.woff2", 0, 0, TT_UCR_MYANMAR, 0}, + {"NotoSansSymbols-VariableFont_wght.woff2", 0x3L, 0x200E4B4L, 0, 0}, + {"NotoSansSymbols2-Regular.woff2", 0x80000003L, 0x200E3E4L, 0x40020L, 0x580A048L}, + {"NotoSansTamil-VariableFont_wdth,wght.woff2", TT_UCR_TAMIL, 0, 0, 0}, + {"NotoSansTelugu-VariableFont_wdth,wght.woff2", TT_UCR_TELUGU, 0, 0, 0}, + {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0}, +}; + +/* Create a new font from filename OR from passed memory pointer. */ +static FontBLF *blf_font_new_ex(const char *name, + const char *filepath, + const unsigned char *mem, + const size_t mem_size) { - FT_Open_Args open; + FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); - open.flags = FT_OPEN_MEMORY; - open.memory_base = (const FT_Byte *)mem; - open.memory_size = mem_size; - FT_Attach_Stream(font->face, &open); -} - -FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size) -{ - FontBLF *font; - FT_Error err; + font->name = BLI_strdup(name); + font->filepath = filepath ? BLI_strdup(filepath) : NULL; + if (mem) { + font->mem = (void *)mem; + font->mem_size = mem_size; + } + blf_font_fill(font); - font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new_from_mem"); - err = FT_New_Memory_Face(ft_lib, mem, mem_size, 0, &font->face); - if (err) { - MEM_freeN(font); - return NULL; + /* If we have static details about this font we don't need to load the Face. */ + const eFaceDetails *static_details = NULL; + char filename[256]; + for (int i = 0; i < (int)ARRAY_SIZE(static_face_details); i++) { + BLI_split_file_part(font->filepath, filename, sizeof(filename)); + if (STREQ(static_face_details[i].name, filename)) { + static_details = &static_face_details[i]; + font->UnicodeRanges[0] = static_details->coverage1; + font->UnicodeRanges[1] = static_details->coverage2; + font->UnicodeRanges[2] = static_details->coverage3; + font->UnicodeRanges[3] = static_details->coverage4; + break; + } } - err = FT_Select_Charmap(font->face, ft_encoding_unicode); - if (err) { - printf("Can't set the unicode character map!\n"); - FT_Done_Face(font->face); - MEM_freeN(font); - return NULL; + if (!static_details) { + if (!blf_ensure_face(font)) { + blf_font_free(font); + return NULL; + } } - if (FT_HAS_MULTIPLE_MASTERS(font->face)) { - FT_Get_MM_Var(font->face, &(font->variations)); + /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ + if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU && + font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) { + font->flags |= BLF_LAST_RESORT; } - font->name = BLI_strdup(name); - font->filepath = NULL; - blf_font_fill(font); return font; } +FontBLF *blf_font_new(const char *name, const char *filename) +{ + return blf_font_new_ex(name, filename, NULL, 0); +} + +FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, const size_t mem_size) +{ + return blf_font_new_ex(name, NULL, mem, mem_size); +} + +void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, const size_t mem_size) +{ + FT_Open_Args open; + + open.flags = FT_OPEN_MEMORY; + open.memory_base = (const FT_Byte *)mem; + open.memory_size = (FT_Long)mem_size; + FT_Attach_Stream(font->face, &open); +} + void blf_font_free(FontBLF *font) { blf_glyph_cache_clear(font); @@ -1378,7 +1453,9 @@ void blf_font_free(FontBLF *font) FT_Done_MM_Var(ft_lib, font->variations); } - FT_Done_Face(font->face); + if (font->face) { + FT_Done_Face(font->face); + } if (font->filepath) { MEM_freeN(font->filepath); } @@ -1396,6 +1473,10 @@ void blf_font_free(FontBLF *font) bool blf_font_size(FontBLF *font, float size, unsigned int dpi) { + if (!blf_ensure_face(font)) { + return false; + } + /* FreeType uses fixed-point integers in 64ths. */ FT_F26Dot6 ft_size = lroundf(size * 64.0f); /* Adjust our new size to be on even 64ths. */ diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index 1bde25b5776..63957fad003 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -66,8 +66,6 @@ void BLF_load_font_stack() } else { BLF_enable(font_id, BLF_DEFAULT); - /* TODO: FontBLF will later load FT_Face on demand. When this is in - * place we can drop this face now since we have all needed data. */ } } } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 215f79e6795..48ddbc9f920 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -584,16 +584,22 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode continue; } if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) { - glyph_index = FT_Get_Char_Index(f->face, charcode); - if (glyph_index) { - *font = f; - return glyph_index; + if (blf_ensure_face(f)) { + glyph_index = FT_Get_Char_Index(f->face, charcode); + if (glyph_index) { + *font = f; + return glyph_index; + } } } } +#ifdef DEBUG + printf("Unicode character U+%04X not found in loaded fonts. \n", charcode); +#endif + /* Not found in the stack, return from Last Resort if there is one. */ - if (last_resort) { + if (last_resort && blf_ensure_face(last_resort)) { glyph_index = FT_Get_Char_Index(last_resort->face, charcode); if (glyph_index) { *font = last_resort; diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 84037ff4bd0..6207edb0107 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -39,12 +39,14 @@ void blf_font_exit(void); bool blf_font_id_is_valid(int fontid); +bool blf_ensure_face(struct FontBLF *font); + void blf_draw_buffer__start(struct FontBLF *font); void blf_draw_buffer__end(void); struct FontBLF *blf_font_new(const char *name, const char *filepath); -struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size); -void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); +struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, size_t mem_size); +void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, size_t mem_size); /** * Change font's output size. Returns true if successful in changing the size. diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 5b55f4af0b8..018cef4540f 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -240,9 +240,13 @@ typedef struct FontBLF { /* # of times this font was loaded */ unsigned int reference_count; - /** File-path or NULL. */ + /* Full path to font file or NULL if from memory. */ char *filepath; + /* Pointer to in-memory font, or NULL if from file. */ + void *mem; + size_t mem_size; + /* Copied from the SFNT OS/2 table. Bit flags for unicode blocks and ranges * considered "functional". Cached here because face might not always exist. * See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur */ diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 3f7d9498e39..c14da538e7c 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -7,6 +7,7 @@ */ #include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" #ifdef __cplusplus extern "C" { @@ -19,6 +20,7 @@ struct BlendWriter; struct ID; struct IDProperty; struct IDPropertyUIData; +struct Library; typedef union IDPropertyTemplate { int i; @@ -318,7 +320,7 @@ void IDP_BlendReadData_impl(struct BlendDataReader *reader, struct IDProperty **prop, const char *caller_func_id); #define IDP_BlendDataRead(reader, prop) IDP_BlendReadData_impl(reader, prop, __func__) -void IDP_BlendReadLib(struct BlendLibReader *reader, struct IDProperty *prop); +void IDP_BlendReadLib(struct BlendLibReader *reader, struct Library *lib, struct IDProperty *prop); void IDP_BlendReadExpand(struct BlendExpander *expander, struct IDProperty *prop); typedef enum eIDPropertyUIDataType { diff --git a/source/blender/blenkernel/BKE_idprop.hh b/source/blender/blenkernel/BKE_idprop.hh index 1e741cc252f..6a42ab1669f 100644 --- a/source/blender/blenkernel/BKE_idprop.hh +++ b/source/blender/blenkernel/BKE_idprop.hh @@ -45,6 +45,9 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, d std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, const StringRefNull value); +/** \brief Allocate a new IDProperty of type IDP_ID, set its name and value. */ +std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, ID *id); + /** * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_INT. * diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 90dbec7ec52..02e3cefe6a5 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -374,6 +374,9 @@ typedef struct bNodeTreeType { int type; /* type identifier */ char idname[64]; /* identifier name */ + /* The ID name of group nodes for this type. */ + char group_idname[64]; + char ui_name[64]; char ui_description[256]; int ui_icon; diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 162459d2005..8b9deadc960 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -13,6 +13,7 @@ #include "DNA_object_enums.h" #include "BKE_attribute.h" +#include "BKE_pbvh.h" #ifdef __cplusplus extern "C" { @@ -397,7 +398,7 @@ typedef struct SculptVertexInfo { typedef struct SculptBoundaryEditInfo { /* Vertex index from where the topology propagation reached this vertex. */ - int original_vertex; + int original_vertex_i; /* How many steps were needed to reach this vertex from the boundary. */ int num_propagation_steps; @@ -408,13 +409,14 @@ typedef struct SculptBoundaryEditInfo { /* Edge for drawing the boundary preview in the cursor. */ typedef struct SculptBoundaryPreviewEdge { - int v1; - int v2; + PBVHVertRef v1; + PBVHVertRef v2; } SculptBoundaryPreviewEdge; typedef struct SculptBoundary { /* Vertex indices of the active boundary. */ - int *vertices; + PBVHVertRef *vertices; + int *vertices_i; int vertices_capacity; int num_vertices; @@ -432,12 +434,13 @@ typedef struct SculptBoundary { bool forms_loop; /* Initial vertex in the boundary which is closest to the current sculpt active vertex. */ - int initial_vertex; + PBVHVertRef initial_vertex; + int initial_vertex_i; /* Vertex that at max_propagation_steps from the boundary and closest to the original active * vertex that was used to initialize the boundary. This is used as a reference to check how much * the deformation will go into the mesh and to calculate the strength of the brushes. */ - int pivot_vertex; + PBVHVertRef pivot_vertex; /* Stores the initial positions of the pivot and boundary initial vertex as they may be deformed * during the brush action. This allows to use them as a reference positions and vectors for some @@ -565,7 +568,7 @@ typedef struct SculptSession { struct ExpandCache *expand_cache; /* Cursor data and active vertex for tools */ - int active_vertex_index; + PBVHVertRef active_vertex; int active_face_index; int active_grid_index; @@ -591,8 +594,8 @@ typedef struct SculptSession { struct Scene *scene; /* Dynamic mesh preview */ - int *preview_vert_index_list; - int preview_vert_index_count; + PBVHVertRef *preview_vert_list; + int preview_vert_count; /* Pose Brush Preview */ float pose_origin[3]; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index f517ff3a949..2f4618e6f7a 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -8,8 +8,11 @@ */ #include "BLI_bitmap.h" +#include "BLI_compiler_compat.h" #include "BLI_ghash.h" +#include "bmesh.h" + /* For embedding CCGKey in iterator. */ #include "BKE_attribute.h" #include "BKE_ccg.h" @@ -43,6 +46,41 @@ struct MeshElemMap; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; +typedef enum { + PBVH_FACES, + PBVH_GRIDS, + PBVH_BMESH, +} PBVHType; + +/* Public members of PBVH, used for inlined functions. */ +struct PBVHPublic { + PBVHType type; + BMesh *bm; +}; + +/* + * These structs represent logical verts/edges/faces. + * for PBVH_GRIDS and PBVH_FACES they store integer + * offsets, PBVH_BMESH stores pointers. + * + * The idea is to enforce stronger type checking by encapsulating + * intptr_t's in structs. + */ + +typedef struct PBVHVertRef { + intptr_t i; +} PBVHVertRef; + +typedef struct PBVHEdgeRef { + intptr_t i; +} PBVHEdgeRef; + +typedef struct PBVHFaceRef { + intptr_t i; +} PBVHFaceRef; + +#define PBVH_REF_NONE -1LL + typedef struct { float (*co)[3]; } PBVHProxyNode; @@ -87,9 +125,97 @@ typedef struct PBVHFrustumPlanes { int num_planes; } PBVHFrustumPlanes; +BLI_INLINE PBVHType BKE_pbvh_type(const PBVH *pbvh) +{ + return ((const struct PBVHPublic *)pbvh)->type; +} + +BLI_INLINE BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) +{ + return ((struct PBVHPublic *)pbvh)->bm; +} + void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); +BLI_INLINE PBVHVertRef BKE_pbvh_make_vref(intptr_t i) +{ + PBVHVertRef ret = {i}; + return ret; +} + +BLI_INLINE PBVHEdgeRef BKE_pbvh_make_eref(intptr_t i) +{ + PBVHEdgeRef ret = {i}; + return ret; +} + +BLI_INLINE PBVHFaceRef BKE_pbvh_make_fref(intptr_t i) +{ + PBVHFaceRef ret = {i}; + return ret; +} + +BLI_INLINE int BKE_pbvh_vertex_to_index(PBVH *pbvh, PBVHVertRef v) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != PBVH_REF_NONE ? + BM_elem_index_get((BMVert *)(v.i)) : + (v.i)); +} + +BLI_INLINE PBVHVertRef BKE_pbvh_index_to_vertex(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_vref(index); + case PBVH_BMESH: + return BKE_pbvh_make_vref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->vtable[index]); + } + + return BKE_pbvh_make_vref(PBVH_REF_NONE); +} + +BLI_INLINE int BKE_pbvh_edge_to_index(PBVH *pbvh, PBVHEdgeRef e) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && e.i != PBVH_REF_NONE ? + BM_elem_index_get((BMEdge *)(e.i)) : + (e.i)); +} + +BLI_INLINE PBVHEdgeRef BKE_pbvh_index_to_edge(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_eref(index); + case PBVH_BMESH: + return BKE_pbvh_make_eref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->etable[index]); + } + + return BKE_pbvh_make_eref(PBVH_REF_NONE); +} + +BLI_INLINE int BKE_pbvh_face_to_index(PBVH *pbvh, PBVHFaceRef f) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && f.i != PBVH_REF_NONE ? + BM_elem_index_get((BMFace *)(f.i)) : + (f.i)); +} + +BLI_INLINE PBVHFaceRef BKE_pbvh_index_to_face(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_fref(index); + case PBVH_BMESH: + return BKE_pbvh_make_fref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->ftable[index]); + } + + return BKE_pbvh_make_fref(PBVH_REF_NONE); +} + /* Callbacks */ /** @@ -181,7 +307,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *active_vertex_index, + PBVHVertRef *active_vertex, int *active_face_grid_index, float *face_normal); @@ -230,13 +356,7 @@ void BKE_pbvh_draw_debug_cb( void *user_data); /* PBVH Access */ -typedef enum { - PBVH_FACES, - PBVH_GRIDS, - PBVH_BMESH, -} PBVHType; -PBVHType BKE_pbvh_type(const PBVH *pbvh); bool BKE_pbvh_has_faces(const PBVH *pbvh); /** @@ -272,7 +392,6 @@ int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh); /** * Only valid for type == #PBVH_BMESH. */ -struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size); typedef enum { @@ -308,7 +427,7 @@ void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked); bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node); void BKE_pbvh_mark_rebuild_pixels(PBVH *pbvh); -void BKE_pbvh_vert_mark_update(PBVH *pbvh, int index); +void BKE_pbvh_vert_mark_update(PBVH *pbvh, PBVHVertRef vertex); void BKE_pbvh_node_get_grids(PBVH *pbvh, PBVHNode *node, @@ -399,6 +518,7 @@ typedef struct PBVHVertexIter { int gy; int i; int index; + PBVHVertRef vertex; bool respect_hide; /* grid */ @@ -443,7 +563,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m if (vi.grids) { \ vi.width = vi.gridsize; \ vi.height = vi.gridsize; \ - vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \ + vi.index = vi.vertex.i = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \ vi.grid = vi.grids[vi.grid_indices[vi.g]]; \ if (mode == PBVH_ITER_UNIQUE) { \ vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \ @@ -462,6 +582,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \ vi.grid = CCG_elem_next(&vi.key, vi.grid); \ vi.index++; \ + vi.vertex.i++; \ vi.visible = true; \ if (vi.gh) { \ if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \ @@ -482,7 +603,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } \ vi.co = vi.mvert->co; \ vi.no = vi.vert_normals[vi.vert_indices[vi.gx]]; \ - vi.index = vi.vert_indices[vi.i]; \ + vi.index = vi.vertex.i = vi.vert_indices[vi.i]; \ if (vi.vmask) { \ vi.mask = &vi.vmask[vi.index]; \ } \ @@ -502,6 +623,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } \ vi.co = vi.bm_vert->co; \ vi.fno = vi.bm_vert->no; \ + vi.vertex = BKE_pbvh_make_vref((intptr_t)vi.bm_vert); \ vi.index = BM_elem_index_get(vi.bm_vert); \ vi.mask = (float *)BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \ } @@ -581,8 +703,8 @@ void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop); void BKE_pbvh_update_active_vcol(PBVH *pbvh, const struct Mesh *mesh); void BKE_pbvh_pmap_set(PBVH *pbvh, const struct MeshElemMap *pmap); -void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]); -void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]); +void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]); +void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]); void BKE_pbvh_ensure_node_loops(PBVH *pbvh); bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 3922bfb6c0d..a24a3e05dab 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -291,7 +291,7 @@ enum { /* Draw an item in the uiList */ typedef void (*uiListDrawItemFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct uiLayout *layout, struct PointerRNA *dataptr, struct PointerRNA *itemptr, @@ -303,12 +303,12 @@ typedef void (*uiListDrawItemFunc)(struct uiList *ui_list, /* Draw the filtering part of an uiList */ typedef void (*uiListDrawFilterFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct uiLayout *layout); /* Filter items of an uiList */ typedef void (*uiListFilterItemsFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct PointerRNA *, const char *propname); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index fee7582acb3..c16d19588ed 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -53,6 +53,7 @@ #include "BIK_api.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "BLO_read_write.h" @@ -1950,7 +1951,7 @@ void BKE_pose_blend_read_lib(BlendLibReader *reader, Object *ob, bPose *pose) pchan->bone = BKE_armature_find_bone_name(arm, pchan->name); - IDP_BlendReadLib(reader, pchan->prop); + IDP_BlendReadLib(reader, ob->id.lib, pchan->prop); BLO_read_id_address(reader, ob->id.lib, &pchan->custom); if (UNLIKELY(pchan->bone == NULL)) { diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 861a89ea9d7..b5b00e031b2 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -43,6 +43,7 @@ #include "BLO_read_write.h" #include "RNA_access.h" +#include "RNA_path.h" #include "CLG_log.h" diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index eb4784bebff..19fef1ce825 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -53,6 +53,7 @@ #include "DEG_depsgraph_query.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "BLO_read_write.h" diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index f29074c827c..7be3fe6f0e1 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -261,12 +261,12 @@ static void armature_blend_read_data(BlendDataReader *reader, ID *id) BKE_armature_bone_hash_make(arm); } -static void lib_link_bones(BlendLibReader *reader, Bone *bone) +static void lib_link_bones(BlendLibReader *reader, Library *lib, Bone *bone) { - IDP_BlendReadLib(reader, bone->prop); + IDP_BlendReadLib(reader, lib, bone->prop); LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { - lib_link_bones(reader, curbone); + lib_link_bones(reader, lib, curbone); } } @@ -274,7 +274,7 @@ static void armature_blend_read_lib(BlendLibReader *reader, ID *id) { bArmature *arm = (bArmature *)id; LISTBASE_FOREACH (Bone *, curbone, &arm->bonebase) { - lib_link_bones(reader, curbone); + lib_link_bones(reader, id->lib, curbone); } } diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 8d4b64da817..fdd269bd9c8 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -73,7 +73,7 @@ static void set_crazy_vertex_quat(float r_quat[4], static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob) { bool disabled = false; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first); for (int i = 0; md && i <= cageIndex; i++, md = md->next) { @@ -241,7 +241,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra Mesh *me_input = static_cast<Mesh *>(ob->data); Mesh *me = nullptr; int i, a, modifiers_left_num = 0, verts_num = 0; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); float(*defmats)[3][3] = nullptr, (*deformedVerts)[3] = nullptr; VirtualModifierData virtualModifierData; ModifierEvalContext mectx = {depsgraph, ob, ModifierApplyFlag(0)}; @@ -362,7 +362,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, VirtualModifierData virtualModifierData; Object object_eval; crazyspace_init_object_for_eval(depsgraph, object, &object_eval); - MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0); + MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, false); const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0; const bool has_multires = mmd != nullptr && mmd->sculptlvl > 0; const ModifierEvalContext mectx = {depsgraph, &object_eval, ModifierApplyFlag(0)}; diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 972ff377519..f5876e48241 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -37,6 +37,7 @@ #include "BLO_read_write.h" #include "RNA_access.h" +#include "RNA_path.h" #include "CLG_log.h" diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index 5d54c5c039b..aa33bef998f 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -30,6 +30,7 @@ #include "BKE_object.h" #include "RNA_access.h" +#include "RNA_path.h" #include "atomic_ops.h" diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 35f02c29a00..43e732b428d 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -1428,7 +1428,7 @@ void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const ch } } -void IDP_BlendReadLib(BlendLibReader *reader, IDProperty *prop) +void IDP_BlendReadLib(BlendLibReader *reader, Library *lib, IDProperty *prop) { if (!prop) { return; @@ -1437,7 +1437,7 @@ void IDP_BlendReadLib(BlendLibReader *reader, IDProperty *prop) switch (prop->type) { case IDP_ID: /* PointerProperty */ { - void *newaddr = BLO_read_get_new_id_address(reader, NULL, IDP_Id(prop)); + void *newaddr = BLO_read_get_new_id_address(reader, lib, IDP_Id(prop)); if (IDP_Id(prop) && !newaddr && G.debug) { printf("Error while loading \"%s\". Data not found in file!\n", prop->name); } @@ -1448,14 +1448,14 @@ void IDP_BlendReadLib(BlendLibReader *reader, IDProperty *prop) { IDProperty *idp_array = IDP_IDPArray(prop); for (int i = 0; i < prop->len; i++) { - IDP_BlendReadLib(reader, &(idp_array[i])); + IDP_BlendReadLib(reader, lib, &(idp_array[i])); } break; } case IDP_GROUP: /* PointerProperty */ { LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { - IDP_BlendReadLib(reader, loop); + IDP_BlendReadLib(reader, lib, loop); } break; } diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc index f549393fd12..a2f58baebf7 100644 --- a/source/blender/blenkernel/intern/idprop_create.cc +++ b/source/blender/blenkernel/intern/idprop_create.cc @@ -44,6 +44,14 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_n return std::unique_ptr<IDProperty, IDPropertyDeleter>(property); } +std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, ID *value) +{ + IDPropertyTemplate prop_template{0}; + prop_template.id = value; + IDProperty *property = IDP_New(IDP_ID, &prop_template, prop_name.c_str()); + return std::unique_ptr<IDProperty, IDPropertyDeleter>(property); +} + static std::unique_ptr<IDProperty, IDPropertyDeleter> array_create(const StringRefNull prop_name, eIDPropertyType subtype, size_t array_len) diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index c2b8ec95a46..ae5eead2547 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -3410,9 +3410,8 @@ void BKE_image_ensure_tile_token(char *filename) /* General 4-digit "udim" pattern. As this format is susceptible to ambiguity * with other digit sequences, we can leverage the supported range of roughly - * 1000 through 2000 to provide better detection. - */ - std::regex pattern(R"((^|.*?\D)([12]\d{3})(\D.*))"); + * 1000 through 2000 to provide better detection. */ + std::regex pattern(R"((.*[._-])([12]\d{3})([._-].*))"); if (std::regex_search(path, match, pattern)) { BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), FILE_MAX); return; diff --git a/source/blender/blenkernel/intern/image_test.cc b/source/blender/blenkernel/intern/image_test.cc index 9c15fc62d21..7004d39c805 100644 --- a/source/blender/blenkernel/intern/image_test.cc +++ b/source/blender/blenkernel/intern/image_test.cc @@ -32,8 +32,12 @@ TEST(udim, image_ensure_tile_token) verify("test_1002_ao.png", "test_<UDIM>_ao.png"); verify("test.1002.ver0023.png", "test.<UDIM>.ver0023.png"); verify("test.ver0023.1002.png", "test.ver0023.<UDIM>.png"); - verify("1002test.png", "<UDIM>test.png"); - verify("test1002.png", "test<UDIM>.png"); + verify("test.1002.1.png", "test.<UDIM>.1.png"); + verify("test.1.1002.png", "test.1.<UDIM>.png"); + verify("test-2022-01-01.1002.png", "test-2022-01-01.<UDIM>.png"); + verify("1111_11.1002.png", "1111_11.<UDIM>.png"); + verify("2111_01.1002.png", "2111_01.<UDIM>.png"); + verify("2022_1002_100200.1002.png", "2022_1002_100200.<UDIM>.png"); /* UVTILE pattern detection. */ verify("uv-test.u2_v10.png", "uv-test.<UVTILE>.png"); @@ -44,8 +48,15 @@ TEST(udim, image_ensure_tile_token) verify("u2_v10uv-test.png", "<UVTILE>uv-test.png"); verify("u2_v10u_v-test.png", "<UVTILE>u_v-test.png"); - /* Incorrect patterns. */ - for (const char *incorrect : {"test.123.png", + /* Patterns which should not be detected as UDIMs. */ + for (const char *incorrect : {"1002.png", + "1002test.png", + "test1002.png", + "test(1002).png", + "(1002)test.png", + "test-1080p.png", + "test-1920x1080.png", + "test.123.png", "test.12345.png", "test.uv.png", "test.u1v.png", diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 7ef15912567..07ce4e46e9b 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -46,6 +46,7 @@ #include "BKE_scene.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "BLO_read_write.h" diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 0202fb3ff5e..4257bccad93 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -2384,7 +2384,7 @@ void BKE_view_layer_blend_read_lib(BlendLibReader *reader, Library *lib, ViewLay BLO_read_id_address(reader, lib, &view_layer->mat_override); - IDP_BlendReadLib(reader, view_layer->id_properties); + IDP_BlendReadLib(reader, lib, view_layer->id_properties); } /** \} */ diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index 4ad8d26cd2a..6afbb9064a8 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -52,6 +52,7 @@ #include "PIL_time.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "RNA_types.h" diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 05e16192f9a..ba473b29474 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -835,7 +835,7 @@ static void ntree_blend_read_data(BlendDataReader *reader, ID *id) static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSocket *sock) { - IDP_BlendReadLib(reader, sock->prop); + IDP_BlendReadLib(reader, lib, sock->prop); /* This can happen for all socket types when a file is saved in an older version of Blender than * it was originally created in (T86298). Some socket types still require a default value. The @@ -901,7 +901,7 @@ void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this. */ - IDP_BlendReadLib(reader, node->prop); + IDP_BlendReadLib(reader, lib, node->prop); BLO_read_id_address(reader, lib, &node->id); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 9b0d15ac702..b540357ce49 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1433,10 +1433,10 @@ static void sculptsession_free_pbvh(Object *object) MEM_SAFE_FREE(ss->persistent_base); - MEM_SAFE_FREE(ss->preview_vert_index_list); - ss->preview_vert_index_count = 0; + MEM_SAFE_FREE(ss->preview_vert_list); + ss->preview_vert_count = 0; - MEM_SAFE_FREE(ss->preview_vert_index_list); + MEM_SAFE_FREE(ss->preview_vert_list); MEM_SAFE_FREE(ss->vertex_info.connected_component); MEM_SAFE_FREE(ss->vertex_info.boundary); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 6cebcdfea4e..0ec7a79f890 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -555,7 +555,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, BB cb; pbvh->mesh = mesh; - pbvh->type = PBVH_FACES; + pbvh->header.type = PBVH_FACES; pbvh->mpoly = mpoly; pbvh->mloop = mloop; pbvh->looptri = looptri; @@ -615,7 +615,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh, { const int gridsize = key->grid_size; - pbvh->type = PBVH_GRIDS; + pbvh->header.type = PBVH_GRIDS; pbvh->grids = grids; pbvh->gridfaces = gridfaces; pbvh->grid_flag_mats = flagmats; @@ -1305,17 +1305,17 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, CustomData *vdata, *ldata; - if (!pbvh->bm) { + if (!pbvh->header.bm) { vdata = pbvh->vdata; ldata = pbvh->ldata; } else { - vdata = &pbvh->bm->vdata; - ldata = &pbvh->bm->ldata; + vdata = &pbvh->header.bm->vdata; + ldata = &pbvh->header.bm->ldata; } if (node->flag & PBVH_RebuildDrawBuffers) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: { bool smooth = node->totprim > 0 ? pbvh->grid_flag_mats[node->prim_indices[0]].flag & ME_SMOOTH : @@ -1344,7 +1344,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, if (node->flag & PBVH_UpdateDrawBuffers) { const int update_flags = pbvh_get_buffers_update_flags(pbvh); - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: GPU_pbvh_grid_buffers_update(pbvh->vbo_id, node->draw_buffers, @@ -1376,7 +1376,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, case PBVH_BMESH: GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id, node->draw_buffers, - pbvh->bm, + pbvh->header.bm, node->bm_faces, node->bm_unique_verts, node->bm_other_verts, @@ -1405,15 +1405,15 @@ static void pbvh_check_draw_layout(PBVH *pbvh) pbvh->vbo_id = GPU_pbvh_make_format(); } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_BMESH: - if (!pbvh->bm) { + if (!pbvh->header.bm) { /* BMesh hasn't been created yet */ return; } - vdata = &pbvh->bm->vdata; - ldata = &pbvh->bm->ldata; + vdata = &pbvh->header.bm->vdata; + ldata = &pbvh->header.bm->ldata; break; case PBVH_FACES: vdata = pbvh->vdata; @@ -1431,7 +1431,7 @@ static void pbvh_check_draw_layout(PBVH *pbvh) * (there's no guarantee there isn't another EEVEE viewport which would * free the draw buffers and corrupt the draw cache). */ - if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) { + if (GPU_pbvh_attribute_names_update(pbvh->header.type, pbvh->vbo_id, vdata, ldata, false)) { /* attribute layout changed; force rebuild */ for (int i = 0; i < pbvh->totnode; i++) { PBVHNode *node = pbvh->nodes + i; @@ -1451,14 +1451,14 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, pbvh->vbo_id = GPU_pbvh_make_format(); } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_BMESH: - if (!pbvh->bm) { + if (!pbvh->header.bm) { /* BMesh hasn't been created yet */ return; } - vdata = &pbvh->bm->vdata; + vdata = &pbvh->header.bm->vdata; break; case PBVH_FACES: vdata = pbvh->vdata; @@ -1469,7 +1469,7 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, } UNUSED_VARS(vdata); - if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) { + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->header.type, PBVH_GRIDS, PBVH_BMESH)) { /* Free buffers uses OpenGL, so not in parallel. */ for (int n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1477,11 +1477,11 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, pbvh_free_draw_buffers(pbvh, node); } else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) { - if (pbvh->type == PBVH_GRIDS) { + if (pbvh->header.type == PBVH_GRIDS) { GPU_pbvh_grid_buffers_update_free( node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices); } - else if (pbvh->type == PBVH_BMESH) { + else if (pbvh->header.type == PBVH_BMESH) { GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers); } } @@ -1795,15 +1795,10 @@ void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int /***************************** PBVH Access ***********************************/ -PBVHType BKE_pbvh_type(const PBVH *pbvh) -{ - return pbvh->type; -} - bool BKE_pbvh_has_faces(const PBVH *pbvh) { - if (pbvh->type == PBVH_BMESH) { - return (pbvh->bm->totface != 0); + if (pbvh->header.type == PBVH_BMESH) { + return (pbvh->header.bm->totface != 0); } return (pbvh->totprim != 0); @@ -1824,46 +1819,40 @@ void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]) BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grid_hidden; } const CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return &pbvh->gridkey; } struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grids; } BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grid_hidden; } int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->totgrid * pbvh->gridkey.grid_area; } int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->totgrid * (pbvh->gridkey.grid_size - 1) * (pbvh->gridkey.grid_size - 1); } -BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) -{ - BLI_assert(pbvh->type == PBVH_BMESH); - return pbvh->bm; -} - /***************************** Node Access ***********************************/ void BKE_pbvh_node_mark_update(PBVHNode *node) @@ -1964,10 +1953,10 @@ bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node) return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked); } -void BKE_pbvh_vert_mark_update(PBVH *pbvh, int index) +void BKE_pbvh_vert_mark_update(PBVH *pbvh, PBVHVertRef index) { - BLI_assert(pbvh->type == PBVH_FACES); - pbvh->vert_bitmap[index] = true; + BLI_assert(pbvh->header.type == PBVH_FACES); + pbvh->vert_bitmap[index.i] = true; } void BKE_pbvh_node_get_loops(PBVH *pbvh, @@ -2004,7 +1993,7 @@ void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int { int tot; - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: tot = node->totprim * pbvh->gridkey.grid_area; if (r_totvert) { @@ -2042,7 +2031,7 @@ void BKE_pbvh_node_get_grids(PBVH *pbvh, int *r_gridsize, CCGElem ***r_griddata) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: if (r_grid_indices) { *r_grid_indices = node->prim_indices; @@ -2125,7 +2114,7 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node) { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); const int *verts = node->vert_indices; const int totvert = node->uniq_verts + node->face_verts; @@ -2299,7 +2288,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, int *r_active_face_index, float *r_face_normal) { @@ -2339,7 +2328,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, normal_tri_v3(r_face_normal, co[0], co[1], co[2]); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { @@ -2349,7 +2338,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, if (j == 0 || len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, co[j]); - *r_active_vertex_index = mloop[lt->tri[j]].v; + r_active_vertex->i = mloop[lt->tri[j]].v; *r_active_face_index = lt->poly; } } @@ -2367,7 +2356,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, int *r_active_grid_index, float *r_face_normal) { @@ -2419,7 +2408,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, normal_quad_v3(r_face_normal, co[0], co[1], co[2], co[3]); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); @@ -2434,8 +2423,8 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, co[j]); - *r_active_vertex_index = gridkey->grid_area * grid_index + - (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]); + r_active_vertex->i = gridkey->grid_area * grid_index + + (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]); } } } @@ -2462,7 +2451,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *active_vertex_index, + PBVHVertRef *active_vertex, int *active_face_grid_index, float *face_normal) { @@ -2472,7 +2461,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, return false; } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_FACES: hit |= pbvh_faces_node_raycast(pbvh, node, @@ -2481,7 +2470,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, ray_normal, isect_precalc, depth, - active_vertex_index, + active_vertex, active_face_grid_index, face_normal); break; @@ -2493,19 +2482,19 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, ray_normal, isect_precalc, depth, - active_vertex_index, + active_vertex, active_face_grid_index, face_normal); break; case PBVH_BMESH: - BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT); + BM_mesh_elem_index_ensure(pbvh->header.bm, BM_VERT); hit = pbvh_bmesh_node_raycast(node, ray_start, ray_normal, isect_precalc, depth, use_origco, - active_vertex_index, + active_vertex, face_normal); break; } @@ -2729,7 +2718,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh, return false; } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_FACES: hit |= pbvh_faces_node_nearest_to_ray( pbvh, node, origco, ray_start, ray_normal, depth, dist_sq); @@ -2820,13 +2809,13 @@ void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg) pbvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode); if (totnode > 0) { - if (pbvh->type == PBVH_BMESH) { + if (pbvh->header.type == PBVH_BMESH) { pbvh_bmesh_normals_update(nodes, totnode); } - else if (pbvh->type == PBVH_FACES) { + else if (pbvh->header.type == PBVH_FACES) { pbvh_faces_update_normals(pbvh, nodes, totnode); } - else if (pbvh->type == PBVH_GRIDS) { + else if (pbvh->header.type == PBVH_GRIDS) { struct CCGFace **faces; int num_faces; BKE_pbvh_get_grid_updates(pbvh, true, (void ***)&faces, &num_faces); @@ -2991,7 +2980,7 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int /* no need for float comparison here (memory is exactly equal or not) */ if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) { copy_v3_v3(mvert->co, vertCos[a]); - BKE_pbvh_vert_mark_update(pbvh, a); + BKE_pbvh_vert_mark_update(pbvh, BKE_pbvh_make_vref(a)); } } @@ -3108,6 +3097,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->no = NULL; vi->fno = NULL; vi->mvert = NULL; + vi->vertex.i = 0LL; vi->respect_hide = pbvh->respect_hide; if (pbvh->respect_hide == false) { @@ -3134,10 +3124,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->vert_indices = vert_indices; vi->mverts = verts; - if (pbvh->type == PBVH_BMESH) { + if (pbvh->header.type == PBVH_BMESH) { BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts); BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts); - vi->bm_vdata = &pbvh->bm->vdata; + vi->bm_vdata = &pbvh->header.bm->vdata; vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK); } @@ -3147,7 +3137,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } vi->mask = NULL; - if (pbvh->type == PBVH_FACES) { + if (pbvh->header.type == PBVH_FACES) { vi->vert_normals = pbvh->vert_normals; vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK); @@ -3156,13 +3146,14 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m bool pbvh_has_mask(const PBVH *pbvh) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: return (pbvh->gridkey.has_mask != 0); case PBVH_FACES: return (pbvh->vdata && CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK)); case PBVH_BMESH: - return (pbvh->bm && (CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK) != -1)); + return (pbvh->header.bm && + (CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK) != -1)); } return false; @@ -3170,7 +3161,7 @@ bool pbvh_has_mask(const PBVH *pbvh) bool pbvh_has_face_sets(PBVH *pbvh) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS)); case PBVH_FACES: @@ -3218,13 +3209,13 @@ void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings, MVert *BKE_pbvh_get_verts(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); return pbvh->verts; } const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3] { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); return pbvh->vert_normals; } @@ -3242,6 +3233,7 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide) { pbvh->respect_hide = respect_hide; } + bool BKE_pbvh_is_drawing(const PBVH *pbvh) { return pbvh->is_drawing; diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index dec93826b9b..70aeb10f087 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -86,10 +86,12 @@ template<> void from_float(const float src[4], MPropCol &dst) } template<typename T> -static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4]) +static void pbvh_vertex_color_get(const PBVH &pbvh, PBVHVertRef vertex, float r_color[4]) { + int index = vertex.i; + if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[vertex]; + const MeshElemMap &melem = pbvh.pmap[index]; int count = 0; zero_v4(r_color); @@ -99,7 +101,7 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4] Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop}; for (const int i_loop : IndexRange(mp.totloop)) { - if (loops[i_loop].v == vertex) { + if (loops[i_loop].v == index) { float temp[4]; to_float(colors[i_loop], temp); @@ -114,15 +116,17 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4] } } else { - to_float(static_cast<T *>(pbvh.color_layer->data)[vertex], r_color); + to_float(static_cast<T *>(pbvh.color_layer->data)[index], r_color); } } template<typename T> -static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4]) +static void pbvh_vertex_color_set(PBVH &pbvh, PBVHVertRef vertex, const float color[4]) { + int index = vertex.i; + if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[vertex]; + const MeshElemMap &melem = pbvh.pmap[index]; for (const int i_poly : Span(melem.indices, melem.count)) { const MPoly &mp = pbvh.mpoly[i_poly]; @@ -130,21 +134,21 @@ static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4]) Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop}; for (const int i_loop : IndexRange(mp.totloop)) { - if (loops[i_loop].v == vertex) { + if (loops[i_loop].v == index) { from_float(color, colors[i_loop]); } } } } else { - from_float(color, static_cast<T *>(pbvh.color_layer->data)[vertex]); + from_float(color, static_cast<T *>(pbvh.color_layer->data)[index]); } } } // namespace blender::bke extern "C" { -void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) +void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]) { blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); @@ -152,7 +156,7 @@ void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) }); } -void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]) +void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]) { blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); @@ -202,7 +206,7 @@ void BKE_pbvh_store_colors_vertex(PBVH *pbvh, blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); for (const int i : IndexRange(indices_num)) { - blender::bke::pbvh_vertex_color_get<T>(*pbvh, indices[i], r_colors[i]); + blender::bke::pbvh_vertex_color_get<T>(*pbvh, BKE_pbvh_make_vref(indices[i]), r_colors[i]); } }); } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 112fd01c699..c4993684100 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -400,7 +400,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index) BM_elem_index_set(f, i); /* set_dirty! */ } /* Likely this is already dirty. */ - pbvh->bm->elem_index_dirty |= BM_FACE; + pbvh->header.bm->elem_index_dirty |= BM_FACE; pbvh_bmesh_node_split(pbvh, bbc_array, node_index); @@ -484,8 +484,8 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh, BLI_assert((pbvh->totnode == 1 || node_index) && node_index <= pbvh->totnode); /* avoid initializing customdata because its quite involved */ - BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_SKIP_CD); - CustomData_bmesh_set_default(&pbvh->bm->vdata, &v->head.data); + BMVert *v = BM_vert_create(pbvh->header.bm, co, NULL, BM_CREATE_SKIP_CD); + CustomData_bmesh_set_default(&pbvh->header.bm->vdata, &v->head.data); /* This value is logged below */ copy_v3_v3(v->no, no); @@ -512,7 +512,7 @@ static BMFace *pbvh_bmesh_face_create( /* ensure we never add existing face */ BLI_assert(!BM_face_exists(v_tri, 3)); - BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); + BMFace *f = BM_face_create(pbvh->header.bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); f->head.hflag = f_example->head.hflag; BLI_gset_insert(node->bm_faces, f); @@ -1185,22 +1185,22 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, v_tri[0] = v1; v_tri[1] = v_new; v_tri[2] = v_opp; - bm_edges_from_tri(pbvh->bm, v_tri, e_tri); + bm_edges_from_tri(pbvh->header.bm, v_tri, e_tri); f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj); long_edge_queue_face_add(eq_ctx, f_new); v_tri[0] = v_new; v_tri[1] = v2; /* v_tri[2] = v_opp; */ /* unchanged */ - e_tri[0] = BM_edge_create(pbvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); + e_tri[0] = BM_edge_create(pbvh->header.bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); e_tri[2] = e_tri[1]; /* switched */ - e_tri[1] = BM_edge_create(pbvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); + e_tri[1] = BM_edge_create(pbvh->header.bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj); long_edge_queue_face_add(eq_ctx, f_new); /* Delete original */ pbvh_bmesh_face_remove(pbvh, f_adj); - BM_face_kill(pbvh->bm, f_adj); + BM_face_kill(pbvh->header.bm, f_adj); /* Ensure new vertex is in the node */ if (!BLI_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) { @@ -1217,7 +1217,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, } } - BM_edge_kill(pbvh->bm, e); + BM_edge_kill(pbvh->header.bm, e); } static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, @@ -1303,12 +1303,12 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BMFace *f_adj = l_adj->f; pbvh_bmesh_face_remove(pbvh, f_adj); - BM_face_kill(pbvh->bm, f_adj); + BM_face_kill(pbvh->header.bm, f_adj); } /* Kill the edge */ BLI_assert(BM_edge_is_wire(e)); - BM_edge_kill(pbvh->bm, e); + BM_edge_kill(pbvh->header.bm, e); /* For all remaining faces of v_del, create a new face that is the * same except it uses v_conn instead of v_del */ @@ -1355,7 +1355,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BMEdge *e_tri[3]; PBVHNode *n = pbvh_bmesh_node_from_face(pbvh, f); int ni = n - pbvh->nodes; - bm_edges_from_tri(pbvh->bm, v_tri, e_tri); + bm_edges_from_tri(pbvh->header.bm, v_tri, e_tri); pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f); /* Ensure that v_conn is in the new face's node */ @@ -1388,13 +1388,13 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, /* Remove the face */ pbvh_bmesh_face_remove(pbvh, f_del); - BM_face_kill(pbvh->bm, f_del); + BM_face_kill(pbvh->header.bm, f_del); /* Check if any of the face's edges are now unused by any * face, if so delete them */ for (int j = 0; j < 3; j++) { if (BM_edge_is_wire(e_tri[j])) { - BM_edge_kill(pbvh->bm, e_tri[j]); + BM_edge_kill(pbvh->header.bm, e_tri[j]); } } @@ -1410,7 +1410,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, v_conn = NULL; } BLI_ghash_insert(deleted_verts, v_tri[j], NULL); - BM_vert_kill(pbvh->bm, v_tri[j]); + BM_vert_kill(pbvh->header.bm, v_tri[j]); } } } @@ -1437,7 +1437,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BM_log_vert_removed(pbvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset); /* v_conn == NULL is OK */ BLI_ghash_insert(deleted_verts, v_del, v_conn); - BM_vert_kill(pbvh->bm, v_del); + BM_vert_kill(pbvh->header.bm, v_del); } static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, @@ -1501,7 +1501,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, struct IsectRayPrecalc *isect_precalc, float *depth, bool use_original, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, float *r_face_normal) { bool hit = false; @@ -1538,14 +1538,14 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { if (len_squared_v3v3(location, v_tri[j]->co) < len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, v_tri[j]->co); - *r_active_vertex_index = BM_elem_index_get(v_tri[j]); + r_active_vertex->i = (intptr_t)v_tri[j]; } } } @@ -1872,11 +1872,11 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, { pbvh->cd_vert_node_offset = cd_vert_node_offset; pbvh->cd_face_node_offset = cd_face_node_offset; - pbvh->bm = bm; + pbvh->header.bm = bm; BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75); - pbvh->type = PBVH_BMESH; + pbvh->header.type = PBVH_BMESH; pbvh->bm_log = log; /* TODO: choose leaf limit better */ @@ -1951,7 +1951,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, /* 2 is enough for edge faces - manifold edge */ BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2); BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32); - const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK); + const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK); const int cd_vert_node_offset = pbvh->cd_vert_node_offset; const int cd_face_node_offset = pbvh->cd_face_node_offset; @@ -1967,7 +1967,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, EdgeQueueContext eq_ctx = { &q, queue_pool, - pbvh->bm, + pbvh->header.bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, @@ -1986,7 +1986,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, EdgeQueueContext eq_ctx = { &q, queue_pool, - pbvh->bm, + pbvh->header.bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, @@ -2126,13 +2126,13 @@ static void pbvh_bmesh_print(PBVH *pbvh) BMIter iter; BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f)); } fprintf(stderr, "bm_vert_to_node:\n"); BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v)); } @@ -2171,21 +2171,21 @@ static void print_flag_factors(int flag) static void pbvh_bmesh_verify(PBVH *pbvh) { /* build list of faces & verts to lookup */ - GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totface); + GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totface); BMIter iter; { BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { BLI_assert(BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE); BLI_gset_insert(faces_all, f); } } - GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totvert); + GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totvert); { BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { BLI_gset_insert(verts_all, v); } @@ -2207,7 +2207,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) { BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { BMIter bm_iter; BMVert *v; PBVHNode *n = pbvh_bmesh_node_lookup(pbvh, f); @@ -2240,7 +2240,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) /* Check verts */ { BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { /* vertex isn't tracked */ if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { continue; @@ -2286,7 +2286,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) # if 0 /* check that every vert belongs somewhere */ /* Slow */ - BM_ITER_MESH (vi, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (vi, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { bool has_unique = false; for (int i = 0; i < pbvh->totnode; i++) { PBVHNode *n = &pbvh->nodes[i]; @@ -2299,7 +2299,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) } /* If totvert differs from number of verts inside the hash. hash-totvert is checked above. */ - BLI_assert(vert_count == pbvh->bm->totvert); + BLI_assert(vert_count == pbvh->header.bm->totvert); # endif /* Check that node elements are recorded in the top level */ diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index a4ac2744a73..0edf224e5ff 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -130,7 +130,7 @@ typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags; typedef struct PBVHBMeshLog PBVHBMeshLog; struct PBVH { - PBVHType type; + struct PBVHPublic header; PBVHFlags flags; PBVHNode *nodes; @@ -183,7 +183,6 @@ struct PBVH { bool respect_hide; /* Dynamic topology */ - BMesh *bm; float bm_max_edge_len; float bm_min_edge_len; int cd_vert_node_offset; @@ -265,7 +264,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, struct IsectRayPrecalc *isect_precalc, float *dist, bool use_original, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, float *r_face_normal); bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node, const float ray_start[3], diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index e2da27fc840..aaa6baac1ff 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -1481,7 +1481,7 @@ static void scene_blend_read_lib(BlendLibReader *reader, ID *id) } LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) { - IDP_BlendReadLib(reader, marker->prop); + IDP_BlendReadLib(reader, sce->id.lib, marker->prop); if (marker->camera) { BLO_read_id_address(reader, sce->id.lib, &marker->camera); diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 0265dd037b1..88e7db1fe6c 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -456,12 +456,12 @@ WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace, WorkSpaceLayout *iter_layout; if (iter_backward) { - LISTBASE_CIRCULAR_BACKWARD_BEGIN (&workspace->layouts, iter_layout, start) { + LISTBASE_CIRCULAR_BACKWARD_BEGIN (WorkSpaceLayout *, &workspace->layouts, iter_layout, start) { if (!callback(iter_layout, arg)) { return iter_layout; } } - LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start); + LISTBASE_CIRCULAR_BACKWARD_END(WorkSpaceLayout *, &workspace->layouts, iter_layout, start); } else { LISTBASE_CIRCULAR_FORWARD_BEGIN (&workspace->layouts, iter_layout, start) { diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh index 6fcc560d856..2b290e1ba7d 100644 --- a/source/blender/blenlib/BLI_index_range.hh +++ b/source/blender/blenlib/BLI_index_range.hh @@ -90,10 +90,10 @@ class IndexRange { return *this; } - constexpr Iterator operator++(int) const + constexpr Iterator operator++(int) { Iterator copied_iterator = *this; - ++copied_iterator; + ++(*this); return copied_iterator; } diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 237fcdae8b9..9322fa4c85b 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -320,13 +320,13 @@ struct LinkData *BLI_genericNodeN(void *data); } \ ((void)0) -#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \ - if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \ +#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(type, lb, lb_iter, lb_init) \ + if ((lb)->last && (lb_init || (lb_init = (type)(lb)->last))) { \ lb_iter = lb_init; \ do { -#define LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \ +#define LISTBASE_CIRCULAR_BACKWARD_END(type, lb, lb_iter, lb_init) \ } \ - while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (lb)->last), (lb_iter != lb_init)) \ + while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (type)(lb)->last), (lb_iter != lb_init)) \ ; \ } \ ((void)0) diff --git a/source/blender/blenlib/BLI_listbase_wrapper.hh b/source/blender/blenlib/BLI_listbase_wrapper.hh index 25e029a5616..2d631cb2441 100644 --- a/source/blender/blenlib/BLI_listbase_wrapper.hh +++ b/source/blender/blenlib/BLI_listbase_wrapper.hh @@ -50,7 +50,7 @@ template<typename T> class ListBaseWrapper { Iterator operator++(int) { Iterator iterator = *this; - ++*this; + ++(*this); return iterator; } diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index 55233676ed8..95d1e344894 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -669,10 +669,10 @@ class Map { return *this; } - BaseIterator operator++(int) const + BaseIterator operator++(int) { BaseIterator copied_iterator = *this; - ++copied_iterator; + ++(*this); return copied_iterator; } diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index 62de4b79e41..a1b6ad9754e 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -427,10 +427,10 @@ class Set { return *this; } - Iterator operator++(int) const + Iterator operator++(int) { Iterator copied_iterator = *this; - ++copied_iterator; + ++(*this); return copied_iterator; } diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc index 14d85b99739..31ea24eb494 100644 --- a/source/blender/blenlib/intern/string_search.cc +++ b/source/blender/blenlib/intern/string_search.cc @@ -11,8 +11,8 @@ #include "BLI_timeit.hh" /* Right arrow, keep in sync with #UI_MENU_ARROW_SEP in `UI_interface.h`. */ -#define UI_MENU_ARROW_SEP "\xe2\x96\xb6" -#define UI_MENU_ARROW_SEP_UNICODE 0x25b6 +#define UI_MENU_ARROW_SEP "\xe2\x96\xb8" +#define UI_MENU_ARROW_SEP_UNICODE 0x25b8 namespace blender::string_search { diff --git a/source/blender/blenlib/tests/BLI_set_test.cc b/source/blender/blenlib/tests/BLI_set_test.cc index 5a97b2c7999..9dfa48b5822 100644 --- a/source/blender/blenlib/tests/BLI_set_test.cc +++ b/source/blender/blenlib/tests/BLI_set_test.cc @@ -532,8 +532,14 @@ TEST(set, ForwardIterator) Set<int>::iterator iter1 = set.begin(); int value1 = *iter1; Set<int>::iterator iter2 = iter1++; - EXPECT_EQ(*iter1, value1); - EXPECT_EQ(*iter2, *(++iter1)); + EXPECT_EQ(*iter2, value1); + EXPECT_EQ(*(++iter2), *iter1); + /* Interesting find: On GCC & MSVC this will succeed, as the 2nd argument is evaluated before the + * 1st. On Apple Clang it's the other way around, and the test fails. */ + // EXPECT_EQ(*iter1, *(++iter1)); + Set<int>::iterator iter3 = ++iter1; + /* Check that #iter1 itself changed. */ + EXPECT_EQ(*iter3, *iter1); } TEST(set, GenericAlgorithms) diff --git a/source/blender/blenlib/tests/BLI_string_search_test.cc b/source/blender/blenlib/tests/BLI_string_search_test.cc index aa6adae8d76..ab1d073ed33 100644 --- a/source/blender/blenlib/tests/BLI_string_search_test.cc +++ b/source/blender/blenlib/tests/BLI_string_search_test.cc @@ -9,7 +9,7 @@ namespace blender::string_search::tests { /* Right arrow, keep in sync with #UI_MENU_ARROW_SEP in `UI_interface.h`. */ -#define UI_MENU_ARROW_SEP "\xe2\x96\xb6" +#define UI_MENU_ARROW_SEP "\xe2\x96\xb8" TEST(string_search, damerau_levenshtein_distance) { diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 5ca026ae9a3..f8bf97b17e9 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -19,6 +19,7 @@ set(INC ../windowmanager ../../../intern/clog ../../../intern/guardedalloc + ../bmesh # for writefile.c: dna_type_offsets.h ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1ed0f2d5dfe..6fad67eb217 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -359,6 +359,12 @@ static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, oldnewmap_insert_or_replace(onm, entry); } +static void oldnewmap_lib_insert( + FileData *fd, const void *oldaddr, ID *newaddr, int nr) +{ + oldnewmap_insert(fd->libmap, oldaddr, newaddr, nr); +} + void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr) { oldnewmap_insert(onm, oldaddr, newaddr, nr); @@ -1667,7 +1673,7 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd) int i = set_listbasepointers(ptr, lbarray); while (i--) { LISTBASE_FOREACH (ID *, id, lbarray[i]) { - oldnewmap_insert(fd->libmap, id, id, GS(id->name)); + oldnewmap_lib_insert(fd, id, id, GS(id->name)); } } } @@ -1993,7 +1999,7 @@ static void lib_link_id(BlendLibReader *reader, ID *id) { /* NOTE: WM IDProperties are never written to file, hence they should always be NULL here. */ BLI_assert((GS(id->name) != ID_WM) || id->properties == NULL); - IDP_BlendReadLib(reader, id->properties); + IDP_BlendReadLib(reader, id->lib, id->properties); AnimData *adt = BKE_animdata_from_id(id); if (adt != NULL) { @@ -3163,7 +3169,7 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID /* Even though we found our linked ID, there is no guarantee its address * is still the same. */ if (id_old != bhead->old) { - oldnewmap_insert(fd->libmap, bhead->old, id_old, GS(id_old->name)); + oldnewmap_lib_insert(fd, bhead->old, id_old, GS(id_old->name)); } /* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed @@ -3305,7 +3311,7 @@ static bool read_libblock_undo_restore( /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old). * Note that existing datablocks in memory (which pointer value would be id_old) are not * remapped anymore, so no need to store this info here. */ - oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); + oldnewmap_lib_insert(fd, bhead->old, id_old, bhead->code); *r_id_old = id_old; return true; @@ -3388,7 +3394,7 @@ static BHead *read_libblock(FileData *fd, * Note that existing datablocks in memory (which pointer value would be id_old) are not remapped * remapped anymore, so no need to store this info here. */ ID *id_target = id_old ? id_old : id; - oldnewmap_insert(fd->libmap, bhead->old, id_target, bhead->code); + oldnewmap_lib_insert(fd, bhead->old, id_target, bhead->code); if (r_id) { *r_id = id_target; @@ -4201,6 +4207,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) /* ID has not been read yet, add placeholder to the main of the * library it belongs to, so that it will be read later. */ read_libblock(fd, libmain, bhead, fd->id_tag_extra | LIB_TAG_INDIRECT, false, &id); + BLI_assert(id != NULL); id_sort_by_name(which_libbase(libmain, GS(id->name)), id, id->prev); /* commented because this can print way too much */ @@ -4227,7 +4234,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) * (B) forest.blend: contains Forest collection linking in Tree from tree.blend. * (C) shot.blend: links in both Tree from tree.blend and Forest from forest.blend. */ - oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); + oldnewmap_lib_insert(fd, bhead->old, id, bhead->code); /* If "id" is a real data-block and not a placeholder, we need to * update fd->libmap to replace ID_LINK_PLACEHOLDER with the real @@ -4263,6 +4270,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) fd->id_tag_extra | LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id); + BLI_assert(id != NULL); id_sort_by_name(which_libbase(mainvar, GS(id->name)), id, id->prev); } else { @@ -4275,7 +4283,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) /* this is actually only needed on UI call? when ID was already read before, * and another append happens which invokes same ID... * in that case the lookup table needs this entry */ - oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); + oldnewmap_lib_insert(fd, bhead->old, id, bhead->code); /* commented because this can print way too much */ // if (G.debug & G_DEBUG) printf("expand: already read %s\n", id->name); } @@ -4395,7 +4403,7 @@ static ID *link_named_part( else { /* already linked */ CLOG_WARN(&LOG, "Append: ID '%s' is already linked", id->name); - oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); + oldnewmap_lib_insert(fd, bhead->old, id, bhead->code); if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) { id->tag &= ~LIB_TAG_INDIRECT; id->flag &= ~LIB_INDIRECT_WEAK_LINK; @@ -4901,11 +4909,15 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } } - Main *main_newid = BKE_main_new(); for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) { - /* Drop weak links for which no data-block was found. */ + /* Drop weak links for which no data-block was found. + * Since this can remap pointers in `libmap` of all libraries, it needs to be performed in its + * own loop, before any call to `lib_link_all` (and the freeing of the libraries' filedata). */ read_library_clear_weak_links(basefd, mainlist, mainptr); + } + Main *main_newid = BKE_main_new(); + for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) { /* Do versioning for newly added linked data-blocks. If no data-blocks * were read from a library versionfile will still be zero and we can * skip it. */ diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index d2a55f6f37e..823385727e1 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -18,6 +18,7 @@ #include "BKE_animsys.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_main_namemap.h" #include "BKE_node.h" #include "MEM_guardedalloc.h" @@ -66,6 +67,7 @@ ID *do_versions_rename_id(Main *bmain, } } if (id != nullptr) { + BKE_main_namemap_remove_name(bmain, id, id->name + 2); BLI_strncpy(id->name + 2, name_dst, sizeof(id->name) - 2); /* We know it's unique, this just sorts. */ BLI_libblock_ensure_unique_name(bmain, id->name); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc index 6474f853390..129e0093d11 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc @@ -15,6 +15,8 @@ #include "BKE_animsys.h" +#include "RNA_path.h" + namespace blender::deg { /* Animated property storage. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 4cbb2ce7060..be087c0b2d4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -93,6 +93,7 @@ #include "BKE_world.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "RNA_types.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 0cb0b60dfb0..7a78280f1f0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -15,6 +15,7 @@ #include "DNA_ID.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_types.h" #include "BLI_string.h" diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 9a047c70d01..19339fa34ea 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -23,6 +23,7 @@ #include "DNA_scene_types.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "DEG_depsgraph.h" diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 9744f2e3cee..9d3b392d7b3 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -138,6 +138,7 @@ set(SRC engines/eevee_next/eevee_film.cc engines/eevee_next/eevee_instance.cc engines/eevee_next/eevee_material.cc + engines/eevee_next/eevee_motion_blur.cc engines/eevee_next/eevee_pipeline.cc engines/eevee_next/eevee_renderbuffers.cc engines/eevee_next/eevee_sampling.cc @@ -367,7 +368,12 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl engines/eevee_next/shaders/eevee_geom_world_vert.glsl + engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl + engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl + engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl + engines/eevee_next/shaders/eevee_motion_blur_lib.glsl engines/eevee_next/shaders/eevee_nodetree_lib.glsl + engines/eevee_next/shaders/eevee_sampling_lib.glsl engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl engines/eevee_next/shaders/eevee_surf_depth_frag.glsl engines/eevee_next/shaders/eevee_surf_forward_frag.glsl diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index 1e7979b594e..cb02689f34a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -45,3 +45,7 @@ #define LIGHTPROBE_FILTER_VIS_GROUP_SIZE 16 #define FILM_GROUP_SIZE 16 + +#define MOTION_BLUR_GROUP_SIZE 32 + +#define MOTION_BLUR_DILATE_GROUP_SIZE 512 diff --git a/source/blender/draw/engines/eevee_next/eevee_film.cc b/source/blender/draw/engines/eevee_next/eevee_film.cc index 49f43265aa8..60e5f95d803 100644 --- a/source/blender/draw/engines/eevee_next/eevee_film.cc +++ b/source/blender/draw/engines/eevee_next/eevee_film.cc @@ -183,20 +183,17 @@ void Film::init(const int2 &extent, const rcti *output_rect) * Using the render pass ensure we store the center depth. */ render_passes |= EEVEE_RENDER_PASS_Z; } - /* TEST */ - render_passes |= EEVEE_RENDER_PASS_VECTOR; } else { /* Render Case. */ render_passes = eViewLayerEEVEEPassType(inst_.view_layer->eevee.render_passes); - render_passes |= EEVEE_RENDER_PASS_COMBINED; - #define ENABLE_FROM_LEGACY(name_legacy, name_eevee) \ SET_FLAG_FROM_TEST(render_passes, \ (inst_.view_layer->passflag & SCE_PASS_##name_legacy) != 0, \ EEVEE_RENDER_PASS_##name_eevee); + ENABLE_FROM_LEGACY(COMBINED, COMBINED) ENABLE_FROM_LEGACY(Z, Z) ENABLE_FROM_LEGACY(MIST, MIST) ENABLE_FROM_LEGACY(NORMAL, NORMAL) @@ -209,6 +206,7 @@ void Film::init(const int2 &extent, const rcti *output_rect) ENABLE_FROM_LEGACY(DIFFUSE_DIRECT, DIFFUSE_LIGHT) ENABLE_FROM_LEGACY(GLOSSY_DIRECT, SPECULAR_LIGHT) ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT) + ENABLE_FROM_LEGACY(VECTOR, VECTOR) #undef ENABLE_FROM_LEGACY } @@ -216,6 +214,11 @@ void Film::init(const int2 &extent, const rcti *output_rect) /* Filter obsolete passes. */ render_passes &= ~(EEVEE_RENDER_PASS_UNUSED_8 | EEVEE_RENDER_PASS_BLOOM); + if (scene_eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) { + /* Disable motion vector pass if motion blur is enabled. */ + render_passes &= ~EEVEE_RENDER_PASS_VECTOR; + } + /* TODO(@fclem): Can't we rely on depsgraph update notification? */ if (assign_if_different(enabled_passes_, render_passes)) { sampling.reset(); @@ -383,7 +386,7 @@ void Film::sync() DRW_shgroup_uniform_block_ref(grp, "camera_curr", &(*velocity.camera_steps[STEP_CURRENT])); DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*velocity.camera_steps[step_next])); DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &rbuffers.depth_tx); - DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &rbuffers.combined_tx); + DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &combined_final_tx_); DRW_shgroup_uniform_texture_ref(grp, "normal_tx", &rbuffers.normal_tx); DRW_shgroup_uniform_texture_ref(grp, "vector_tx", &rbuffers.vector_tx); DRW_shgroup_uniform_texture_ref(grp, "diffuse_light_tx", &rbuffers.diffuse_light_tx); @@ -458,6 +461,10 @@ float2 Film::pixel_jitter_get() const eViewLayerEEVEEPassType Film::enabled_passes_get() const { + if (inst_.is_viewport() && data_.use_reprojection) { + /* Enable motion vector rendering but not the accumulation buffer. */ + return enabled_passes_ | EEVEE_RENDER_PASS_VECTOR; + } return enabled_passes_; } @@ -538,7 +545,7 @@ void Film::update_sample_table() } } -void Film::accumulate(const DRWView *view) +void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx) { if (inst_.is_viewport()) { DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); @@ -554,6 +561,8 @@ void Film::accumulate(const DRWView *view) update_sample_table(); + combined_final_tx_ = combined_final_tx; + /* Need to update the static references as there could have change from a previous swap. */ weight_src_tx_ = weight_tx_.current(); weight_dst_tx_ = weight_tx_.next(); @@ -580,12 +589,14 @@ void Film::display() BLI_assert(inst_.is_viewport()); /* Acquire dummy render buffers for correct binding. They will not be used. */ - inst_.render_buffers.acquire(int2(1), (void *)this); + inst_.render_buffers.acquire(int2(1)); DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); GPU_framebuffer_bind(dfbl->default_fb); GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data_.offset), UNPACK2(data_.extent)); + combined_final_tx_ = inst_.render_buffers.combined_tx; + /* Need to update the static references as there could have change from a previous swap. */ weight_src_tx_ = weight_tx_.current(); weight_dst_tx_ = weight_tx_.next(); diff --git a/source/blender/draw/engines/eevee_next/eevee_film.hh b/source/blender/draw/engines/eevee_next/eevee_film.hh index 1165b9a4c12..d47e3dfa24b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_film.hh +++ b/source/blender/draw/engines/eevee_next/eevee_film.hh @@ -50,6 +50,8 @@ class Film { /** Static reference as SwapChain does not actually move the objects when swapping. */ GPUTexture *combined_src_tx_ = nullptr; GPUTexture *combined_dst_tx_ = nullptr; + /** Incomming combined buffer with post fx applied (motion blur + depth of field). */ + GPUTexture *combined_final_tx_ = nullptr; /** Weight buffers. Double buffered to allow updating it during accumulation. */ SwapChain<Texture, 2> weight_tx_; /** Static reference as SwapChain does not actually move the objects when swapping. */ @@ -74,7 +76,7 @@ class Film { void end_sync(); /** Accumulate the newly rendered sample contained in #RenderBuffers and blit to display. */ - void accumulate(const DRWView *view); + void accumulate(const DRWView *view, GPUTexture *combined_final_tx); /** Blit to display. No rendered sample needed. */ void display(); diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 9f8cf6dc6ba..70b5cb7d98f 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -60,6 +60,8 @@ void Instance::init(const int2 &output_res, sampling.init(scene); camera.init(); film.init(output_res, output_rect); + velocity.init(); + motion_blur.init(); main_view.init(); } @@ -92,15 +94,14 @@ void Instance::update_eval_members() void Instance::begin_sync() { materials.begin_sync(); - velocity.begin_sync(); + velocity.begin_sync(); /* NOTE: Also syncs camera. */ gpencil_engine_enabled = false; - render_buffers.sync(); + motion_blur.sync(); pipelines.sync(); main_view.sync(); world.sync(); - camera.sync(); film.sync(); } @@ -212,22 +213,12 @@ void Instance::render_sample() sampling.step(); main_view.render(); -} - -/** \} */ -/* -------------------------------------------------------------------- */ -/** \name Interface - * \{ */ + motion_blur.step(); +} -void Instance::render_frame(RenderLayer *render_layer, const char *view_name) +void Instance::render_read_result(RenderLayer *render_layer, const char *view_name) { - while (!sampling.finished()) { - this->render_sample(); - /* TODO(fclem) print progression. */ - } - - /* Read Results. */ eViewLayerEEVEEPassType pass_bits = film.enabled_passes_get(); for (auto i : IndexRange(EEVEE_RENDER_PASS_MAX_BIT)) { eViewLayerEEVEEPassType pass_type = eViewLayerEEVEEPassType(pass_bits & (1 << i)); @@ -240,7 +231,6 @@ void Instance::render_frame(RenderLayer *render_layer, const char *view_name) if (rp) { float *result = film.read_pass(pass_type); if (result) { - std::cout << "read " << pass_name << std::endl; BLI_mutex_lock(&render->update_render_passes_mutex); /* WORKAROUND: We use texture read to avoid using a framebuffer to get the render result. * However, on some implementation, we need a buffer with a few extra bytes for the read to @@ -252,6 +242,45 @@ void Instance::render_frame(RenderLayer *render_layer, const char *view_name) } } } + + /* The vector pass is initialized to weird values. Set it to neutral value if not rendered. */ + if ((pass_bits & EEVEE_RENDER_PASS_VECTOR) == 0) { + const char *vector_pass_name = Film::pass_to_render_pass_name(EEVEE_RENDER_PASS_VECTOR); + RenderPass *vector_rp = RE_pass_find_by_name(render_layer, vector_pass_name, view_name); + if (vector_rp) { + memset(vector_rp->rect, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Interface + * \{ */ + +void Instance::render_frame(RenderLayer *render_layer, const char *view_name) +{ + while (!sampling.finished()) { + this->render_sample(); + + /* TODO(fclem) print progression. */ +#if 0 + /* TODO(fclem): Does not currently work. But would be better to just display to 2D view like + * cycles does. */ + if (G.background == false && first_read) { + /* Allow to preview the first sample. */ + /* TODO(fclem): Might want to not do this during animation render to avoid too much stall. */ + this->render_read_result(render_layer, view_name); + first_read = false; + DRW_render_context_disable(render->re); + /* Allow the 2D viewport to grab the ticket mutex to display the render. */ + DRW_render_context_enable(render->re); + } +#endif + } + + this->render_read_result(render_layer, view_name); } void Instance::draw_viewport(DefaultFramebufferList *dfbl) @@ -260,7 +289,10 @@ void Instance::draw_viewport(DefaultFramebufferList *dfbl) render_sample(); velocity.step_swap(); - if (!sampling.finished_viewport()) { + /* Do not request redraw during viewport animation to lock the framerate to the animation + * playback rate. This is in order to preserve motion blur aspect and also to avoid TAA reset + * that can show flickering. */ + if (!sampling.finished_viewport() && !DRW_state_is_playback()) { DRW_viewport_request_redraw(); } diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index 1efda769648..d714111a3c6 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -18,6 +18,7 @@ #include "eevee_camera.hh" #include "eevee_film.hh" #include "eevee_material.hh" +#include "eevee_motion_blur.hh" #include "eevee_pipeline.hh" #include "eevee_renderbuffers.hh" #include "eevee_sampling.hh" @@ -34,6 +35,7 @@ namespace blender::eevee { */ class Instance { friend VelocityModule; + friend MotionBlurModule; public: ShaderModule &shaders; @@ -41,6 +43,7 @@ class Instance { MaterialModule materials; PipelineModule pipelines; VelocityModule velocity; + MotionBlurModule motion_blur; Sampling sampling; Camera camera; Film film; @@ -76,6 +79,7 @@ class Instance { materials(*this), pipelines(*this), velocity(*this), + motion_blur(*this), sampling(*this), camera(*this), film(*this), @@ -138,6 +142,7 @@ class Instance { RenderEngine *engine, Depsgraph *depsgraph); void render_sample(); + void render_read_result(RenderLayer *render_layer, const char *view_name); void mesh_sync(Object *ob, ObjectHandle &ob_handle); diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc new file mode 100644 index 00000000000..660eb9f1e22 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc @@ -0,0 +1,262 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + */ + +// #include "BLI_map.hh" +#include "DEG_depsgraph_query.h" + +#include "eevee_instance.hh" +#include "eevee_motion_blur.hh" +// #include "eevee_sampling.hh" +// #include "eevee_shader_shared.hh" +// #include "eevee_velocity.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name MotionBlurModule + * + * \{ */ + +void MotionBlurModule::init() +{ + const Scene *scene = inst_.scene; + + enabled_ = (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) != 0; + + if (!enabled_) { + motion_blur_fx_enabled_ = false; + return; + } + + /* Take into account the steps needed for fx motion blur. */ + int steps_count = max_ii(1, scene->eevee.motion_blur_steps) * 2 + 1; + + time_steps_.resize(steps_count); + + initial_frame_ = scene->r.cfra; + initial_subframe_ = scene->r.subframe; + frame_time_ = initial_frame_ + initial_subframe_; + shutter_position_ = scene->eevee.motion_blur_position; + shutter_time_ = scene->eevee.motion_blur_shutter; + + data_.depth_scale = scene->eevee.motion_blur_depth_scale; + motion_blur_fx_enabled_ = true; /* TODO(fclem): UI option. */ + + /* Viewport stops here. We only do Post-FX motion blur. */ + if (inst_.is_viewport()) { + enabled_ = false; + return; + } + + /* Without this there is the possibility of the curve table not being allocated. */ + BKE_curvemapping_changed((struct CurveMapping *)&scene->r.mblur_shutter_curve, false); + + Vector<float> cdf(CM_TABLE); + Sampling::cdf_from_curvemapping(scene->r.mblur_shutter_curve, cdf); + Sampling::cdf_invert(cdf, time_steps_); + + for (float &time : time_steps_) { + time = this->shutter_time_to_scene_time(time); + } + + step_id_ = 1; + + if (motion_blur_fx_enabled_) { + /* A bit weird but we have to sync the first 2 steps here because the step() + * function is only called after rendering a sample. */ + inst_.velocity.step_sync(STEP_PREVIOUS, time_steps_[0]); + inst_.velocity.step_sync(STEP_NEXT, time_steps_[2]); + } + inst_.set_time(time_steps_[1]); +} + +/* Runs after rendering a sample. */ +void MotionBlurModule::step() +{ + if (!enabled_) { + return; + } + + if (inst_.sampling.finished()) { + /* Restore original frame number. This is because the render pipeline expects it. */ + RE_engine_frame_set(inst_.render, initial_frame_, initial_subframe_); + } + else if (inst_.sampling.do_render_sync()) { + /* Time to change motion step. */ + BLI_assert(time_steps_.size() > step_id_ + 2); + step_id_ += 2; + + if (motion_blur_fx_enabled_) { + inst_.velocity.step_swap(); + inst_.velocity.step_sync(eVelocityStep::STEP_NEXT, time_steps_[step_id_ + 1]); + } + inst_.set_time(time_steps_[step_id_]); + } +} + +float MotionBlurModule::shutter_time_to_scene_time(float time) +{ + switch (shutter_position_) { + case SCE_EEVEE_MB_START: + /* No offset. */ + break; + case SCE_EEVEE_MB_CENTER: + time -= 0.5f; + break; + case SCE_EEVEE_MB_END: + time -= 1.0; + break; + default: + BLI_assert(!"Invalid motion blur position enum!"); + break; + } + time *= shutter_time_; + time += frame_time_; + return time; +} + +void MotionBlurModule::sync() +{ + /* Disable motion blur in viewport when changing camera projection type. + * Avoids really high velocities. */ + if (inst_.velocity.camera_changed_projection()) { + motion_blur_fx_enabled_ = false; + } + + if (!motion_blur_fx_enabled_) { + return; + } + + eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT; + RenderBuffers &render_buffers = inst_.render_buffers; + + { + /* Create max velocity tiles. */ + DRW_PASS_CREATE(tiles_flatten_ps_, DRW_STATE_NO_DRAW); + eShaderType shader = (inst_.is_viewport()) ? MOTION_BLUR_TILE_FLATTEN_VIEWPORT : + MOTION_BLUR_TILE_FLATTEN_RENDER; + GPUShader *sh = inst_.shaders.static_shader_get(shader); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tiles_flatten_ps_); + inst_.velocity.bind_resources(grp); + DRW_shgroup_uniform_block(grp, "motion_blur_buf", data_); + DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &render_buffers.depth_tx); + DRW_shgroup_uniform_image_ref(grp, "velocity_img", &render_buffers.vector_tx); + DRW_shgroup_uniform_image_ref(grp, "out_tiles_img", &tiles_tx_); + + DRW_shgroup_call_compute_ref(grp, dispatch_flatten_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_TEXTURE_FETCH); + } + { + /* Expand max velocity tiles by spreading them in their neighborhood. */ + DRW_PASS_CREATE(tiles_dilate_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(MOTION_BLUR_TILE_DILATE); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tiles_dilate_ps_); + DRW_shgroup_storage_block(grp, "tile_indirection_buf", tile_indirection_buf_); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_img", &tiles_tx_); + + DRW_shgroup_call_compute_ref(grp, dispatch_dilate_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE); + } + { + /* Do the motion blur gather algorithm. */ + DRW_PASS_CREATE(gather_ps_, DRW_STATE_NO_DRAW); + GPUShader *sh = inst_.shaders.static_shader_get(MOTION_BLUR_GATHER); + DRWShadingGroup *grp = DRW_shgroup_create(sh, gather_ps_); + inst_.sampling.bind_resources(grp); + DRW_shgroup_uniform_block(grp, "motion_blur_buf", data_); + DRW_shgroup_storage_block(grp, "tile_indirection_buf", tile_indirection_buf_); + DRW_shgroup_uniform_texture_ref_ex(grp, "depth_tx", &render_buffers.depth_tx, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "velocity_tx", &render_buffers.vector_tx, no_filter); + DRW_shgroup_uniform_texture_ref_ex(grp, "in_color_tx", &input_color_tx_, no_filter); + DRW_shgroup_uniform_image_ref(grp, "in_tiles_img", &tiles_tx_); + DRW_shgroup_uniform_image_ref(grp, "out_color_img", &output_color_tx_); + + DRW_shgroup_call_compute_ref(grp, dispatch_gather_size_); + DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH); + } +} + +void MotionBlurModule::render(GPUTexture **input_tx, GPUTexture **output_tx) +{ + if (!motion_blur_fx_enabled_) { + return; + } + + const Texture &depth_tx = inst_.render_buffers.depth_tx; + + int2 extent = {depth_tx.width(), depth_tx.height()}; + int2 tiles_extent = math::divide_ceil(extent, int2(MOTION_BLUR_TILE_SIZE)); + + if (inst_.is_viewport()) { + float frame_delta = fabsf(inst_.velocity.step_time_delta_get(STEP_PREVIOUS, STEP_CURRENT)); + /* Avoid highly disturbing blurs, during navigation with high shutter time. */ + if (frame_delta > 0.0f && !DRW_state_is_navigating()) { + /* Rescale motion blur intensity to be shutter time relative and avoid long streak when we + * have frame skipping. Always try to stick to what the render frame would look like. */ + data_.motion_scale = float2(shutter_time_ / frame_delta); + } + else { + /* There is no time change. Motion only comes from viewport navigation and object transform. + * Apply motion blur as smoothing and only blur towards last frame. */ + data_.motion_scale = float2(1.0f, 0.0f); + + if (was_navigating_ != DRW_state_is_navigating()) { + /* Special case for navigation events that only last for one frame (for instance mouse + * scroll for zooming). For this case we have to wait for the next frame before enabling + * the navigation motion blur. */ + was_navigating_ = DRW_state_is_navigating(); + return; + } + } + was_navigating_ = DRW_state_is_navigating(); + + /* Change texture swizzling to avoid complexity in gather pass shader. */ + GPU_texture_swizzle_set(inst_.render_buffers.vector_tx, "rgrg"); + } + else { + data_.motion_scale = float2(1.0f); + } + /* Second motion vector is stored inverted. */ + data_.motion_scale.y = -data_.motion_scale.y; + data_.target_size_inv = 1.0f / float2(extent); + data_.push_update(); + + input_color_tx_ = *input_tx; + output_color_tx_ = *output_tx; + + dispatch_flatten_size_ = int3(tiles_extent, 1); + dispatch_dilate_size_ = int3(math::divide_ceil(tiles_extent, int2(MOTION_BLUR_GROUP_SIZE)), 1); + dispatch_gather_size_ = int3(math::divide_ceil(extent, int2(MOTION_BLUR_GROUP_SIZE)), 1); + + DRW_stats_group_start("Motion Blur"); + + tiles_tx_.acquire(tiles_extent, GPU_RGBA16F); + + GPU_storagebuf_clear_to_zero(tile_indirection_buf_); + + DRW_draw_pass(tiles_flatten_ps_); + DRW_draw_pass(tiles_dilate_ps_); + DRW_draw_pass(gather_ps_); + + tiles_tx_.release(); + + DRW_stats_group_end(); + + if (inst_.is_viewport()) { + /* Reset swizzle since this texture might be reused in other places. */ + GPU_texture_swizzle_set(inst_.render_buffers.vector_tx, "rgba"); + } + + /* Swap buffers so that next effect has the right input. */ + *input_tx = output_color_tx_; + *output_tx = input_color_tx_; +} + +/** \} */ + +} // namespace blender::eevee
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh b/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh new file mode 100644 index 00000000000..310e94a702b --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.hh @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * Motion blur is done by accumulating scene samples over shutter time. + * Since the number of step is discrete, quite low, and not per pixel randomized, + * we couple this with a post processing motion blur. + * + * The post-fx motion blur is done in two directions, from the previous step and to the next. + * + * For a scene with 3 motion steps, a flat shutter curve and shutter time of 2 frame + * centered on frame we have: + * + * |--------------------|--------------------| + * -1 0 1 Frames + * + * |-------------|-------------|-------------| + * 1 2 3 Motion steps + * + * |------|------|------|------|------|------| + * 0 1 2 4 5 6 7 Time Steps + * + * |-------------| One motion step blurs this range. + * -1 | +1 Objects and geometry steps are recorded here. + * 0 Scene is rendered here. + * + * Since motion step N and N+1 share one time step we reuse it to avoid an extra scene evaluation. + * + * Note that we have to evaluate -1 and +1 time steps before rendering so eval order is -1, +1, 0. + * This is because all GPUBatches from the DRWCache are being free when changing a frame. + * + * For viewport, we only have the current and previous step data to work with. So we center the + * blur on the current frame and extrapolate the motion. + * + * The Post-FX motion blur is based on: + * "A Fast and Stable Feature-Aware Motion Blur Filter" + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + */ + +#pragma once + +#include "BLI_map.hh" +#include "DEG_depsgraph_query.h" + +#include "eevee_sampling.hh" +#include "eevee_shader_shared.hh" +#include "eevee_velocity.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name MotionBlur + * + * \{ */ + +/** + * Manages time-steps evaluations and accumulation Motion blur. + * Also handles Post process motion blur. + */ +class MotionBlurModule { + private: + Instance &inst_; + + /** + * Array containing all steps (in scene time) we need to evaluate (not render). + * Only odd steps are rendered. The even ones are evaluated for fx motion blur. + */ + Vector<float> time_steps_; + + /** Copy of input frame and sub-frame to restore after render. */ + int initial_frame_; + float initial_subframe_; + /** Time of the frame we are rendering. */ + float frame_time_; + /** Enum controlling when the shutter opens. See SceneEEVEE.motion_blur_position. */ + int shutter_position_; + /** Time in scene frame the shutter is open. Controls the amount of blur. */ + float shutter_time_; + + /** True if motion blur is enabled as a module. */ + bool enabled_ = false; + /** True if motion blur post-fx is enabled. */ + float motion_blur_fx_enabled_ = false; + /** True if last viewport redraw state was already in navigation state. */ + bool was_navigating_ = false; + + int step_id_ = 0; + + /** Velocity tiles used to guide and speedup the gather pass. */ + TextureFromPool tiles_tx_; + + GPUTexture *input_color_tx_ = nullptr; + GPUTexture *output_color_tx_ = nullptr; + + DRWPass *tiles_flatten_ps_ = nullptr; + DRWPass *tiles_dilate_ps_ = nullptr; + DRWPass *gather_ps_ = nullptr; + + MotionBlurTileIndirectionBuf tile_indirection_buf_; + MotionBlurDataBuf data_; + /** Dispatch size for full-screen passes. */ + int3 dispatch_flatten_size_ = int3(0); + int3 dispatch_dilate_size_ = int3(0); + int3 dispatch_gather_size_ = int3(0); + + public: + MotionBlurModule(Instance &inst) : inst_(inst){}; + ~MotionBlurModule(){}; + + void init(); + + void step(); + + void sync(); + + bool postfx_enabled() const + { + return motion_blur_fx_enabled_; + } + + void render(GPUTexture **input_tx, GPUTexture **output_tx); + + private: + float shutter_time_to_scene_time(float time); +}; + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc index c60054496c1..b69fde7b26c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc +++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc @@ -24,25 +24,7 @@ namespace blender::eevee { -void RenderBuffers::sync() -{ - depth_tx.sync(); - combined_tx.sync(); - - normal_tx.sync(); - vector_tx.sync(); - diffuse_light_tx.sync(); - diffuse_color_tx.sync(); - specular_light_tx.sync(); - specular_color_tx.sync(); - volume_light_tx.sync(); - emission_tx.sync(); - environment_tx.sync(); - shadow_tx.sync(); - ambient_occlusion_tx.sync(); -} - -void RenderBuffers::acquire(int2 extent, void *owner) +void RenderBuffers::acquire(int2 extent) { auto pass_extent = [&](eViewLayerEEVEEPassType pass_bit) -> int2 { /* Use dummy texture for disabled passes. Allows correct bindings. */ @@ -53,25 +35,26 @@ void RenderBuffers::acquire(int2 extent, void *owner) eGPUTextureFormat float_format = GPU_R16F; /* Depth and combined are always needed. */ - depth_tx.acquire(extent, GPU_DEPTH24_STENCIL8, owner); - combined_tx.acquire(extent, color_format, owner); + depth_tx.acquire(extent, GPU_DEPTH24_STENCIL8); + combined_tx.acquire(extent, color_format); - bool do_vector_render_pass = inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR; + bool do_vector_render_pass = (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR) || + (inst_.motion_blur.postfx_enabled() && !inst_.is_viewport()); /* Only RG16F when only doing only reprojection or motion blur. */ eGPUTextureFormat vector_format = do_vector_render_pass ? GPU_RGBA16F : GPU_RG16F; /* TODO(fclem): Make vector pass allocation optional if no TAA or motion blur is needed. */ - vector_tx.acquire(extent, vector_format, owner); - - normal_tx.acquire(pass_extent(EEVEE_RENDER_PASS_NORMAL), color_format, owner); - diffuse_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_LIGHT), color_format, owner); - diffuse_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_COLOR), color_format, owner); - specular_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_LIGHT), color_format, owner); - specular_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_COLOR), color_format, owner); - volume_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VOLUME_LIGHT), color_format, owner); - emission_tx.acquire(pass_extent(EEVEE_RENDER_PASS_EMIT), color_format, owner); - environment_tx.acquire(pass_extent(EEVEE_RENDER_PASS_ENVIRONMENT), color_format, owner); - shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format, owner); - ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format, owner); + vector_tx.acquire(extent, vector_format); + + normal_tx.acquire(pass_extent(EEVEE_RENDER_PASS_NORMAL), color_format); + diffuse_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_LIGHT), color_format); + diffuse_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_COLOR), color_format); + specular_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_LIGHT), color_format); + specular_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_COLOR), color_format); + volume_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VOLUME_LIGHT), color_format); + emission_tx.acquire(pass_extent(EEVEE_RENDER_PASS_EMIT), color_format); + environment_tx.acquire(pass_extent(EEVEE_RENDER_PASS_ENVIRONMENT), color_format); + shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format); + ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format); const AOVsInfoData &aovs = inst_.film.aovs_info; aov_color_tx.ensure_2d_array( diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh index 8c91fed2f0f..787f5604aa4 100644 --- a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh +++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh @@ -48,9 +48,8 @@ class RenderBuffers { public: RenderBuffers(Instance &inst) : inst_(inst){}; - void sync(); /* Acquires (also ensures) the render buffer before rendering to them. */ - void acquire(int2 extent, void *owner); + void acquire(int2 extent); void release(); }; diff --git a/source/blender/draw/engines/eevee_next/eevee_sampling.cc b/source/blender/draw/engines/eevee_next/eevee_sampling.cc index 1d320c75f16..76a0e98638b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sampling.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sampling.cc @@ -232,7 +232,7 @@ void Sampling::cdf_from_curvemapping(const CurveMapping &curve, Vector<float> &c BLI_assert(cdf.size() > 1); cdf[0] = 0.0f; /* Actual CDF evaluation. */ - for (int u : cdf.index_range()) { + for (int u : IndexRange(cdf.size() - 1)) { float x = (float)(u + 1) / (float)(cdf.size() - 1); cdf[u + 1] = cdf[u] + BKE_curvemapping_evaluateF(&curve, 0, x); } diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 7db9692783a..782e73f6dd0 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -82,6 +82,14 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_film_frag"; case FILM_COMP: return "eevee_film_comp"; + case MOTION_BLUR_GATHER: + return "eevee_motion_blur_gather"; + case MOTION_BLUR_TILE_DILATE: + return "eevee_motion_blur_tiles_dilate"; + case MOTION_BLUR_TILE_FLATTEN_RENDER: + return "eevee_motion_blur_tiles_flatten_render"; + case MOTION_BLUR_TILE_FLATTEN_VIEWPORT: + return "eevee_motion_blur_tiles_flatten_viewport"; /* To avoid compiler warning about missing case. */ case MAX_SHADER_TYPE: return ""; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh index 280aaab4e1c..8dc61fbae0b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh @@ -29,6 +29,11 @@ enum eShaderType { FILM_FRAG = 0, FILM_COMP, + MOTION_BLUR_GATHER, + MOTION_BLUR_TILE_DILATE, + MOTION_BLUR_TILE_FLATTEN_RENDER, + MOTION_BLUR_TILE_FLATTEN_VIEWPORT, + MAX_SHADER_TYPE, }; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index 3c10f633740..70de4101bb9 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -124,7 +124,7 @@ struct CameraData { float clip_far; eCameraType type; - bool initialized; + bool1 initialized; #ifdef __cplusplus /* Small constructor to allow detecting new buffers. */ @@ -312,6 +312,40 @@ BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Motion Blur + * \{ */ + +#define MOTION_BLUR_TILE_SIZE 32 +#define MOTION_BLUR_MAX_TILE 512 /* 16384 / MOTION_BLUR_TILE_SIZE */ +struct MotionBlurData { + /** As the name suggests. Used to avoid a division in the sampling. */ + float2 target_size_inv; + /** Viewport motion scaling factor. Make blur relative to frame time not render time. */ + float2 motion_scale; + /** Depth scaling factor. Avoid blurring background behind moving objects. */ + float depth_scale; + + float _pad0, _pad1, _pad2; +}; +BLI_STATIC_ASSERT_ALIGN(MotionBlurData, 16) + +/* For some reasons some GLSL compilers do not like this struct. + * So we declare it as a uint array instead and do indexing ourselves. */ +#ifdef __cplusplus +struct MotionBlurTileIndirection { + /** + * Stores indirection to the tile with the highest velocity covering each tile. + * This is stored using velocity in the MSB to be able to use atomicMax operations. + */ + uint prev[MOTION_BLUR_MAX_TILE][MOTION_BLUR_MAX_TILE]; + uint next[MOTION_BLUR_MAX_TILE][MOTION_BLUR_MAX_TILE]; +}; +BLI_STATIC_ASSERT_ALIGN(MotionBlurTileIndirection, 16) +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Ray-Tracing * \{ */ @@ -375,6 +409,8 @@ using SamplingDataBuf = draw::StorageBuffer<SamplingData>; using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>; using VelocityIndexBuf = draw::StorageArrayBuffer<VelocityIndex, 16>; using VelocityObjectBuf = draw::StorageArrayBuffer<float4x4, 16>; +using MotionBlurDataBuf = draw::UniformBuffer<MotionBlurData>; +using MotionBlurTileIndirectionBuf = draw::StorageBuffer<MotionBlurTileIndirection, true>; } // namespace blender::eevee #endif diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc index 048daf1b2db..36734f0c28c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc @@ -32,13 +32,16 @@ namespace blender::eevee { void VelocityModule::init() { - if (inst_.render && (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR)) { - /* No motion blur and the vector pass was requested. Do the step sync here. */ + if (inst_.render && (inst_.film.enabled_passes_get() & EEVEE_RENDER_PASS_VECTOR) != 0) { + /* No motion blur and the vector pass was requested. Do the steps sync here. */ const Scene *scene = inst_.scene; float initial_time = scene->r.cfra + scene->r.subframe; step_sync(STEP_PREVIOUS, initial_time - 1.0f); step_sync(STEP_NEXT, initial_time + 1.0f); + inst_.set_time(initial_time); + step_ = STEP_CURRENT; + /* Let the main sync loop handle the current step. */ } } @@ -64,10 +67,12 @@ void VelocityModule::step_camera_sync() { inst_.camera.sync(); *camera_steps[step_] = inst_.camera.data_get(); + step_time[step_] = inst_.scene->r.cfra + inst_.scene->r.subframe; /* Fix undefined camera steps when rendering is starting. */ if ((step_ == STEP_CURRENT) && (camera_steps[STEP_PREVIOUS]->initialized == false)) { *camera_steps[STEP_PREVIOUS] = *static_cast<CameraData *>(camera_steps[step_]); camera_steps[STEP_PREVIOUS]->initialized = true; + step_time[STEP_PREVIOUS] = step_time[step_]; } } @@ -212,6 +217,7 @@ void VelocityModule::step_swap() SWAP(VelocityObjectBuf *, object_steps[step_a], object_steps[step_b]); SWAP(VelocityGeometryBuf *, geometry_steps[step_a], geometry_steps[step_b]); SWAP(CameraDataBuf *, camera_steps[step_a], camera_steps[step_b]); + SWAP(float, step_time[step_a], step_time[step_b]); for (VelocityObjectData &vel : velocity_map.values()) { vel.obj.ofs[step_a] = vel.obj.ofs[step_b]; @@ -238,10 +244,7 @@ void VelocityModule::step_swap() void VelocityModule::begin_sync() { - if (inst_.is_viewport()) { - /* Viewport always evaluate current step. */ - step_ = STEP_CURRENT; - } + step_ = STEP_CURRENT; step_camera_sync(); object_steps_usage[step_] = 0; } @@ -360,6 +363,21 @@ bool VelocityModule::camera_has_motion() const *camera_steps[STEP_NEXT] != *camera_steps[STEP_CURRENT]; } +bool VelocityModule::camera_changed_projection() const +{ + /* Only valid after sync. */ + if (inst_.is_viewport()) { + return camera_steps[STEP_PREVIOUS]->type != camera_steps[STEP_CURRENT]->type; + } + /* Cannot happen in render mode since we set the type during the init phase. */ + return false; +} + +float VelocityModule::step_time_delta_get(eVelocityStep start, eVelocityStep end) const +{ + return step_time[end] - step_time[start]; +} + /** \} */ } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh index 826cd631a96..01b8a5fb8c1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.hh +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh @@ -56,6 +56,8 @@ class VelocityModule { int3 object_steps_usage = int3(0); /** Buffer of all #VelocityIndex used in this frame. Indexed by draw manager resource id. */ VelocityIndexBuf indirection_buf; + /** Frame time at which each steps were evaluated. */ + float3 step_time; /** * Copies of camera data. One for previous and one for next time step. @@ -78,7 +80,6 @@ class VelocityModule { } for (CameraDataBuf *&step_buf : camera_steps) { step_buf = new CameraDataBuf(); - /* */ } }; @@ -112,6 +113,10 @@ class VelocityModule { void bind_resources(DRWShadingGroup *grp); bool camera_has_motion() const; + bool camera_changed_projection() const; + + /* Returns frame time difference between two steps. */ + float step_time_delta_get(eVelocityStep start, eVelocityStep end) const; private: bool object_has_velocity(const Object *ob); diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index 55741bee4df..c7434a662a2 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -79,14 +79,11 @@ void ShadingView::sync() render_view_ = DRW_view_create_sub(main_view_, viewmat_p, winmat_p); // dof_.sync(winmat_p, extent_); - // mb_.sync(extent_); // rt_buffer_opaque_.sync(extent_); // rt_buffer_refract_.sync(extent_); // inst_.hiz_back.view_sync(extent_); // inst_.hiz_front.view_sync(extent_); // inst_.gbuffer.view_sync(extent_); - - postfx_tx_.sync(); } void ShadingView::render() @@ -96,12 +93,8 @@ void ShadingView::render() } /* Query temp textures and create frame-buffers. */ - /* HACK: View name should be unique and static. - * With this, we can reuse the same texture across views. */ - DrawEngineType *owner = (DrawEngineType *)name_; - RenderBuffers &rbufs = inst_.render_buffers; - rbufs.acquire(extent_, owner); + rbufs.acquire(extent_); combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx), GPU_ATTACHMENT_TEXTURE(rbufs.combined_tx)); prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx), @@ -138,9 +131,9 @@ void ShadingView::render() // inst_.lights.debug_draw(view_fb_); // inst_.shadows.debug_draw(view_fb_); - // GPUTexture *final_radiance_tx = render_post(combined_tx_); + GPUTexture *combined_final_tx = render_postfx(rbufs.combined_tx); - inst_.film.accumulate(sub_view_); + inst_.film.accumulate(sub_view_, combined_final_tx); rbufs.release(); postfx_tx_.release(); @@ -148,23 +141,19 @@ void ShadingView::render() DRW_stats_group_end(); } -GPUTexture *ShadingView::render_post(GPUTexture *input_tx) +GPUTexture *ShadingView::render_postfx(GPUTexture *input_tx) { -#if 0 - if (!dof_.postfx_enabled() && !mb_.enabled()) { + if (/*!dof_.postfx_enabled() &&*/ !inst_.motion_blur.postfx_enabled()) { return input_tx; } - /* HACK: View name should be unique and static. - * With this, we can reuse the same texture across views. */ - postfx_tx_.acquire(extent_, GPU_RGBA16F, (void *)name_); + postfx_tx_.acquire(extent_, GPU_RGBA16F); - GPUTexture *velocity_tx = velocity_.view_vectors_get(); GPUTexture *output_tx = postfx_tx_; /* Swapping is done internally. Actual output is set to the next input. */ - dof_.render(depth_tx_, &input_tx, &output_tx); - mb_.render(depth_tx_, velocity_tx, &input_tx, &output_tx); -#endif + // dof_.render(depth_tx_, &input_tx, &output_tx); + inst_.motion_blur.render(&input_tx, &output_tx); + return input_tx; } diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh index c6faebdd0e5..ac8decc7632 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.hh +++ b/source/blender/draw/engines/eevee_next/eevee_view.hh @@ -78,7 +78,7 @@ class ShadingView { void render(); - GPUTexture *render_post(GPUTexture *input_tx); + GPUTexture *render_postfx(GPUTexture *input_tx); private: void update_view(); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl index b286836e8df..135507d956c 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl @@ -636,6 +636,8 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth vec4 normal = texelFetch(normal_tx, film_sample.texel, 0); float depth = texelFetch(depth_tx, film_sample.texel, 0).x; vec4 vector = velocity_resolve(vector_tx, film_sample.texel, depth); + /* Transform to pixel space. */ + vector *= vec4(film_buf.render_extent, -film_buf.render_extent); film_store_depth(texel_film, depth, out_depth); film_store_data(texel_film, film_buf.normal_id, normal, out_color); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl new file mode 100644 index 00000000000..c59b7d7f4df --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_dilate_comp.glsl @@ -0,0 +1,116 @@ + +/** + * Dilate motion vector tiles until we covered maximum velocity. + * Outputs the largest intersecting motion vector in the neighboorhod. + * + */ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_motion_blur_lib.glsl) + +#define DEBUG_BYPASS_DILATION 0 + +struct MotionRect { + ivec2 bottom_left; + ivec2 extent; +}; + +MotionRect compute_motion_rect(ivec2 tile, vec2 motion) +{ +#if DEBUG_BYPASS_DILATION + return MotionRect(tile, ivec2(1)); +#endif + /* Ceil to number of tile touched.*/ + ivec2 point1 = tile + ivec2(sign(motion) * ceil(abs(motion) / float(MOTION_BLUR_TILE_SIZE))); + ivec2 point2 = tile; + + ivec2 max_point = max(point1, point2); + ivec2 min_point = min(point1, point2); + /* Clamp to bounds. */ + max_point = min(max_point, imageSize(in_tiles_img) - 1); + min_point = max(min_point, ivec2(0)); + + MotionRect rect; + rect.bottom_left = min_point; + rect.extent = 1 + max_point - min_point; + return rect; +} + +struct MotionLine { + /** Origin of the line. */ + vec2 origin; + /** Normal to the line direction. */ + vec2 normal; +}; + +MotionLine compute_motion_line(ivec2 tile, vec2 motion) +{ + vec2 dir = safe_normalize(motion); + + MotionLine line; + line.origin = vec2(tile); + /* Rotate 90° Counter-Clockwise. */ + line.normal = vec2(-dir.y, dir.x); + return line; +} + +bool is_inside_motion_line(ivec2 tile, MotionLine motion_line) +{ +#if DEBUG_BYPASS_DILATION + return true; +#endif + /* NOTE: Everything in is tile unit. */ + float dist = point_line_projection_dist(vec2(tile), motion_line.origin, motion_line.normal); + /* In order to be conservative and for simplicity, we use the tiles bounding circles. + * Consider that both the tile and the line have bouding radius of M_SQRT1_2. */ + return abs(dist) < M_SQRT2; +} + +void main() +{ + ivec2 src_tile = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(src_tile, imageSize(in_tiles_img)))) { + return; + } + + vec4 max_motion = imageLoad(in_tiles_img, src_tile); + + MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, src_tile); + MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + if (true) { + /* Rectangular area (in tiles) where the motion vector spreads. */ + MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy); + MotionLine motion_line = compute_motion_line(src_tile, max_motion.xy); + /* Do a conservative rasterization of the line of the motion vector line. */ + for (int x = 0; x < motion_rect.extent.x; x++) { + for (int y = 0; y < motion_rect.extent.y; y++) { + ivec2 tile = motion_rect.bottom_left + ivec2(x, y); + if (is_inside_motion_line(tile, motion_line)) { + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in + * the motion next so that weighting in gather pass is better. */ + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + } + } + } + } + + if (true) { + MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile); + /* Rectangular area (in tiles) where the motion vector spreads. */ + MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw); + MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw); + /* Do a conservative rasterization of the line of the motion vector line. */ + for (int x = 0; x < motion_rect.extent.x; x++) { + for (int y = 0; y < motion_rect.extent.y; y++) { + ivec2 tile = motion_rect.bottom_left + ivec2(x, y); + if (is_inside_motion_line(tile, motion_line)) { + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt); + /* FIXME: This is a bit weird, but for some reason, we need the store the same vector in + * the motion next so that weighting in gather pass is better. */ + motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv); + } + } + } + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl new file mode 100644 index 00000000000..cbbeea25d20 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_flatten_comp.glsl @@ -0,0 +1,103 @@ + +/** + * Shaders that down-sample velocity buffer into squared tile of MB_TILE_DIVISOR pixels wide. + * Outputs the largest motion vector in the tile area. + * Also perform velocity resolve to speedup the convolution pass. + * + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * Adapted from G3D Innovation Engine implementation. + */ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl) + +shared uint payload_prev; +shared uint payload_next; +shared vec2 max_motion_prev; +shared vec2 max_motion_next; + +/* Store velocity magnitude in the MSB and thread id in the LSB. */ +uint pack_payload(vec2 motion, uvec2 thread_id) +{ + /* NOTE: We clamp max velocity to 16k pixels. */ + return (min(uint(ceil(length(motion))), 0xFFFFu) << 16u) | (thread_id.y << 8) | thread_id.x; +} + +/* Return thread index from the payload. */ +uvec2 unpack_payload(uint payload) +{ + return uvec2(payload & 0xFFu, (payload >> 8) & 0xFFu); +} + +void main() +{ + if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) { + payload_prev = 0u; + payload_next = 0u; + } + barrier(); + + uint local_payload_prev = 0u; + uint local_payload_next = 0u; + vec2 local_max_motion_prev; + vec2 local_max_motion_next; + + ivec2 texel = min(ivec2(gl_GlobalInvocationID.xy), imageSize(velocity_img) - 1); + + vec2 render_size = vec2(imageSize(velocity_img).xy); + vec2 uv = (vec2(texel) + 0.5) / render_size; + float depth = texelFetch(depth_tx, texel, 0).r; + vec4 motion = velocity_resolve(imageLoad(velocity_img, texel), uv, depth); +#ifdef FLATTEN_VIEWPORT + /* imageLoad does not perform the swizzling like sampler does. Do it manually. */ + motion = motion.xyxy; +#endif + + /* Store resolved velocity to speedup the gather pass. Out of bounds writes are ignored. + * Unfortunately, we cannot convert to pixel space here since it is also used by TAA and the + * motion blur needs to remain optional. */ + imageStore(velocity_img, ivec2(gl_GlobalInvocationID.xy), velocity_pack(motion)); + /* Clip velocity to viewport bounds (in NDC space). */ + vec2 line_clip; + line_clip.x = line_unit_square_intersect_dist_safe(uv * 2.0 - 1.0, motion.xy * 2.0); + line_clip.y = line_unit_square_intersect_dist_safe(uv * 2.0 - 1.0, -motion.zw * 2.0); + motion *= min(line_clip, vec2(1.0)).xxyy; + /* Convert to pixel space. Note this is only for velocity tiles. */ + motion *= render_size.xyxy; + /* Rescale to shutter relative motion for viewport. */ + motion *= motion_blur_buf.motion_scale.xxyy; + + uint sample_payload_prev = pack_payload(motion.xy, gl_LocalInvocationID.xy); + if (local_payload_prev < sample_payload_prev) { + local_payload_prev = sample_payload_prev; + local_max_motion_prev = motion.xy; + } + + uint sample_payload_next = pack_payload(motion.zw, gl_LocalInvocationID.xy); + if (local_payload_next < sample_payload_next) { + local_payload_next = sample_payload_next; + local_max_motion_next = motion.zw; + } + + /* Compare the local payload with the other threads. */ + atomicMax(payload_prev, local_payload_prev); + atomicMax(payload_next, local_payload_next); + barrier(); + + /* Need to broadcast the result to another thread in order to issue a unique write. */ + if (all(equal(unpack_payload(payload_prev), gl_LocalInvocationID.xy))) { + max_motion_prev = local_max_motion_prev; + } + if (all(equal(unpack_payload(payload_next), gl_LocalInvocationID.xy))) { + max_motion_next = local_max_motion_next; + } + barrier(); + + if (all(equal(gl_LocalInvocationID.xy, uvec2(0)))) { + ivec2 tile_co = ivec2(gl_WorkGroupID.xy); + imageStore(out_tiles_img, tile_co, vec4(max_motion_prev, max_motion_next)); + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl new file mode 100644 index 00000000000..a7329f77181 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl @@ -0,0 +1,221 @@ + +/** + * Perform two gather blur in the 2 motion blur directions + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * With modification from the presentation: + * Next Generation Post Processing in Call of Duty Advanced Warfare + * by Jorge Jimenez + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_motion_blur_lib.glsl) + +const int gather_sample_count = 8; + +/* Converts uv velocity into pixel space. Assumes velocity_tx is the same resolution as the + * target post-fx framebuffer. */ +vec4 motion_blur_sample_velocity(sampler2D velocity_tx, vec2 uv) +{ + /* We can load velocity without velocity_resolve() since we resovled during the flatten pass. */ + vec4 velocity = velocity_unpack(texture(velocity_tx, uv)); + return velocity * vec2(textureSize(velocity_tx, 0)).xyxy * motion_blur_buf.motion_scale.xxyy; +} + +vec2 spread_compare(float center_motion_length, float sample_motion_length, float offset_length) +{ + return saturate(vec2(center_motion_length, sample_motion_length) - offset_length + 1.0); +} + +vec2 depth_compare(float center_depth, float sample_depth) +{ + vec2 depth_scale = vec2(-motion_blur_buf.depth_scale, motion_blur_buf.depth_scale); + return saturate(0.5 + depth_scale * (sample_depth - center_depth)); +} + +/* Kill contribution if not going the same direction. */ +float dir_compare(vec2 offset, vec2 sample_motion, float sample_motion_length) +{ + if (sample_motion_length < 0.5) { + return 1.0; + } + return (dot(offset, sample_motion) > 0.0) ? 1.0 : 0.0; +} + +/* Return background (x) and foreground (y) weights. */ +vec2 sample_weights(float center_depth, + float sample_depth, + float center_motion_length, + float sample_motion_length, + float offset_length) +{ + /* Classify foreground/background. */ + vec2 depth_weight = depth_compare(center_depth, sample_depth); + /* Weight if sample is overlapping or under the center pixel. */ + vec2 spread_weight = spread_compare(center_motion_length, sample_motion_length, offset_length); + return depth_weight * spread_weight; +} + +struct Accumulator { + vec4 fg; + vec4 bg; + /** x: Background, y: Foreground, z: dir. */ + vec3 weight; +}; + +void gather_sample(vec2 screen_uv, + float center_depth, + float center_motion_len, + vec2 offset, + float offset_len, + const bool next, + inout Accumulator accum) +{ + vec2 sample_uv = screen_uv - offset * motion_blur_buf.target_size_inv; + vec4 sample_vectors = motion_blur_sample_velocity(velocity_tx, sample_uv); + vec2 sample_motion = (next) ? sample_vectors.zw : sample_vectors.xy; + float sample_motion_len = length(sample_motion); + float sample_depth = texture(depth_tx, sample_uv).r; + vec4 sample_color = textureLod(in_color_tx, sample_uv, 0.0); + + sample_depth = get_view_z_from_depth(sample_depth); + + vec3 weights; + weights.xy = sample_weights( + center_depth, sample_depth, center_motion_len, sample_motion_len, offset_len); + weights.z = dir_compare(offset, sample_motion, sample_motion_len); + weights.xy *= weights.z; + + accum.fg += sample_color * weights.y; + accum.bg += sample_color * weights.x; + accum.weight += weights; +} + +void gather_blur(vec2 screen_uv, + vec2 center_motion, + float center_depth, + vec2 max_motion, + float ofs, + const bool next, + inout Accumulator accum) +{ + float center_motion_len = length(center_motion); + float max_motion_len = length(max_motion); + + /* Tile boundaries randomization can fetch a tile where there is less motion than this pixel. + * Fix this by overriding the max_motion. */ + if (max_motion_len < center_motion_len) { + max_motion_len = center_motion_len; + max_motion = center_motion; + } + + if (max_motion_len < 0.5) { + return; + } + + int i; + float t, inc = 1.0 / float(gather_sample_count); + for (i = 0, t = ofs * inc; i < gather_sample_count; i++, t += inc) { + gather_sample(screen_uv, + center_depth, + center_motion_len, + max_motion * t, + max_motion_len * t, + next, + accum); + } + + if (center_motion_len < 0.5) { + return; + } + + for (i = 0, t = ofs * inc; i < gather_sample_count; i++, t += inc) { + /* Also sample in center motion direction. + * Allow recovering motion where there is conflicting + * motion between foreground and background. */ + gather_sample(screen_uv, + center_depth, + center_motion_len, + center_motion * t, + center_motion_len * t, + next, + accum); + } +} + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(depth_tx, 0).xy); + + if (!in_texture_range(texel, depth_tx)) { + return; + } + + /* Data of the center pixel of the gather (target). */ + float center_depth = get_view_z_from_depth(texelFetch(depth_tx, texel, 0).r); + vec4 center_motion = motion_blur_sample_velocity(velocity_tx, uv); + + vec4 center_color = textureLod(in_color_tx, uv, 0.0); + + float noise_offset = sampling_rng_1D_get(SAMPLING_TIME); + /** TODO(fclem) Blue noise. */ + vec2 rand = vec2(interlieved_gradient_noise(vec2(gl_GlobalInvocationID.xy), 0, noise_offset), + interlieved_gradient_noise(vec2(gl_GlobalInvocationID.xy), 1, noise_offset)); + + /* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile. + * Note this randomize only in one direction but in practice it's enough. */ + rand.x = rand.x * 2.0 - 1.0; + ivec2 tile = (texel + ivec2(rand.x * float(MOTION_BLUR_TILE_SIZE) * 0.25)) / + MOTION_BLUR_TILE_SIZE; + tile = clamp(tile, ivec2(0), imageSize(in_tiles_img) - 1); + /* NOTE: Tile velocity is already in pixel space and with correct zw sign. */ + vec4 max_motion; + /* Load dilation result from the indirection table. */ + ivec2 tile_prev; + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, tile, tile_prev); + max_motion.xy = imageLoad(in_tiles_img, tile_prev).xy; + ivec2 tile_next; + motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, tile, tile_next); + max_motion.zw = imageLoad(in_tiles_img, tile_next).zw; + + Accumulator accum; + accum.weight = vec3(0.0, 0.0, 1.0); + accum.bg = vec4(0.0); + accum.fg = vec4(0.0); + /* First linear gather. time = [T - delta, T] */ + gather_blur(uv, center_motion.xy, center_depth, max_motion.xy, rand.y, false, accum); + /* Second linear gather. time = [T, T + delta] */ + gather_blur(uv, center_motion.zw, center_depth, max_motion.zw, rand.y, true, accum); + +#if 1 /* Own addition. Not present in reference implementation. */ + /* Avoid division by 0.0. */ + float w = 1.0 / (50.0 * float(gather_sample_count) * 4.0); + accum.bg += center_color * w; + accum.weight.x += w; + /* NOTE: In Jimenez's presentation, they used center sample. + * We use background color as it contains more information for foreground + * elements that have not enough weights. + * Yield better blur in complex motion. */ + center_color = accum.bg / accum.weight.x; +#endif + /* Merge background. */ + accum.fg += accum.bg; + accum.weight.y += accum.weight.x; + /* Balance accumulation for failed samples. + * We replace the missing foreground by the background. */ + float blend_fac = saturate(1.0 - accum.weight.y / accum.weight.z); + vec4 out_color = (accum.fg / accum.weight.z) + center_color * blend_fac; + +#if 0 /* For debugging. */ + out_color.rgb = out_color.ggg; + out_color.rg += max_motion.xy; +#endif + + imageStore(out_color_img, texel, out_color); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl new file mode 100644 index 00000000000..436fd01795a --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_motion_blur_lib.glsl @@ -0,0 +1,48 @@ + + +/* -------------------------------------------------------------------- */ +/** \name Tile indirection packing + * \{ */ + +#define MotionPayload uint + +/* Store velocity magnitude in the MSB to be able to use it with atomicMax operations. */ +MotionPayload motion_blur_tile_indirection_pack_payload(vec2 motion, uvec2 payload) +{ + /* NOTE: Clamp to 16383 pixel velocity. After that, it is tile position that determine the tile + * to dilate over. */ + uint velocity = min(uint(ceil(length(motion))), 0x3FFFu); + /* Designed for 512x512 tiles max. */ + return (velocity << 18u) | ((payload.x & 0x1FFu) << 9u) | (payload.y & 0x1FFu); +} + +/* Return thread index. */ +ivec2 motion_blur_tile_indirection_pack_payload(uint data) +{ + return ivec2((data >> 9u) & 0x1FFu, data & 0x1FFu); +} + +uint motion_blur_tile_indirection_index(uint motion_step, uvec2 tile) +{ + uint index = tile.x; + index += tile.y * MOTION_BLUR_MAX_TILE; + index += motion_step * MOTION_BLUR_MAX_TILE * MOTION_BLUR_MAX_TILE; + return index; +} + +#define MOTION_PREV 0u +#define MOTION_NEXT 1u + +#define motion_blur_tile_indirection_store(table_, step_, tile, payload_) \ + if (true) { \ + uint index = motion_blur_tile_indirection_index(step_, tile); \ + atomicMax(table_[index], payload_); \ + } + +#define motion_blur_tile_indirection_load(table_, step_, tile_, result_) \ + if (true) { \ + uint index = motion_blur_tile_indirection_index(step_, tile_); \ + result_ = motion_blur_tile_indirection_pack_payload(table_[index]); \ + } + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl new file mode 100644 index 00000000000..0c7bbaa9dc2 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl @@ -0,0 +1,104 @@ + +/** + * Sampling data accessors and random number generators. + * Also contains some sample mapping functions. + **/ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +/* -------------------------------------------------------------------- */ +/** \name Sampling data. + * + * Return a random values from Low Discrepency Sequence in [0..1) range. + * This value is uniform (constant) for the whole scene sample. + * You might want to couple it with a noise function. + * \{ */ + +#ifdef EEVEE_SAMPLING_DATA + +float sampling_rng_1D_get(const eSamplingDimension dimension) +{ + return sampling_buf.dimensions[dimension]; +} + +vec2 sampling_rng_2D_get(const eSamplingDimension dimension) +{ + return vec2(sampling_buf.dimensions[dimension], sampling_buf.dimensions[dimension + 1u]); +} + +vec3 sampling_rng_3D_get(const eSamplingDimension dimension) +{ + return vec3(sampling_buf.dimensions[dimension], + sampling_buf.dimensions[dimension + 1u], + sampling_buf.dimensions[dimension + 2u]); +} + +#endif + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Random Number Generators. + * \{ */ + +/* Interlieved gradient noise by Jorge Jimenez + * http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare + * Seeding found by Epic Game. */ +float interlieved_gradient_noise(vec2 pixel, float seed, float offset) +{ + pixel += seed * (vec2(47, 17) * 0.695); + return fract(offset + 52.9829189 * fract(0.06711056 * pixel.x + 0.00583715 * pixel.y)); +} + +/* From: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */ +float van_der_corput_radical_inverse(uint bits) +{ +#if 0 /* Reference */ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); +#else + bits = bitfieldReverse(bits); +#endif + /* Same as dividing by 0x100000000. */ + return float(bits) * 2.3283064365386963e-10; +} + +vec2 hammersley_2d(float i, float sample_count) +{ + vec2 rand; + rand.x = i / sample_count; + rand.y = van_der_corput_radical_inverse(uint(i)); + return rand; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Distribution mapping. + * + * Functions mapping input random numbers to sampling shapes (i.e: hemisphere). + * \{ */ + +/* Given 2 random number in [0..1] range, return a random unit disk sample. */ +vec2 sample_disk(vec2 noise) +{ + float angle = noise.x * M_2PI; + return vec2(cos(angle), sin(angle)) * sqrt(noise.y); +} + +/* This transform a 2d random sample (in [0..1] range) to a sample located on a cylinder of the + * same range. This is because the sampling functions expect such a random sample which is + * normally precomputed. */ +vec3 sample_cylinder(vec2 rand) +{ + float theta = rand.x; + float phi = (rand.y - 0.5) * M_2PI; + float cos_phi = cos(phi); + float sin_phi = sqrt(1.0 - sqr(cos_phi)) * sign(phi); + return vec3(theta, cos_phi, sin_phi); +} + +/** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl index 34ea288852a..bd32215ddc2 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl @@ -73,7 +73,7 @@ void main() nodetree_surface(); - // float noise_offset = sampling_rng_1D_get(sampling_buf, SAMPLING_TRANSPARENCY); + // float noise_offset = sampling_rng_1D_get(SAMPLING_TRANSPARENCY); float noise_offset = 0.5; float random_threshold = hashed_alpha_threshold(1.0, noise_offset, g_data.P); @@ -84,7 +84,7 @@ void main() #endif #ifdef MAT_VELOCITY - out_velocity = velocity_surface(interp.P + motion.prev, interp.P, interp.P - motion.next); + out_velocity = velocity_surface(interp.P + motion.prev, interp.P, interp.P + motion.next); out_velocity = velocity_pack(out_velocity); #endif } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl index c21456b7a5c..c0a5b976810 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl @@ -2,8 +2,6 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(eevee_camera_lib.glsl) -#ifdef VELOCITY_CAMERA - vec4 velocity_pack(vec4 data) { return data * 0.01; @@ -14,6 +12,8 @@ vec4 velocity_unpack(vec4 data) return data * 100.0; } +#ifdef VELOCITY_CAMERA + /** * Given a triple of position, compute the previous and next motion vectors. * Returns uv space motion vectors in pairs (motion_prev.xy, motion_next.xy). @@ -24,7 +24,15 @@ vec4 velocity_surface(vec3 P_prv, vec3 P, vec3 P_nxt) vec2 prev_uv = project_point(camera_prev.persmat, P_prv).xy; vec2 curr_uv = project_point(camera_curr.persmat, P).xy; vec2 next_uv = project_point(camera_next.persmat, P_nxt).xy; - + /* Fix issue with perspective division. */ + if (any(isnan(prev_uv))) { + prev_uv = curr_uv; + } + if (any(isnan(next_uv))) { + next_uv = curr_uv; + } + /* NOTE: We output both vectors in the same direction so we can reuse the same vector + * with rgrg swizzle in viewport. */ vec4 motion = vec4(prev_uv - curr_uv, curr_uv - next_uv); /* Convert NDC velocity to UV velocity */ motion *= 0.5; @@ -45,7 +53,8 @@ vec4 velocity_background(vec3 vV) vec2 prev_uv = project_point(camera_prev.winmat, V).xy; vec2 curr_uv = project_point(camera_curr.winmat, V).xy; vec2 next_uv = project_point(camera_next.winmat, V).xy; - + /* NOTE: We output both vectors in the same direction so we can reuse the same vector + * with rgrg swizzle in viewport. */ vec4 motion = vec4(prev_uv - curr_uv, curr_uv - next_uv); /* Convert NDC velocity to UV velocity */ motion *= 0.5; @@ -53,15 +62,8 @@ vec4 velocity_background(vec3 vV) return motion; } -/** - * Load and resolve correct velocity as some pixels might still not have correct - * motion data for performance reasons. - */ -vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth) +vec4 velocity_resolve(vec4 vector, vec2 uv, float depth) { - vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(vector_tx, 0).xy); - vec4 vector = texelFetch(vector_tx, texel, 0); - if (vector.x == VELOCITY_INVALID) { bool is_background = (depth == 1.0); if (is_background) { @@ -78,6 +80,18 @@ vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth) return velocity_unpack(vector); } +/** + * Load and resolve correct velocity as some pixels might still not have correct + * motion data for performance reasons. + * Returns motion vector in render UV space. + */ +vec4 velocity_resolve(sampler2D vector_tx, ivec2 texel, float depth) +{ + vec2 uv = (vec2(texel) + 0.5) / vec2(textureSize(vector_tx, 0).xy); + vec4 vector = texelFetch(vector_tx, texel, 0); + return velocity_resolve(vector, uv, depth); +} + #endif #ifdef MAT_VELOCITY diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index 2368061402c..db3cfc4a7a2 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -12,8 +12,9 @@ GPU_SHADER_CREATE_INFO(eevee_shared) .typedef_source("eevee_shader_shared.hh"); GPU_SHADER_CREATE_INFO(eevee_sampling_data) + .define("EEVEE_SAMPLING_DATA") .additional_info("eevee_shared") - .uniform_buf(14, "SamplingData", "sampling_buf"); + .storage_buf(14, Qualifier::READ, "SamplingData", "sampling_buf"); /** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh new file mode 100644 index 00000000000..b01d1521c5e --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh @@ -0,0 +1,44 @@ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten) + .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view", "eevee_velocity_camera") + .uniform_buf(4, "MotionBlurData", "motion_blur_buf") + .sampler(0, ImageType::DEPTH_2D, "depth_tx") + .image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_tiles_img") + .compute_source("eevee_motion_blur_flatten_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten_viewport) + .do_static_compilation(true) + .define("FLATTEN_VIEWPORT") + .image(0, GPU_RG16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_img") + .additional_info("eevee_motion_blur_tiles_flatten"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_flatten_render) + .do_static_compilation(true) + .image(0, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_img") + .additional_info("eevee_motion_blur_tiles_flatten"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_tiles_dilate) + .do_static_compilation(true) + .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE) + .additional_info("eevee_shared") + /* NOTE: See MotionBlurTileIndirection. */ + .storage_buf(0, Qualifier::READ_WRITE, "uint", "tile_indirection_buf[]") + .image(1, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_img") + .compute_source("eevee_motion_blur_dilate_comp.glsl"); + +GPU_SHADER_CREATE_INFO(eevee_motion_blur_gather) + .do_static_compilation(true) + .local_group_size(MOTION_BLUR_GROUP_SIZE, MOTION_BLUR_GROUP_SIZE) + .additional_info("eevee_shared", "draw_view", "eevee_sampling_data") + .uniform_buf(4, "MotionBlurData", "motion_blur_buf") + .sampler(0, ImageType::DEPTH_2D, "depth_tx") + .sampler(1, ImageType::FLOAT_2D, "velocity_tx") + .sampler(2, ImageType::FLOAT_2D, "in_color_tx") + /* NOTE: See MotionBlurTileIndirection. */ + .storage_buf(0, Qualifier::READ, "uint", "tile_indirection_buf[]") + .image(0, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "in_tiles_img") + .image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") + .compute_source("eevee_motion_blur_gather_comp.glsl"); diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index 8e61c25be71..954d8c49f4c 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -57,6 +57,7 @@ #include "MEM_guardedalloc.h" +#include "draw_manager.h" #include "draw_texture_pool.h" #include "BLI_math_vec_types.hh" @@ -772,50 +773,26 @@ class Texture : NonCopyable { }; class TextureFromPool : public Texture, NonMovable { - private: - GPUTexture *tx_tmp_saved_ = nullptr; - public: TextureFromPool(const char *name = "gpu::Texture") : Texture(name){}; - /* Always use `release()` after rendering and `sync()` in sync phase. */ - void acquire(int2 extent, eGPUTextureFormat format, void *owner_) + /* Always use `release()` after rendering. */ + void acquire(int2 extent, eGPUTextureFormat format) { BLI_assert(this->tx_ == nullptr); - if (this->tx_ != nullptr) { - return; - } - if (tx_tmp_saved_ != nullptr) { - if (GPU_texture_width(tx_tmp_saved_) != extent.x || - GPU_texture_height(tx_tmp_saved_) != extent.y || - GPU_texture_format(tx_tmp_saved_) != format) { - this->tx_tmp_saved_ = nullptr; - } - else { - this->tx_ = tx_tmp_saved_; - return; - } - } - DrawEngineType *owner = (DrawEngineType *)owner_; - this->tx_ = DRW_texture_pool_query_2d(UNPACK2(extent), format, owner); + + this->tx_ = DRW_texture_pool_texture_acquire( + DST.vmempool->texture_pool, UNPACK2(extent), format); } void release(void) { /* Allows multiple release. */ - if (this->tx_ != nullptr) { - tx_tmp_saved_ = this->tx_; - this->tx_ = nullptr; + if (this->tx_ == nullptr) { + return; } - } - - /** - * Clears any reference. Workaround for pool texture not being able to release on demand. - * Needs to be called at during the sync phase. - */ - void sync(void) - { - tx_tmp_saved_ = nullptr; + DRW_texture_pool_texture_release(DST.vmempool->texture_pool, this->tx_); + this->tx_ = nullptr; } /** Remove methods that are forbidden with this type of textures. */ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index fc09606f9f3..af8e58c78f8 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -538,8 +538,8 @@ MeshRenderData *mesh_render_data_create(Object *object, /* Seems like the mesh_eval_final do not have the right origin indices. * Force not mapped in this case. */ - if (use_mapped && do_final && editmesh_eval_final != editmesh_eval_cage) { - // mr->edit_bmesh = nullptr; + if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) { + // mr->edit_bmesh = NULL; mr->extract_type = MR_EXTRACT_MESH; } } diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index 0e4e67f3320..88cc71fa0dd 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -27,6 +27,7 @@ #include "BKE_duplilist.h" #include "RNA_access.h" +#include "RNA_path.h" #include "BLI_bitmap.h" #include "BLI_memblock.h" diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index e8944442607..266db22a84f 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef GPU_SHADER +# pragma once + # include "GPU_shader.h" # include "GPU_shader_shared_utils.h" diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h index 1c30ea88552..7396b55d53a 100644 --- a/source/blender/draw/intern/draw_texture_pool.h +++ b/source/blender/draw/intern/draw_texture_pool.h @@ -26,6 +26,7 @@ void DRW_texture_pool_free(DRWTexturePool *pool); /** * Try to find a texture corresponding to params into the texture pool. * If no texture was found, create one and add it to the pool. + * DEPRECATED: Use DRW_texture_pool_texture_acquire instead and do it just before rendering. */ GPUTexture *DRW_texture_pool_query( DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user); diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl index ae82277d9a6..cb2da9d35bf 100644 --- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl @@ -10,6 +10,11 @@ float point_plane_projection_dist(vec3 line_origin, vec3 plane_origin, vec3 plan return dot(plane_normal, plane_origin - line_origin); } +float point_line_projection_dist(vec2 point, vec2 line_origin, vec2 line_normal) +{ + return dot(line_normal, line_origin - point); +} + float line_plane_intersect_dist(vec3 line_origin, vec3 line_direction, vec3 plane_origin, @@ -104,6 +109,25 @@ float line_unit_box_intersect_dist_safe(vec3 line_origin, vec3 line_direction) } /** + * Same as line_unit_box_intersect_dist but for 2D case. + */ +float line_unit_square_intersect_dist(vec2 line_origin, vec2 line_direction) +{ + vec2 first_plane = (vec2(1.0) - line_origin) / line_direction; + vec2 second_plane = (vec2(-1.0) - line_origin) / line_direction; + vec2 farthest_plane = max(first_plane, second_plane); + + return min_v2(farthest_plane); +} + +float line_unit_square_intersect_dist_safe(vec2 line_origin, vec2 line_direction) +{ + vec2 safe_line_direction = max(vec2(1e-8), abs(line_direction)) * + select(vec2(1.0), -vec2(1.0), lessThan(line_direction, vec2(0.0))); + return line_unit_square_intersect_dist(line_origin, safe_line_direction); +} + +/** * Returns clipping distance (intersection with the nearest plane) with the given axis-aligned * bound box along \a line_direction. * Safe even if \a line_direction is degenerate. diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 729e8533d50..f665ec27b07 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -43,6 +43,7 @@ #include "DNA_world_types.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "BKE_anim_data.h" diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index ff53ad42e84..22c14983569 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -32,6 +32,7 @@ #include "DEG_depsgraph.h" #include "RNA_access.h" +#include "RNA_path.h" #include "SEQ_sequencer.h" #include "SEQ_utils.h" diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index d9dcbf1d57e..e352b4e26fe 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -35,6 +35,7 @@ #include "ED_keyframes_keylist.h" #include "RNA_access.h" +#include "RNA_path.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index f01b3522547..93d83ff5f8e 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -22,6 +22,7 @@ #include "DNA_anim_types.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "ED_anim_api.h" diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index effedd4307d..63794caf5a7 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -39,6 +39,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "anim_intern.h" diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 7723c221a40..40f0ac59b01 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -29,6 +29,7 @@ #include "RNA_access.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "ED_anim_api.h" #include "ED_keyframes_edit.h" diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 9084b9bb214..12f83343299 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -64,6 +64,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "anim_intern.h" diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 97b81277008..967a324ef95 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -39,6 +39,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "anim_intern.h" diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 38c99c2ef60..3e36a0d233a 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -53,6 +53,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "WM_api.h" diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 032e0ec077c..ea038362532 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -26,6 +26,7 @@ #include "DEG_depsgraph.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "WM_api.h" diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h index 2dc67fc4d37..b54f81004f2 100644 --- a/source/blender/editors/asset/ED_asset_list.h +++ b/source/blender/editors/asset/ED_asset_list.h @@ -24,7 +24,7 @@ struct wmNotifier; void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference, const struct bContext *C); void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference, - struct bContext *C); + const struct bContext *C); void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C); bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference); /** diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc index 67e253a4fcd..773838a54cd 100644 --- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc +++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc @@ -97,10 +97,8 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf( RNA_enum_item_add_separator(&item, &totitem); } - int i = 0; - for (bUserAssetLibrary *user_library = (bUserAssetLibrary *)U.asset_libraries.first; - user_library; - user_library = user_library->next, i++) { + int i; + LISTBASE_FOREACH_INDEX (bUserAssetLibrary *, user_library, &U.asset_libraries, i) { /* Note that the path itself isn't checked for validity here. If an invalid library path is * used, the Asset Browser can give a nice hint on what's wrong. */ const bool is_valid = (user_library->name[0] && user_library->path[0]); diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 55167c1ed2d..b0ff5c86520 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -110,7 +110,7 @@ class AssetList : NonCopyable { void setup(); void fetch(const bContext &C); - void ensurePreviewsJob(bContext *C); + void ensurePreviewsJob(const bContext *C); void clear(bContext *C); bool needsRefetch() const; @@ -212,7 +212,7 @@ void AssetList::iterate(AssetListIterFn fn) const } } -void AssetList::ensurePreviewsJob(bContext *C) +void AssetList::ensurePreviewsJob(const bContext *C) { FileList *files = filelist_; int numfiles = filelist_files_ensure(files); @@ -422,7 +422,8 @@ void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, AssetListStorage::fetch_library(*library_reference, *C); } -void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, bContext *C) +void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, + const bContext *C) { AssetList *list = AssetListStorage::lookup_list(*library_reference); diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index 619a873909a..05d0b7d0af4 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -295,7 +295,7 @@ void AssetClearHelper::reportResults(const bContext *C, ReportList &reports) con else if (stats.tot_cleared == 1) { /* If only one data-block: Give more useful message by printing asset name. */ BKE_reportf( - &reports, RPT_INFO, "Data-block '%s' is no asset anymore", stats.last_id->name + 2); + &reports, RPT_INFO, "Data-block '%s' is not an asset anymore", stats.last_id->name + 2); } else { BKE_reportf(&reports, RPT_INFO, "%i data-blocks are no assets anymore", stats.tot_cleared); diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt index 303d2fb71dc..945bba0a77c 100644 --- a/source/blender/editors/curves/CMakeLists.txt +++ b/source/blender/editors/curves/CMakeLists.txt @@ -13,6 +13,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index 740e53b59f8..eec2c5d205d 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -755,6 +755,9 @@ static int curves_set_selection_domain_exec(bContext *C, wmOperator *op) CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + if (curves.points_num() == 0) { + continue; + } if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) { VArray<float> curve_selection = curves.adapt_domain( diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt index e0c440b09b4..6e28bb3e8ec 100644 --- a/source/blender/editors/geometry/CMakeLists.txt +++ b/source/blender/editors/geometry/CMakeLists.txt @@ -10,6 +10,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../bmesh ) set(INC_SYS diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 09a3cac0d48..9cb9e7ca1af 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -14,6 +14,7 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 71cf9b1fafd..69a74c36aee 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3989,6 +3989,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) /* TODO use `BKE_gpencil_stroke_smooth` when the weights are better used. */ bGPDstroke gps_old = *gps; gps_old.points = (bGPDspoint *)MEM_dupallocN(gps->points); + bool need_update = false; /* Here the iteration needs to be done outside the smooth functions, * as there are points that don't get smoothed. */ for (int n = 0; n < repeat; n++) { @@ -4000,6 +4001,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) /* Perform smoothing. */ if (smooth_position) { BKE_gpencil_stroke_smooth_point(&gps_old, i, factor, 1, false, false, gps); + need_update = true; } if (smooth_strength) { BKE_gpencil_stroke_smooth_strength(&gps_old, i, factor, 1, gps); @@ -4009,6 +4011,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) } if (smooth_uv) { BKE_gpencil_stroke_smooth_uv(&gps_old, i, factor, 1, gps); + need_update = true; } } if (n < repeat - 1) { @@ -4016,6 +4019,11 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) } } MEM_freeN(gps_old.points); + + if (need_update) { + gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; + BKE_gpencil_stroke_geometry_update(gpd_, gps); + } } } GP_EDITABLE_STROKES_END(gpstroke_iter); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 80a75da27f8..24d6819536d 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -305,6 +305,29 @@ void ED_uvedit_buttons_register(struct ARegionType *art); /* uvedit_islands.c */ +struct FaceIsland { + struct FaceIsland *next; + struct FaceIsland *prev; + struct BMFace **faces; + int faces_len; + rctf bounds_rect; + /** + * \note While this is duplicate information, + * it allows islands from multiple meshes to be stored in the same list. + */ + uint cd_loop_uv_offset; + float aspect_y; +}; + +int bm_mesh_calc_uv_islands(const Scene *scene, + struct BMesh *bm, + ListBase *island_list, + const bool only_selected_faces, + const bool only_selected_uvs, + const bool use_seams, + const float aspect_y, + const uint cd_loop_uv_offset); + struct UVMapUDIM_Params { const struct Image *image; /** Copied from #SpaceImage.tile_grid_shape */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a8d25b75036..163ea7e9493 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -85,7 +85,7 @@ typedef struct uiViewItemHandle uiViewItemHandle; /* Separator for text in search menus (right pointing arrow). * keep in sync with `string_search.cc`. */ -#define UI_MENU_ARROW_SEP "\xe2\x96\xb6" +#define UI_MENU_ARROW_SEP "\xe2\x96\xb8" /* names */ #define UI_MAX_DRAW_STR 400 @@ -2482,7 +2482,7 @@ enum uiTemplateListFlags { ENUM_OPERATORS(enum uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST); void uiTemplateList(uiLayout *layout, - struct bContext *C, + const struct bContext *C, const char *listtype_name, const char *list_id, struct PointerRNA *dataptr, @@ -2496,7 +2496,7 @@ void uiTemplateList(uiLayout *layout, int columns, enum uiTemplateListFlags flags); struct uiList *uiTemplateList_ex(uiLayout *layout, - struct bContext *C, + const struct bContext *C, const char *listtype_name, const char *list_id, struct PointerRNA *dataptr, @@ -2566,7 +2566,7 @@ enum { UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY = (1 << 2), }; void uiTemplateAssetView(struct uiLayout *layout, - struct bContext *C, + const struct bContext *C, const char *list_id, struct PointerRNA *asset_library_dataptr, const char *asset_library_propname, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 07c3bfdafbf..c54bcad905f 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -35,7 +36,7 @@ set(SRC eyedroppers/eyedropper_gpencil_color.c interface.cc interface_align.c - interface_anim.c + interface_anim.cc interface_button_group.c interface_context_menu.c interface_context_path.cc @@ -46,8 +47,8 @@ set(SRC interface_icons.c interface_icons_event.c interface_layout.c - interface_ops.c - interface_panel.c + interface_ops.cc + interface_panel.cc interface_query.cc interface_region_color_picker.cc interface_region_hud.cc @@ -56,16 +57,16 @@ set(SRC interface_region_popover.cc interface_region_popup.cc interface_region_search.cc - interface_region_tooltip.c + interface_region_tooltip.cc interface_regions.cc interface_style.cc interface_template_asset_view.cc interface_template_attribute_search.cc interface_template_list.cc interface_template_search_menu.cc - interface_template_search_operator.c + interface_template_search_operator.cc interface_templates.c - interface_undo.c + interface_undo.cc interface_utils.cc interface_widgets.c resources.c @@ -82,7 +83,7 @@ set(SRC eyedroppers/eyedropper_intern.h interface_intern.h - interface_regions_intern.h + interface_regions_intern.hh ) set(LIB diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_driver.c b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c index a9314df44a5..0f3062c3f61 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_driver.c +++ b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c @@ -24,6 +24,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_path.h" #include "UI_interface.h" diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.cc index 0e69b4bb358..8e898b7fe66 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.cc @@ -4,9 +4,9 @@ * \ingroup edinterface */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <cstdio> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -35,6 +35,7 @@ #include "UI_interface.h" #include "RNA_access.h" +#include "RNA_path.h" #include "WM_api.h" #include "WM_types.h" @@ -48,8 +49,14 @@ static FCurve *ui_but_get_fcurve( * but works well enough in typical cases */ const int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex; - return BKE_fcurve_find_by_rna_context_ui( - but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special); + return BKE_fcurve_find_by_rna_context_ui(static_cast<bContext *>(but->block->evil_C), + &but->rnapoin, + but->rnaprop, + rnaindex, + adt, + action, + r_driven, + r_special); } void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) @@ -92,7 +99,7 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) } /* XXX: this feature is totally broken and useless with NLA */ - if (adt == NULL || adt->nla_tracks.first == NULL) { + if (adt == nullptr || adt->nla_tracks.first == nullptr) { const AnimationEvalContext remapped_context = BKE_animsys_eval_context_construct_at( anim_eval_context, cfra); if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, &remapped_context)) { @@ -108,13 +115,13 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_decorate) { - uiBut *but_iter = NULL; + uiBut *but_iter = nullptr; BLI_assert(UI_but_is_decorator(&but_decorate->but)); BLI_assert(but_decorate->rnapoin.data && but_decorate->rnaprop); LISTBASE_CIRCULAR_BACKWARD_BEGIN ( - &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) { + uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) { if (but_iter != (uiBut *)but_decorate && ui_but_rna_equals_ex( but_iter, &but_decorate->rnapoin, but_decorate->rnaprop, but_decorate->rnaindex)) { @@ -122,9 +129,9 @@ static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_deco } } LISTBASE_CIRCULAR_BACKWARD_END( - &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev); + uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev); - return NULL; + return nullptr; } void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but) @@ -172,7 +179,7 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen) ChannelDriver *driver; bool driven, special; - fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special); + fcu = ui_but_get_fcurve(but, nullptr, nullptr, &driven, &special); if (fcu && driven) { driver = fcu->driver; @@ -194,13 +201,13 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str) ChannelDriver *driver; bool driven, special; - fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special); + fcu = ui_but_get_fcurve(but, nullptr, nullptr, &driven, &special); if (fcu && driven) { driver = fcu->driver; if (driver && (driver->type == DRIVER_TYPE_PYTHON)) { - bContext *C = but->block->evil_C; + bContext *C = static_cast<bContext *>(but->block->evil_C); BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression)); @@ -212,7 +219,7 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str) fcu->flag &= ~FCURVE_DISABLED; /* this notifier should update the Graph Editor and trigger depsgraph refresh? */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, nullptr); DEG_relations_tag_update(CTX_data_main(C)); @@ -225,14 +232,14 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str) bool ui_but_anim_expression_create(uiBut *but, const char *str) { - bContext *C = but->block->evil_C; + bContext *C = static_cast<bContext *>(but->block->evil_C); ID *id; FCurve *fcu; char *path; bool ok = false; /* button must have RNA-pointer to a numeric-capable property */ - if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) { + if (ELEM(nullptr, but->rnapoin.data, but->rnaprop)) { if (G.debug & G_DEBUG) { printf("ERROR: create expression failed - button has no RNA info attached\n"); } @@ -252,7 +259,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) /* FIXME: until materials can be handled by depsgraph, * don't allow drivers to be created for them */ id = but->rnapoin.owner_id; - if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) { + if ((id == nullptr) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) { if (G.debug & G_DEBUG) { printf("ERROR: create expression failed - invalid data-block for adding drivers (%p)\n", id); } @@ -261,7 +268,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) /* get path */ path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); - if (path == NULL) { + if (path == nullptr) { return false; } @@ -281,7 +288,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) /* updates */ BKE_driver_invalidate_expression(driver, true, false); DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, nullptr); ok = true; } } @@ -299,19 +306,19 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) void ui_but_anim_copy_driver(bContext *C) { /* this operator calls UI_context_active_but_prop_get */ - WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL); + WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); } void ui_but_anim_paste_driver(bContext *C) { /* this operator calls UI_context_active_but_prop_get */ - WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL); + WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, nullptr, nullptr); } void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)) { wmWindowManager *wm = CTX_wm_manager(C); - uiButDecorator *but_decorate = arg_but; + uiButDecorator *but_decorate = static_cast<uiButDecorator *>(arg_but); uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate); if (!but_anim) { @@ -331,7 +338,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy) wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false); WM_operator_properties_create_ptr(&props_ptr, ot); RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr); WM_operator_properties_free(&props_ptr); } else { @@ -339,7 +346,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy) wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false); WM_operator_properties_create_ptr(&props_ptr, ot); RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr); WM_operator_properties_free(&props_ptr); } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 03b9d03a6e3..d75d86c2665 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -468,6 +468,7 @@ typedef enum uiButtonGroupFlag { /** The buttons in this group are inside a panel header. */ UI_BUTTON_GROUP_PANEL_HEADER = (1 << 1), } uiButtonGroupFlag; +ENUM_OPERATORS(uiButtonGroupFlag, UI_BUTTON_GROUP_PANEL_HEADER); struct uiBlock { uiBlock *next, *prev; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.cc index ddd805f6010..2533a5454a5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.cc @@ -5,7 +5,7 @@ * \ingroup edinterface */ -#include <string.h> +#include <cstring> #include "MEM_guardedalloc.h" @@ -40,6 +40,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "RNA_types.h" @@ -127,7 +128,7 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *op) /* try to create driver using property retrieved from UI */ UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (ptr.owner_id != NULL) { + if (ptr.owner_id != nullptr) { if (full_path) { if (prop) { path = RNA_path_full_property_py_ex(bmain, &ptr, prop, index, true); @@ -216,7 +217,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *op) if (ptr.owner_id && ptr.data && prop) { ID *id; - const int dim = RNA_property_array_dimension(&ptr, prop, NULL); + const int dim = RNA_property_array_dimension(&ptr, prop, nullptr); char *path = RNA_path_from_real_ID_to_property_index(bmain, &ptr, prop, dim, index, &id); if (path) { @@ -260,25 +261,25 @@ static bool copy_python_command_button_poll(bContext *C) { uiBut *but = UI_context_active_but_get(C); - if (but && (but->optype != NULL)) { - return 1; + if (but && (but->optype != nullptr)) { + return true; } - return 0; + return false; } static int copy_python_command_button_exec(bContext *C, wmOperator *UNUSED(op)) { uiBut *but = UI_context_active_but_get(C); - if (but && (but->optype != NULL)) { + if (but && (but->optype != nullptr)) { PointerRNA *opptr; char *str; opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */ - str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr); + str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr); - WM_clipboard_text_set(str, 0); + WM_clipboard_text_set(str, false); MEM_freeN(str); @@ -390,7 +391,8 @@ static void UI_OT_reset_default_button(wmOperatorType *ot) ot->flag = 0; /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + RNA_def_boolean( + ot->srna, "all", true, "All", "Reset to default values all elements of the array"); } /** \} */ @@ -529,7 +531,7 @@ static EnumPropertyItem override_type_items[] = { 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static bool override_type_set_button_poll(bContext *C) @@ -580,16 +582,16 @@ static int override_type_set_button_exec(bContext *C, wmOperator *op) /* try to reset the nominated setting to its default value */ UI_context_active_but_prop_get(C, &ptr, &prop, &index); - BLI_assert(ptr.owner_id != NULL); + BLI_assert(ptr.owner_id != nullptr); if (all) { index = -1; } IDOverrideLibraryPropertyOperation *opop = RNA_property_override_property_operation_get( - CTX_data_main(C), &ptr, prop, operation, index, true, NULL, &created); + CTX_data_main(C), &ptr, prop, operation, index, true, nullptr, &created); - if (opop == NULL) { + if (opop == nullptr) { /* Sometimes e.g. RNA cannot generate a path to the given property. */ BKE_reportf(op->reports, RPT_WARNING, "Failed to create the override operation"); return OPERATOR_CANCELLED; @@ -600,7 +602,7 @@ static int override_type_set_button_exec(bContext *C, wmOperator *op) } /* Outliner e.g. has to be aware of this change. */ - WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr); return operator_button_property_finish(C, &ptr, prop); } @@ -633,7 +635,8 @@ static void UI_OT_override_type_set_button(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + RNA_def_boolean( + ot->srna, "all", true, "All", "Reset to default values all elements of the array"); ot->prop = RNA_def_enum(ot->srna, "type", override_type_items, @@ -670,8 +673,8 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) ID *id = ptr.owner_id; IDOverrideLibraryProperty *oprop = RNA_property_override_property_find(bmain, &ptr, prop, &id); - BLI_assert(oprop != NULL); - BLI_assert(id != NULL && id->override_library != NULL); + BLI_assert(oprop != nullptr); + BLI_assert(id != nullptr && id->override_library != nullptr); const bool is_template = ID_IS_OVERRIDE_LIBRARY_TEMPLATE(id); @@ -690,8 +693,8 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) /* Remove override operation for given item, * add singular operations for the other items as needed. */ IDOverrideLibraryPropertyOperation *opop = BKE_lib_override_library_property_operation_find( - oprop, NULL, NULL, index, index, false, &is_strict_find); - BLI_assert(opop != NULL); + oprop, nullptr, nullptr, index, index, false, &is_strict_find); + BLI_assert(opop != nullptr); if (!is_strict_find) { /* No specific override operation, we have to get generic one, * and create item-specific override operations for all but given index, @@ -699,7 +702,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) for (int idx = RNA_property_array_length(&ptr, prop); idx--;) { if (idx != index) { BKE_lib_override_library_property_operation_get( - oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL); + oprop, opop->operation, nullptr, nullptr, idx, idx, true, nullptr, nullptr); } } } @@ -720,7 +723,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op) } /* Outliner e.g. has to be aware of this change. */ - WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); + WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, nullptr); return operator_button_property_finish(C, &ptr, prop); } @@ -740,7 +743,8 @@ static void UI_OT_override_remove_button(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + RNA_def_boolean( + ot->srna, "all", true, "All", "Reset to default values all elements of the array"); } /** \} */ @@ -749,8 +753,8 @@ static void UI_OT_override_remove_button(wmOperatorType *ot) /** \name Copy To Selected Operator * \{ */ -#define NOT_NULL(assignment) ((assignment) != NULL) -#define NOT_RNA_NULL(assignment) ((assignment).data != NULL) +#define NOT_NULL(assignment) ((assignment) != nullptr) +#define NOT_RNA_NULL(assignment) ((assignment).data != nullptr) static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb) { @@ -759,7 +763,7 @@ static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb) if (!BLI_listbase_is_empty(&lb)) { LISTBASE_FOREACH (CollectionPointerLink *, link, &lb) { - bPoseChannel *pchan = link->ptr.data; + bPoseChannel *pchan = static_cast<bPoseChannel *>(link->ptr.data); RNA_pointer_create(link->ptr.owner_id, &RNA_Bone, pchan->bone, &link->ptr); } } @@ -775,9 +779,9 @@ bool UI_context_copy_to_selected_list(bContext *C, char **r_path) { *r_use_path_from_id = false; - *r_path = NULL; + *r_path = nullptr; /* special case for bone constraints */ - char *path_from_bone = NULL; + char *path_from_bone = nullptr; /* Remove links from the collection list which don't contain 'prop'. */ bool ensure_list_items_contain_prop = false; @@ -791,29 +795,32 @@ bool UI_context_copy_to_selected_list(bContext *C, */ if (!RNA_property_is_idprop(prop) && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) { PointerRNA owner_ptr; - char *idpath = NULL; + char *idpath = nullptr; /* First, check the active PoseBone and PoseBone->Bone. */ if (NOT_RNA_NULL( owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone))) { - if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty( + &owner_ptr, static_cast<IDProperty *>(ptr->data)))) { *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); } else { - bPoseChannel *pchan = owner_ptr.data; + bPoseChannel *pchan = static_cast<bPoseChannel *>(owner_ptr.data); RNA_pointer_create(owner_ptr.owner_id, &RNA_Bone, pchan->bone, &owner_ptr); - if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty( + &owner_ptr, static_cast<IDProperty *>(ptr->data)))) { ui_context_selected_bones_via_pose(C, r_lb); } } } - if (idpath == NULL) { + if (idpath == nullptr) { /* Check the active EditBone if in edit mode. */ if (NOT_RNA_NULL( owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)) && - NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + NOT_NULL(idpath = RNA_path_from_struct_to_idproperty( + &owner_ptr, static_cast<IDProperty *>(ptr->data)))) { *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); } @@ -866,30 +873,30 @@ bool UI_context_copy_to_selected_list(bContext *C, } else if (RNA_struct_is_a(ptr->type, &RNA_Constraint) && (path_from_bone = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone)) != - NULL) { + nullptr) { *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); *r_path = path_from_bone; } else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { - ListBase lb = {NULL, NULL}; - char *path = NULL; - bNode *node = NULL; + ListBase lb = {nullptr, nullptr}; + char *path = nullptr; + bNode *node = nullptr; /* Get the node we're editing */ if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNodeSocket *sock = ptr->data; - if (nodeFindNode(ntree, sock, &node, NULL)) { - if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) { + bNodeSocket *sock = static_cast<bNodeSocket *>(ptr->data); + if (nodeFindNode(ntree, sock, &node, nullptr)) { + if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != nullptr) { /* we're good! */ } else { - node = NULL; + node = nullptr; } } } else { - node = ptr->data; + node = static_cast<bNode *>(ptr->data); } /* Now filter by type */ @@ -897,7 +904,7 @@ bool UI_context_copy_to_selected_list(bContext *C, lb = CTX_data_collection_get(C, "selected_nodes"); LISTBASE_FOREACH_MUTABLE (CollectionPointerLink *, link, &lb) { - bNode *node_data = link->ptr.data; + bNode *node_data = static_cast<bNode *>(link->ptr.data); if (node_data->type != node->type) { BLI_remlink(&lb, link); @@ -928,17 +935,17 @@ bool UI_context_copy_to_selected_list(bContext *C, LISTBASE_FOREACH (CollectionPointerLink *, link, &lb) { Object *ob = (Object *)link->ptr.owner_id; if (ob->data) { - ID *id_data = ob->data; + ID *id_data = static_cast<ID *>(ob->data); id_data->tag |= LIB_TAG_DOIT; } } LISTBASE_FOREACH_MUTABLE (CollectionPointerLink *, link, &lb) { Object *ob = (Object *)link->ptr.owner_id; - ID *id_data = ob->data; + ID *id_data = static_cast<ID *>(ob->data); - if ((id_data == NULL) || (id_data->tag & LIB_TAG_DOIT) == 0 || ID_IS_LINKED(id_data) || - (GS(id_data->name) != id_code)) { + if ((id_data == nullptr) || (id_data->tag & LIB_TAG_DOIT) == 0 || + ID_IS_LINKED(id_data) || (GS(id_data->name) != id_code)) { BLI_remlink(&lb, link); MEM_freeN(link); } @@ -960,7 +967,8 @@ bool UI_context_copy_to_selected_list(bContext *C, /* Sequencer's ID is scene :/ */ /* Try to recursively find an RNA_Sequence ancestor, * to handle situations like T41062... */ - if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { + if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != + nullptr) { /* Special case when we do this for 'Sequence.lock'. * (if the sequence is locked, it won't be in "selected_editable_sequences"). */ const char *prop_id = RNA_property_identifier(prop); @@ -974,7 +982,7 @@ bool UI_context_copy_to_selected_list(bContext *C, ensure_list_items_contain_prop = true; } } - return (*r_path != NULL); + return (*r_path != nullptr); } else { return false; @@ -1012,13 +1020,13 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr, if (use_path_from_id) { /* Path relative to ID. */ - lprop = NULL; + lprop = nullptr; RNA_id_pointer_create(ptr_link->owner_id, &idptr); RNA_path_resolve_property(&idptr, path, &lptr, &lprop); } else if (path) { /* Path relative to elements from list. */ - lprop = NULL; + lprop = nullptr; RNA_path_resolve_property(ptr_link, path, &lptr, &lprop); } else { @@ -1033,7 +1041,7 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr, /* Skip non-existing properties on link. This was previously covered with the `lprop != prop` * check but we are now more permissive when it comes to ID properties, see below. */ - if (lprop == NULL) { + if (lprop == nullptr) { return false; } @@ -1104,13 +1112,13 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) UI_context_active_but_prop_get(C, &ptr, &prop, &index); /* if there is a valid property that is editable... */ - if (ptr.data == NULL || prop == NULL) { + if (ptr.data == nullptr || prop == nullptr) { return false; } - char *path = NULL; + char *path = nullptr; bool use_path_from_id; - ListBase lb = {NULL}; + ListBase lb = {nullptr}; if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) { return false; @@ -1197,7 +1205,7 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll) /* Verify pointer type. */ char bone_name[MAXBONENAME]; - const StructRNA *target_type = NULL; + const StructRNA *target_type = nullptr; if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) { RNA_string_get(&ptr, "name", bone_name); @@ -1209,13 +1217,13 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll) target_type = &RNA_Object; } - if (target_type == NULL) { + if (target_type == nullptr) { return false; } /* Find the containing Object. */ ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = NULL; + Base *base = nullptr; const short id_type = GS(ptr.owner_id->name); if (id_type == ID_OB) { base = BKE_view_layer_base_find(view_layer, (Object *)ptr.owner_id); @@ -1225,7 +1233,7 @@ static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll) } bool ok = false; - if ((base == NULL) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) { + if ((base == nullptr) || ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE))) { /* pass */ } else if (poll) { @@ -1277,13 +1285,14 @@ static bool jump_to_target_button(bContext *C, bool poll) if (type == PROP_STRING) { const uiBut *but = UI_context_active_but_get(C); const uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but : - NULL; + nullptr; if (search_but && search_but->items_update_fn == ui_rna_collection_search_update_fn) { - uiRNACollectionSearch *coll_search = search_but->arg; + uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(search_but->arg); char str_buf[MAXBONENAME]; - char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL); + char *str_ptr = RNA_property_string_get_alloc( + &ptr, prop, str_buf, sizeof(str_buf), nullptr); int found = RNA_property_collection_lookup_string( &coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr); @@ -1341,39 +1350,39 @@ static void UI_OT_jump_to_target_button(wmOperatorType *ot) /* EditSource Utility funcs and operator, * NOTE: this includes utility functions and button matching checks. */ -typedef struct uiEditSourceStore { +struct uiEditSourceStore { uiBut but_orig; GHash *hash; -} uiEditSourceStore; +}; -typedef struct uiEditSourceButStore { +struct uiEditSourceButStore { char py_dbg_fn[FILE_MAX]; int py_dbg_line_number; -} uiEditSourceButStore; +}; /* should only ever be set while the edit source operator is running */ -static struct uiEditSourceStore *ui_editsource_info = NULL; +static uiEditSourceStore *ui_editsource_info = nullptr; bool UI_editsource_enable_check(void) { - return (ui_editsource_info != NULL); + return (ui_editsource_info != nullptr); } static void ui_editsource_active_but_set(uiBut *but) { - BLI_assert(ui_editsource_info == NULL); + BLI_assert(ui_editsource_info == nullptr); - ui_editsource_info = MEM_callocN(sizeof(uiEditSourceStore), __func__); + ui_editsource_info = MEM_cnew<uiEditSourceStore>(__func__); memcpy(&ui_editsource_info->but_orig, but, sizeof(uiBut)); ui_editsource_info->hash = BLI_ghash_ptr_new(__func__); } -static void ui_editsource_active_but_clear(void) +static void ui_editsource_active_but_clear() { - BLI_ghash_free(ui_editsource_info->hash, NULL, MEM_freeN); + BLI_ghash_free(ui_editsource_info->hash, nullptr, MEM_freeN); MEM_freeN(ui_editsource_info); - ui_editsource_info = NULL; + ui_editsource_info = nullptr; } static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b) @@ -1394,11 +1403,14 @@ static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b) return false; } +extern "C" { +void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno); +} + void UI_editsource_active_but_test(uiBut *but) { - extern void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno); - struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__); + uiEditSourceButStore *but_store = MEM_cnew<uiEditSourceButStore>(__func__); const char *fn; int line_number = -1; @@ -1423,9 +1435,10 @@ void UI_editsource_active_but_test(uiBut *but) void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but) { - uiEditSourceButStore *but_store = BLI_ghash_lookup(ui_editsource_info->hash, old_but); + uiEditSourceButStore *but_store = static_cast<uiEditSourceButStore *>( + BLI_ghash_lookup(ui_editsource_info->hash, old_but)); if (but_store) { - BLI_ghash_remove(ui_editsource_info->hash, old_but, NULL, NULL); + BLI_ghash_remove(ui_editsource_info->hash, old_but, nullptr, nullptr); BLI_ghash_insert(ui_editsource_info->hash, new_but, but_store); } } @@ -1435,8 +1448,8 @@ static int editsource_text_edit(bContext *C, const char filepath[FILE_MAX], const int line) { - struct Main *bmain = CTX_data_main(C); - Text *text = NULL; + Main *bmain = CTX_data_main(C); + Text *text = nullptr; /* Developers may wish to copy-paste to an external editor. */ printf("%s:%d\n", filepath, line); @@ -1448,11 +1461,11 @@ static int editsource_text_edit(bContext *C, } } - if (text == NULL) { + if (text == nullptr) { text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain)); } - if (text == NULL) { + if (text == nullptr) { BKE_reportf(op->reports, RPT_WARNING, "File '%s' cannot be opened", filepath); return OPERATOR_CANCELLED; } @@ -1476,7 +1489,7 @@ static int editsource_exec(bContext *C, wmOperator *op) if (but) { GHashIterator ghi; - struct uiEditSourceButStore *but_store = NULL; + uiEditSourceButStore *but_store = nullptr; ARegion *region = CTX_wm_region(C); int ret; @@ -1495,9 +1508,9 @@ static int editsource_exec(bContext *C, wmOperator *op) for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash); BLI_ghashIterator_done(&ghi) == false; BLI_ghashIterator_step(&ghi)) { - uiBut *but_key = BLI_ghashIterator_getKey(&ghi); + uiBut *but_key = static_cast<uiBut *>(BLI_ghashIterator_getKey(&ghi)); if (but_key && ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) { - but_store = BLI_ghashIterator_getValue(&ghi); + but_store = static_cast<uiEditSourceButStore *>(BLI_ghashIterator_getValue(&ghi)); break; } } @@ -1568,7 +1581,7 @@ static void edittranslation_find_po_file(const char *root, /* Now try without the second iso code part (_ES in es_ES). */ { - const char *tc = NULL; + const char *tc = nullptr; size_t szt = 0; tstr[0] = '\0'; @@ -1602,7 +1615,7 @@ static void edittranslation_find_po_file(const char *root, static int edittranslation_exec(bContext *C, wmOperator *op) { uiBut *but = UI_context_active_but_get(C); - if (but == NULL) { + if (but == nullptr) { BKE_report(op->reports, RPT_ERROR, "Active button not found"); return OPERATOR_CANCELLED; } @@ -1613,16 +1626,16 @@ static int edittranslation_exec(bContext *C, wmOperator *op) const char *root = U.i18ndir; const char *uilng = BLT_lang_get(); - uiStringInfo but_label = {BUT_GET_LABEL, NULL}; - uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL}; - uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; - uiStringInfo but_tip = {BUT_GET_TIP, NULL}; - uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL}; - uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; - uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; - uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; - uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL}; - uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL}; + uiStringInfo but_label = {BUT_GET_LABEL, nullptr}; + uiStringInfo rna_label = {BUT_GET_RNA_LABEL, nullptr}; + uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, nullptr}; + uiStringInfo but_tip = {BUT_GET_TIP, nullptr}; + uiStringInfo rna_tip = {BUT_GET_RNA_TIP, nullptr}; + uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, nullptr}; + uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, nullptr}; + uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, nullptr}; + uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, nullptr}; + uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, nullptr}; if (!BLI_is_dir(root)) { BKE_report(op->reports, @@ -1631,8 +1644,8 @@ static int edittranslation_exec(bContext *C, wmOperator *op) "Directory' path to a valid directory"); return OPERATOR_CANCELLED; } - ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0); - if (ot == NULL) { + ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, false); + if (ot == nullptr) { BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate add-on " @@ -1661,7 +1674,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) &rna_prop, &rna_enum, &rna_ctxt, - NULL); + nullptr); WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, "lang", uilng); @@ -1676,7 +1689,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo); RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo); RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo); - const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL); + const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); /* Clean up */ if (but_label.strinfo) { @@ -1736,7 +1749,7 @@ static int reloadtranslation_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) { BLT_lang_init(); BLF_cache_clear(); - BLT_lang_set(NULL); + BLT_lang_set(nullptr); UI_reinit_font(); return OPERATOR_FINISHED; } @@ -1763,13 +1776,13 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev bScreen *screen = CTX_wm_screen(C); const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed"); ARegion *region_prev = CTX_wm_region(C); - ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL; + ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : nullptr; - if (region == NULL) { + if (region == nullptr) { region = region_prev; } - if (region == NULL) { + if (region == nullptr) { return OPERATOR_PASS_THROUGH; } @@ -1777,7 +1790,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev uiBut *but = UI_context_active_but_get(C); CTX_wm_region_set(C, region_prev); - if (but == NULL) { + if (but == nullptr) { return OPERATOR_PASS_THROUGH; } if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) { @@ -1790,7 +1803,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev UI_but_execute(C, region, but); - but->optype = but_optype; + but->optype = static_cast<wmOperatorType *>(but_optype); WM_event_add_mousemove(CTX_wm_window(C)); @@ -1806,7 +1819,7 @@ static void UI_OT_button_execute(wmOperatorType *ot) ot->invoke = ui_button_press_invoke; ot->flag = OPTYPE_INTERNAL; - RNA_def_boolean(ot->srna, "skip_depressed", 0, "Skip Depressed", ""); + RNA_def_boolean(ot->srna, "skip_depressed", false, "Skip Depressed", ""); } /** \} */ @@ -1852,21 +1865,21 @@ bool UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED( ARegion *region = CTX_wm_region(C); if (UI_but_active_drop_color(C)) { - return 1; + return true; } if (sima && (sima->mode == SI_MODE_PAINT) && sima->image && (region && region->regiontype == RGN_TYPE_WINDOW)) { - return 1; + return true; } } - return 0; + return false; } void UI_drop_color_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { - uiDragColorHandle *drag_info = drag->poin; + uiDragColorHandle *drag_info = static_cast<uiDragColorHandle *>(drag->poin); RNA_float_set_array(drop->ptr, "color", drag_info->color); RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected); @@ -1875,7 +1888,7 @@ void UI_drop_color_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *region = CTX_wm_region(C); - uiBut *but = NULL; + uiBut *but = nullptr; float color[4]; bool gamma; @@ -1932,8 +1945,10 @@ static void UI_OT_drop_color(wmOperatorType *ot) ot->invoke = drop_color_invoke; ot->flag = OPTYPE_INTERNAL; - RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0); - RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected"); + RNA_def_float_color( + ot->srna, "color", 3, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0); + RNA_def_boolean( + ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected"); } /** \} */ @@ -1963,7 +1978,7 @@ static bool drop_name_poll(bContext *C) static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { uiBut *but = UI_but_active_drop_name_button(C); - char *str = RNA_string_get_alloc(op->ptr, "string", NULL, 0, NULL); + char *str = RNA_string_get_alloc(op->ptr, "string", nullptr, 0, nullptr); if (str) { ui_but_set_string_interactive(C, but, str); @@ -1984,7 +1999,7 @@ static void UI_OT_drop_name(wmOperatorType *ot) ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; RNA_def_string( - ot->srna, "string", NULL, 0, "String", "The string value to drop into the button"); + ot->srna, "string", nullptr, 0, "String", "The string value to drop into the button"); } /** \} */ @@ -2002,7 +2017,7 @@ static bool ui_list_focused_poll(bContext *C) const wmWindow *win = CTX_wm_window(C); const uiList *list = UI_list_find_mouse_over(region, win->eventstate); - return list != NULL; + return list != nullptr; } /** @@ -2025,7 +2040,7 @@ static int ui_list_start_filter_invoke(bContext *C, wmOperator *UNUSED(op), cons ARegion *region = CTX_wm_region(C); uiList *list = UI_list_find_mouse_over(region, event); /* Poll should check. */ - BLI_assert(list != NULL); + BLI_assert(list != nullptr); if (ui_list_unhide_filter_options(list)) { ui_region_redraw_immediately(C, region); @@ -2060,7 +2075,7 @@ static bool ui_view_drop_poll(bContext *C) const ARegion *region = CTX_wm_region(C); const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, win->eventstate->xy); - return hovered_item != NULL; + return hovered_item != nullptr; } static int ui_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -2072,7 +2087,8 @@ static int ui_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven const ARegion *region = CTX_wm_region(C); uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy); - if (!UI_view_item_drop_handle(C, hovered_item, event->customdata)) { + if (!UI_view_item_drop_handle( + C, hovered_item, static_cast<const ListBase *>(event->customdata))) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } @@ -2106,7 +2122,7 @@ static bool ui_view_item_rename_poll(bContext *C) { const ARegion *region = CTX_wm_region(C); const uiViewItemHandle *active_item = UI_region_views_find_active_item(region); - return active_item != NULL && UI_view_item_can_rename(active_item); + return active_item != nullptr && UI_view_item_can_rename(active_item); } static int ui_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op)) @@ -2143,8 +2159,8 @@ static void UI_OT_view_item_rename(wmOperatorType *ot) static bool ui_drop_material_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object); - Object *ob = ptr.data; - if (ob == NULL) { + const Object *ob = static_cast<const Object *>(ptr.data); + if (ob == nullptr) { return false; } @@ -2162,12 +2178,12 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op) Material *ma = (Material *)WM_operator_properties_id_lookup_from_name_or_session_uuid( bmain, op->ptr, ID_MA); - if (ma == NULL) { + if (ma == nullptr) { return OPERATOR_CANCELLED; } PointerRNA ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object); - Object *ob = ptr.data; + Object *ob = static_cast<Object *>(ptr.data); BLI_assert(ob); PointerRNA mat_slot = CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot); @@ -2175,14 +2191,14 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op) const int target_slot = RNA_int_get(&mat_slot, "slot_index") + 1; /* only drop grease pencil material on grease pencil objects */ - if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) { + if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) { return OPERATOR_CANCELLED; } BKE_object_material_assign(bmain, ob, ma, target_slot, BKE_MAT_ASSIGN_USERPREF); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.cc index d4a9a4ca4cd..53f1265ee74 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.cc @@ -8,10 +8,10 @@ /* a full doc with API notes can be found in * bf-blender/trunk/blender/doc/guides/interface_API.txt */ -#include <ctype.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> +#include <cctype> +#include <cmath> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -57,7 +57,7 @@ #define ANIMATION_TIME 0.30 #define ANIMATION_INTERVAL 0.02 -typedef enum uiPanelRuntimeFlag { +enum uiPanelRuntimeFlag { PANEL_LAST_ADDED = (1 << 0), PANEL_ACTIVE = (1 << 2), PANEL_WAS_ACTIVE = (1 << 3), @@ -78,22 +78,22 @@ typedef enum uiPanelRuntimeFlag { PANEL_IS_DRAG_DROP = (1 << 10), /** Draw a border with the active color around the panel. */ PANEL_ACTIVE_BORDER = (1 << 11), -} uiPanelRuntimeFlag; +}; /* The state of the mouse position relative to the panel. */ -typedef enum uiPanelMouseState { +enum uiPanelMouseState { PANEL_MOUSE_OUTSIDE, /** Mouse is not in the panel. */ PANEL_MOUSE_INSIDE_CONTENT, /** Mouse is in the actual panel content. */ PANEL_MOUSE_INSIDE_HEADER, /** Mouse is in the panel header. */ -} uiPanelMouseState; +}; -typedef enum uiHandlePanelState { +enum uiHandlePanelState { PANEL_STATE_DRAG, PANEL_STATE_ANIMATION, PANEL_STATE_EXIT, -} uiHandlePanelState; +}; -typedef struct uiHandlePanelData { +struct uiHandlePanelData { uiHandlePanelState state; /* Animation. */ @@ -104,17 +104,17 @@ typedef struct uiHandlePanelData { int startx, starty; int startofsx, startofsy; float start_cur_xmin, start_cur_ymin; -} uiHandlePanelData; +}; -typedef struct PanelSort { +struct PanelSort { Panel *panel; int new_offset_x; int new_offset_y; -} PanelSort; +}; static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel); static int get_panel_real_size_y(const Panel *panel); -static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state); +static void panel_activate_state(const bContext *C, Panel *panel, const uiHandlePanelState state); static int compare_panel(const void *a, const void *b); static bool panel_type_context_poll(ARegion *region, const PanelType *panel_type, @@ -155,7 +155,7 @@ static bool panel_active_animation_changed(ListBase *lb, /* Detect animation. */ if (panel->activedata) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); if (data->state == PANEL_STATE_ANIMATION) { *r_panel_animation = panel; } @@ -178,7 +178,7 @@ static bool panel_active_animation_changed(ListBase *lb, static bool properties_space_needs_realign(const ScrArea *area, const ARegion *region) { if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) { - SpaceProperties *sbuts = area->spacedata.first; + const SpaceProperties *sbuts = static_cast<SpaceProperties *>(area->spacedata.first); if (sbuts->mainbo != sbuts->mainb) { return true; @@ -190,14 +190,14 @@ static bool properties_space_needs_realign(const ScrArea *area, const ARegion *r static bool panels_need_realign(const ScrArea *area, ARegion *region, Panel **r_panel_animation) { - *r_panel_animation = NULL; + *r_panel_animation = nullptr; if (properties_space_needs_realign(area, region)) { return true; } /* Detect if a panel was added or removed. */ - Panel *panel_animation = NULL; + Panel *panel_animation = nullptr; bool no_animation = false; if (panel_active_animation_changed(®ion->panels, &panel_animation, &no_animation)) { return true; @@ -225,7 +225,7 @@ static Panel *panel_add_instanced(ARegion *region, PanelType *panel_type, PointerRNA *custom_data) { - Panel *panel = MEM_callocN(sizeof(Panel), __func__); + Panel *panel = MEM_cnew<Panel>(__func__); panel->type = panel_type; BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname)); @@ -235,7 +235,7 @@ static Panel *panel_add_instanced(ARegion *region, /* Add the panel's children too. Although they aren't instanced panels, we can still use this * function to create them, as UI_panel_begin does other things we don't need to do. */ LISTBASE_FOREACH (LinkData *, child, &panel_type->children) { - PanelType *child_type = child->data; + PanelType *child_type = static_cast<PanelType *>(child->data); panel_add_instanced(region, &panel->children, child_type, custom_data); } @@ -265,12 +265,12 @@ Panel *UI_panel_add_instanced(const bContext *C, { ARegionType *region_type = region->type; - PanelType *panel_type = BLI_findstring( - ®ion_type->paneltypes, panel_idname, offsetof(PanelType, idname)); + PanelType *panel_type = static_cast<PanelType *>( + BLI_findstring(®ion_type->paneltypes, panel_idname, offsetof(PanelType, idname))); - if (panel_type == NULL) { + if (panel_type == nullptr) { printf("Panel type '%s' not found.\n", panel_idname); - return NULL; + return nullptr; } Panel *new_panel = panel_add_instanced(region, panels, panel_type, custom_data); @@ -314,14 +314,14 @@ void UI_panels_free_instanced(const bContext *C, ARegion *region) { /* Delete panels with the instanced flag. */ LISTBASE_FOREACH_MUTABLE (Panel *, panel, ®ion->panels) { - if ((panel->type != NULL) && (panel->type->flag & PANEL_TYPE_INSTANCED)) { + if ((panel->type != nullptr) && (panel->type->flag & PANEL_TYPE_INSTANCED)) { /* Make sure the panel's handler is removed before deleting it. */ - if (C != NULL && panel->activedata != NULL) { + if (C != nullptr && panel->activedata != nullptr) { panel_activate_state(C, panel, PANEL_STATE_EXIT); } /* Free panel's custom data. */ - if (panel->runtime.custom_data_ptr != NULL) { + if (panel->runtime.custom_data_ptr != nullptr) { MEM_freeN(panel->runtime.custom_data_ptr); } @@ -335,28 +335,28 @@ bool UI_panel_list_matches_data(ARegion *region, ListBase *data, uiListPanelIDFromDataFunc panel_idname_func) { - /* Check for NULL data. */ + /* Check for nullptr data. */ int data_len = 0; - Link *data_link = NULL; - if (data == NULL) { + Link *data_link = nullptr; + if (data == nullptr) { data_len = 0; - data_link = NULL; + data_link = nullptr; } else { data_len = BLI_listbase_count(data); - data_link = data->first; + data_link = static_cast<Link *>(data->first); } int i = 0; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { - if (panel->type != NULL && panel->type->flag & PANEL_TYPE_INSTANCED) { + if (panel->type != nullptr && panel->type->flag & PANEL_TYPE_INSTANCED) { /* The panels were reordered by drag and drop. */ if (panel->flag & PNL_INSTANCED_LIST_ORDER_CHANGED) { return false; } /* We reached the last data item before the last instanced panel. */ - if (data_link == NULL) { + if (data_link == nullptr) { return false; } @@ -383,15 +383,15 @@ bool UI_panel_list_matches_data(ARegion *region, static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *drag_panel) { /* Without a type we cannot access the reorder callback. */ - if (drag_panel->type == NULL) { + if (drag_panel->type == nullptr) { return; } /* Don't reorder if this instanced panel doesn't support drag and drop reordering. */ - if (drag_panel->type->reorder == NULL) { + if (drag_panel->type->reorder == nullptr) { return; } - char *context = NULL; + char *context = nullptr; if (!UI_panel_category_is_visible(region)) { context = drag_panel->type->context; } @@ -415,7 +415,8 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr BLI_assert(start_index != -1); /* The drag panel should definitely be in the list. */ /* Sort the matching instanced panels by their display order. */ - PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__); + PanelSort *panel_sort = static_cast<PanelSort *>( + MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__)); PanelSort *sort_index = panel_sort; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->type) { @@ -452,7 +453,7 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr /* Finally, move this panel's list item to the new index in its list. */ drag_panel->type->reorder(C, drag_panel, move_to_index); - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); } /** @@ -480,9 +481,9 @@ static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, */ static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel) { - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); BLI_assert(panel->type->flag & PANEL_TYPE_INSTANCED); - if (panel->type->get_list_data_expand_flag == NULL) { + if (panel->type->get_list_data_expand_flag == nullptr) { /* Instanced panel doesn't support loading expansion. */ return; } @@ -504,7 +505,7 @@ static void region_panels_set_expansion_from_list_data(const bContext *C, ARegio LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { PanelType *panel_type = panel->type; - if (panel_type != NULL && panel->type->flag & PANEL_TYPE_INSTANCED) { + if (panel_type != nullptr && panel->type->flag & PANEL_TYPE_INSTANCED) { panel_set_expansion_from_list_data(C, panel); } } @@ -537,7 +538,7 @@ static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *r { LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { PanelType *panel_type = panel->type; - if (panel_type == NULL) { + if (panel_type == nullptr) { continue; } @@ -563,11 +564,11 @@ static bool panel_custom_data_active_get(const Panel *panel) { /* The caller should make sure the panel is active and has a type. */ BLI_assert(UI_panel_is_active(panel)); - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); if (panel->type->active_property[0] != '\0') { PointerRNA *ptr = UI_panel_custom_data_get(panel); - if (ptr != NULL && !RNA_pointer_is_null(ptr)) { + if (ptr != nullptr && !RNA_pointer_is_null(ptr)) { return RNA_boolean_get(ptr, panel->type->active_property); } } @@ -579,12 +580,12 @@ static void panel_custom_data_active_set(Panel *panel) { /* Since the panel is interacted with, it should be active and have a type. */ BLI_assert(UI_panel_is_active(panel)); - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); if (panel->type->active_property[0] != '\0') { PointerRNA *ptr = UI_panel_custom_data_get(panel); - BLI_assert(RNA_struct_find_property(ptr, panel->type->active_property) != NULL); - if (ptr != NULL && !RNA_pointer_is_null(ptr)) { + BLI_assert(RNA_struct_find_property(ptr, panel->type->active_property) != nullptr); + if (ptr != nullptr && !RNA_pointer_is_null(ptr)) { RNA_boolean_set(ptr, panel->type->active_property, true); } } @@ -617,7 +618,7 @@ static void panel_set_runtime_flag_recursive(Panel *panel, short flag, bool valu static void panels_collapse_all(ARegion *region, const Panel *from_panel) { const bool has_category_tabs = UI_panel_category_is_visible(region); - const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL; + const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : nullptr; const PanelType *from_pt = from_panel->type; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { @@ -659,7 +660,7 @@ Panel *UI_panel_find_by_type(ListBase *lb, const PanelType *pt) return panel; } } - return NULL; + return nullptr; } Panel *UI_panel_begin( @@ -668,10 +669,10 @@ Panel *UI_panel_begin( Panel *panel_last; const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); const char *idname = pt->idname; - const bool newpanel = (panel == NULL); + const bool newpanel = (panel == nullptr); if (newpanel) { - panel = MEM_callocN(sizeof(Panel), __func__); + panel = MEM_cnew<Panel>(__func__); panel->type = pt; BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname)); @@ -701,7 +702,7 @@ Panel *UI_panel_begin( /* If a new panel is added, we insert it right after the panel that was last added. * This way new panels are inserted in the right place between versions. */ - for (panel_last = lb->first; panel_last; panel_last = panel_last->next) { + for (panel_last = static_cast<Panel *>(lb->first); panel_last; panel_last = panel_last->next) { if (panel_last->runtime_flag & PANEL_LAST_ADDED) { BLI_remlink(lb, panel); BLI_insertlinkafter(lb, panel_last, panel); @@ -755,7 +756,7 @@ void UI_panel_header_buttons_end(Panel *panel) /* A button group should always be created in #UI_panel_header_buttons_begin. */ BLI_assert(!BLI_listbase_is_empty(&block->button_groups)); - uiButtonGroup *button_group = block->button_groups.last; + uiButtonGroup *button_group = static_cast<uiButtonGroup *>(block->button_groups.last); button_group->flag &= ~UI_BUTTON_GROUP_LOCK; @@ -770,7 +771,7 @@ void UI_panel_header_buttons_end(Panel *panel) /* Always add a new button group. Although this may result in many empty groups, without it, * new buttons in the panel body not protected with a #ui_block_new_button_group call would * end up in the panel header group. */ - ui_block_new_button_group(block, 0); + ui_block_new_button_group(block, (uiButtonGroupFlag)0); } } @@ -867,7 +868,7 @@ void ui_panel_tag_search_filter_match(Panel *panel) static void panel_matches_search_filter_recursive(const Panel *panel, bool *filter_matches) { - *filter_matches |= panel->runtime_flag & PANEL_SEARCH_FILTER_MATCH; + *filter_matches |= bool(panel->runtime_flag & PANEL_SEARCH_FILTER_MATCH); /* If the panel has no match we need to make sure that its children are too. */ if (!*filter_matches) { @@ -893,7 +894,7 @@ static void panel_set_expansion_from_search_filter_recursive(const bContext *C, { /* This has to run on inactive panels that may not have a type, * but we can prevent running on header-less panels in some cases. */ - if (panel->type == NULL || !(panel->type->flag & PANEL_TYPE_NO_HEADER)) { + if (panel->type == nullptr || !(panel->type->flag & PANEL_TYPE_NO_HEADER)) { SET_FLAG_FROM_TEST(panel->runtime_flag, use_search_closed, PANEL_USE_CLOSED_FROM_SEARCH); } @@ -926,9 +927,9 @@ static void region_panels_set_expansion_from_search_filter(const bContext *C, static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *parent_panel) { uiBlock *block = panel->runtime.block; - BLI_assert(block != NULL); + BLI_assert(block != nullptr); BLI_assert(block->active); - if (parent_panel != NULL && UI_panel_is_closed(parent_panel)) { + if (parent_panel != nullptr && UI_panel_is_closed(parent_panel)) { /* The parent panel is closed, so this panel can be completely removed. */ UI_block_set_search_only(block, true); LISTBASE_FOREACH (uiBut *, but, &block->buttons) { @@ -944,7 +945,7 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel * continue; } LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) { - uiBut *but = link->data; + uiBut *but = static_cast<uiBut *>(link->data); but->flag |= UI_HIDDEN; } } @@ -952,7 +953,7 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel * LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { if (child_panel->runtime_flag & PANEL_ACTIVE) { - BLI_assert(child_panel->runtime.block != NULL); + BLI_assert(child_panel->runtime.block != nullptr); panel_remove_invisible_layouts_recursive(child_panel, panel); } } @@ -962,8 +963,8 @@ static void region_panels_remove_invisible_layouts(ARegion *region) { LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { - BLI_assert(panel->runtime.block != NULL); - panel_remove_invisible_layouts_recursive(panel, NULL); + BLI_assert(panel->runtime.block != nullptr); + panel_remove_invisible_layouts_recursive(panel, nullptr); } } } @@ -1054,7 +1055,7 @@ static void panel_draw_highlight_border(const Panel *panel, const rcti *rect, const rcti *header_rect) { - const bool is_subpanel = panel->type->parent != NULL; + const bool is_subpanel = panel->type->parent != nullptr; if (is_subpanel) { return; } @@ -1064,18 +1065,15 @@ static void panel_draw_highlight_border(const Panel *panel, const float radius = (btheme->tui.panel_roundness * U.widget_unit * 0.5f) / aspect; UI_draw_roundbox_corner_set(UI_CNR_ALL); + rctf box_rect; + box_rect.xmin = rect->xmin; + box_rect.xmax = rect->xmax; + box_rect.ymin = UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin; + box_rect.ymax = header_rect->ymax; + float color[4]; UI_GetThemeColor4fv(TH_SELECT_ACTIVE, color); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rect->xmin, - .xmax = rect->xmax, - .ymin = UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin, - .ymax = header_rect->ymax, - }, - false, - radius, - color); + UI_draw_roundbox_4fv(&box_rect, false, radius, color); } static void panel_draw_aligned_widgets(const uiStyle *style, @@ -1086,19 +1084,18 @@ static void panel_draw_aligned_widgets(const uiStyle *style, const bool show_background, const bool region_search_filter_active) { - const bool is_subpanel = panel->type->parent != NULL; + const bool is_subpanel = panel->type->parent != nullptr; const uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle; const int header_height = BLI_rcti_size_y(header_rect); const int scaled_unit = round_fl_to_int(UI_UNIT_X / aspect); /* Offset triangle and text to the right for subpanels. */ - const rcti widget_rect = { - .xmin = header_rect->xmin + (is_subpanel ? scaled_unit * 0.7f : 0), - .xmax = header_rect->xmax, - .ymin = header_rect->ymin, - .ymax = header_rect->ymax, - }; + rcti widget_rect; + widget_rect.xmin = header_rect->xmin + (is_subpanel ? scaled_unit * 0.7f : 0); + widget_rect.xmax = header_rect->xmax; + widget_rect.ymin = header_rect->ymin; + widget_rect.ymax = header_rect->ymax; uchar title_color[4]; panel_title_color_get(panel, show_background, region_search_filter_active, title_color); @@ -1121,20 +1118,16 @@ static void panel_draw_aligned_widgets(const uiStyle *style, /* Draw text label. */ if (panel->drawname[0] != '\0') { - const rcti title_rect = { - .xmin = widget_rect.xmin + (panel->labelofs / aspect) + scaled_unit * 1.1f, - .xmax = widget_rect.xmax, - .ymin = widget_rect.ymin - 2.0f / aspect, - .ymax = widget_rect.ymax, - }; - UI_fontstyle_draw(fontstyle, - &title_rect, - panel->drawname, - sizeof(panel->drawname), - title_color, - &(struct uiFontStyleDraw_Params){ - .align = UI_STYLE_TEXT_LEFT, - }); + rcti title_rect; + title_rect.xmin = widget_rect.xmin + (panel->labelofs / aspect) + scaled_unit * 1.1f; + title_rect.xmax = widget_rect.xmax; + title_rect.ymin = widget_rect.ymin - 2.0f / aspect; + title_rect.ymax = widget_rect.ymax; + + uiFontStyleDraw_Params params{}; + params.align = UI_STYLE_TEXT_LEFT; + UI_fontstyle_draw( + fontstyle, &title_rect, panel->drawname, sizeof(panel->drawname), title_color, ¶ms); } /* Draw the pin icon. */ @@ -1177,7 +1170,7 @@ static void panel_draw_aligned_backdrop(const Panel *panel, const rcti *rect, const rcti *header_rect) { - const bool is_subpanel = panel->type->parent != NULL; + const bool is_subpanel = panel->type->parent != nullptr; const bool is_open = !UI_panel_is_closed(panel); if (is_subpanel && !is_open) { @@ -1197,16 +1190,12 @@ static void panel_draw_aligned_backdrop(const Panel *panel, UI_draw_roundbox_corner_set(is_open ? UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT : UI_CNR_ALL); UI_GetThemeColor4fv((is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK), panel_backcolor); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rect->xmin, - .xmax = rect->xmax, - .ymin = rect->ymin, - .ymax = rect->ymax, - }, - true, - radius, - panel_backcolor); + rctf box_rect; + box_rect.xmin = rect->xmin; + box_rect.xmax = rect->xmax; + box_rect.ymin = rect->ymin; + box_rect.ymax = rect->ymax; + UI_draw_roundbox_4fv(&box_rect, true, radius, panel_backcolor); } /* Panel header backdrops for non sub-panels. */ @@ -1217,16 +1206,12 @@ static void panel_draw_aligned_backdrop(const Panel *panel, UI_draw_roundbox_corner_set(is_open ? UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT : UI_CNR_ALL); /* Change the width a little bit to line up with the sides. */ - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rect->xmin, - .xmax = rect->xmax, - .ymin = header_rect->ymin, - .ymax = header_rect->ymax, - }, - true, - radius, - panel_headercolor); + rctf box_rect; + box_rect.xmin = rect->xmin; + box_rect.xmax = rect->xmax; + box_rect.ymin = header_rect->ymin; + box_rect.ymax = header_rect->ymax; + UI_draw_roundbox_4fv(&box_rect, true, radius, panel_headercolor); } GPU_blend(GPU_BLEND_NONE); @@ -1247,7 +1232,7 @@ void ui_draw_aligned_panel(const uiStyle *style, rect->xmin, rect->xmax, rect->ymax, - rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f), + rect->ymax + (int)floor(PNL_HEADER / block->aspect + 0.001f), }; if (show_background) { @@ -1300,7 +1285,7 @@ bool UI_panel_should_show_background(const ARegion *region, const PanelType *pan void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) { // #define USE_FLAT_INACTIVE - const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT); + const bool is_left = (bool)RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT); View2D *v2d = ®ion->v2d; const uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; @@ -1463,26 +1448,17 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) { /* Draw filled rectangle and outline for tab. */ UI_draw_roundbox_corner_set(roundboxtype); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rct->xmin, - .xmax = rct->xmax, - .ymin = rct->ymin, - .ymax = rct->ymax, - }, - true, - tab_curve_radius, - is_active ? theme_col_tab_active : theme_col_tab_inactive); - UI_draw_roundbox_4fv( - &(const rctf){ - .xmin = rct->xmin, - .xmax = rct->xmax, - .ymin = rct->ymin, - .ymax = rct->ymax, - }, - false, - tab_curve_radius, - theme_col_tab_outline); + rctf box_rect; + box_rect.xmin = rct->xmin; + box_rect.xmax = rct->xmax; + box_rect.ymin = rct->ymin; + box_rect.ymax = rct->ymax; + + UI_draw_roundbox_4fv(&box_rect, + true, + tab_curve_radius, + is_active ? theme_col_tab_active : theme_col_tab_inactive); + UI_draw_roundbox_4fv(&box_rect, false, tab_curve_radius, theme_col_tab_outline); /* Disguise the outline on one side to join the tab to the panel. */ pos = GPU_vertformat_attr_add( @@ -1502,7 +1478,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) if (do_scaletabs) { category_draw_len = BLF_width_to_strlen( - fontid, category_id_draw, category_draw_len, category_width, NULL); + fontid, category_id_draw, category_draw_len, category_width, nullptr); } BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f); @@ -1660,7 +1636,7 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { /* These panels should have types since they are currently displayed to the user. */ - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); active_panels_len++; } } @@ -1669,7 +1645,8 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra } /* Sort panels. */ - PanelSort *panel_sort = MEM_mallocN(sizeof(PanelSort) * active_panels_len, __func__); + PanelSort *panel_sort = static_cast<PanelSort *>( + MEM_mallocN(sizeof(PanelSort) * active_panels_len, __func__)); { PanelSort *ps = panel_sort; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { @@ -1791,7 +1768,7 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y) static void ui_do_animate(bContext *C, Panel *panel) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); ARegion *region = CTX_wm_region(C); float fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME; @@ -1856,7 +1833,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PANEL_ACTIVE) { - BLI_assert(panel->runtime.block != NULL); + BLI_assert(panel->runtime.block != nullptr); panel_calculate_size_recursive(region, panel); } } @@ -1892,7 +1869,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) #define DRAG_REGION_PAD (PNL_HEADER * 0.5) static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); ARegion *region = CTX_wm_region(C); /* Keep the drag position in the region with a small pad to keep the panel visible. */ @@ -1942,14 +1919,14 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, return PANEL_MOUSE_OUTSIDE; } -typedef struct uiPanelDragCollapseHandle { +struct uiPanelDragCollapseHandle { bool was_first_open; int xy_init[2]; -} uiPanelDragCollapseHandle; +}; static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata) { - uiPanelDragCollapseHandle *dragcol_data = userdata; + uiPanelDragCollapseHandle *dragcol_data = static_cast<uiPanelDragCollapseHandle *>(userdata); MEM_freeN(dragcol_data); } @@ -1960,11 +1937,11 @@ static void ui_panel_drag_collapse(const bContext *C, ARegion *region = CTX_wm_region(C); LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { - float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)}; - float xy_b_block[2] = {UNPACK2(xy_dst)}; + float xy_a_block[2] = {(float)dragcol_data->xy_init[0], (float)dragcol_data->xy_init[1]}; + float xy_b_block[2] = {(float)xy_dst[0], (float)xy_dst[1]}; Panel *panel = block->panel; - if (panel == NULL || (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER))) { + if (panel == nullptr || (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER))) { continue; } const int oldflag = panel->flag; @@ -2006,7 +1983,7 @@ static void ui_panel_drag_collapse(const bContext *C, static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata) { wmWindow *win = CTX_wm_window(C); - uiPanelDragCollapseHandle *dragcol_data = userdata; + uiPanelDragCollapseHandle *dragcol_data = static_cast<uiPanelDragCollapseHandle *>(userdata); short retval = WM_UI_HANDLER_CONTINUE; switch (event->type) { @@ -2037,7 +2014,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was { wmWindow *win = CTX_wm_window(C); const wmEvent *event = win->eventstate; - uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__); + uiPanelDragCollapseHandle *dragcol_data = MEM_new<uiPanelDragCollapseHandle>(__func__); dragcol_data->was_first_open = was_open; copy_v2_v2_int(dragcol_data->xy_init, event->xy); @@ -2066,10 +2043,10 @@ static void ui_handle_panel_header(const bContext *C, Panel *panel = block->panel; ARegion *region = CTX_wm_region(C); - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); BLI_assert(!(panel->type->flag & PANEL_TYPE_NO_HEADER)); - const bool is_subpanel = (panel->type->parent != NULL); + const bool is_subpanel = (panel->type->parent != nullptr); const bool use_pin = UI_panel_category_is_visible(region) && UI_panel_can_be_pinned(panel); const bool show_pin = use_pin && (panel->flag & PNL_PIN); const bool show_drag = !is_subpanel; @@ -2102,8 +2079,8 @@ static void ui_handle_panel_header(const bContext *C, else { /* If a panel has sub-panels and it's open, toggle the expansion * of the sub-panels (based on the expansion of the first sub-panel). */ - Panel *first_child = panel->children.first; - BLI_assert(first_child != NULL); + Panel *first_child = static_cast<Panel *>(panel->children.first); + BLI_assert(first_child != nullptr); panel_set_flag_recursive(panel, PNL_CLOSED, !UI_panel_is_closed(first_child)); panel->flag |= PNL_CLOSED; } @@ -2157,13 +2134,14 @@ bool UI_panel_category_is_visible(const ARegion *region) PanelCategoryDyn *UI_panel_category_find(const ARegion *region, const char *idname) { - return BLI_findstring(®ion->panels_category, idname, offsetof(PanelCategoryDyn, idname)); + return static_cast<PanelCategoryDyn *>( + BLI_findstring(®ion->panels_category, idname, offsetof(PanelCategoryDyn, idname))); } PanelCategoryStack *UI_panel_category_active_find(ARegion *region, const char *idname) { - return BLI_findstring( - ®ion->panels_category_active, idname, offsetof(PanelCategoryStack, idname)); + return static_cast<PanelCategoryStack *>(BLI_findstring( + ®ion->panels_category_active, idname, offsetof(PanelCategoryStack, idname))); } static void ui_panel_category_active_set(ARegion *region, const char *idname, bool fallback) @@ -2175,7 +2153,7 @@ static void ui_panel_category_active_set(ARegion *region, const char *idname, bo BLI_remlink(lb, pc_act); } else { - pc_act = MEM_callocN(sizeof(PanelCategoryStack), __func__); + pc_act = MEM_cnew<PanelCategoryStack>(__func__); BLI_strncpy(pc_act->idname, idname, sizeof(pc_act->idname)); } @@ -2226,14 +2204,14 @@ const char *UI_panel_category_active_get(ARegion *region, bool set_fallback) } if (set_fallback) { - PanelCategoryDyn *pc_dyn = region->panels_category.first; + PanelCategoryDyn *pc_dyn = static_cast<PanelCategoryDyn *>(region->panels_category.first); if (pc_dyn) { ui_panel_category_active_set(region, pc_dyn->idname, true); return pc_dyn->idname; } } - return NULL; + return nullptr; } static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const wmEvent *event) @@ -2244,12 +2222,12 @@ static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const } } - return NULL; + return nullptr; } void UI_panel_category_add(ARegion *region, const char *name) { - PanelCategoryDyn *pc_dyn = MEM_callocN(sizeof(*pc_dyn), __func__); + PanelCategoryDyn *pc_dyn = MEM_cnew<PanelCategoryDyn>(__func__); BLI_addtail(®ion->panels_category, pc_dyn); BLI_strncpy(pc_dyn->idname, name, sizeof(pc_dyn->idname)); @@ -2294,7 +2272,8 @@ static int ui_handle_panel_category_cycling(const wmEvent *event, pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next; if (!pc_dyn) { /* Proper cyclic behavior, back to first/last category (only used for ctrl+tab). */ - pc_dyn = backwards ? region->panels_category.last : region->panels_category.first; + pc_dyn = backwards ? static_cast<PanelCategoryDyn *>(region->panels_category.last) : + static_cast<PanelCategoryDyn *>(region->panels_category.first); } } @@ -2359,11 +2338,11 @@ int ui_handler_panel_region(bContext *C, return retval; } - const bool region_has_active_button = (ui_region_find_active_but(region) != NULL); + const bool region_has_active_button = (ui_region_find_active_but(region) != nullptr); LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { Panel *panel = block->panel; - if (panel == NULL || panel->type == NULL) { + if (panel == nullptr || panel->type == nullptr) { continue; } /* We can't expand or collapse panels without headers, they would disappear. */ @@ -2434,10 +2413,10 @@ void UI_panel_context_pointer_set(Panel *panel, const char *name, PointerRNA *pt void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data) { - BLI_assert(panel->type != NULL); + BLI_assert(panel->type != nullptr); /* Free the old custom data, which should be shared among all of the panel's sub-panels. */ - if (panel->runtime.custom_data_ptr != NULL) { + if (panel->runtime.custom_data_ptr != nullptr) { MEM_freeN(panel->runtime.custom_data_ptr); } @@ -2455,7 +2434,7 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { Panel *panel = block->panel; - if (panel == NULL) { + if (panel == nullptr) { continue; } @@ -2468,12 +2447,12 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm } } - return NULL; + return nullptr; } bool UI_panel_can_be_pinned(const Panel *panel) { - return (panel->type->parent == NULL) && !(panel->type->flag & PANEL_TYPE_INSTANCED); + return (panel->type->parent == nullptr) && !(panel->type->flag & PANEL_TYPE_INSTANCED); } /** \} */ @@ -2485,8 +2464,8 @@ bool UI_panel_can_be_pinned(const Panel *panel) /* NOTE: this is modal handler and should not swallow events for animation. */ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) { - Panel *panel = userdata; - uiHandlePanelData *data = panel->activedata; + Panel *panel = static_cast<Panel *>(userdata); + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); /* Verify if we can stop. */ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { @@ -2506,7 +2485,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) } } - data = panel->activedata; + data = static_cast<uiHandlePanelData *>(panel->activedata); if (data && data->state == PANEL_STATE_ANIMATION) { return WM_UI_HANDLER_CONTINUE; @@ -2516,7 +2495,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) static void ui_handler_remove_panel(bContext *C, void *userdata) { - Panel *panel = userdata; + Panel *panel = static_cast<Panel *>(userdata); panel_activate_state(C, panel, PANEL_STATE_EXIT); } @@ -2527,13 +2506,13 @@ static void panel_handle_data_ensure(const bContext *C, Panel *panel, const uiHandlePanelState state) { - if (panel->activedata == NULL) { + if (panel->activedata == nullptr) { panel->activedata = MEM_callocN(sizeof(uiHandlePanelData), __func__); WM_event_add_ui_handler( C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, 0); } - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL); @@ -2554,11 +2533,11 @@ static void panel_handle_data_ensure(const bContext *C, */ static void panel_activate_state(const bContext *C, Panel *panel, const uiHandlePanelState state) { - uiHandlePanelData *data = panel->activedata; + uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); wmWindow *win = CTX_wm_window(C); ARegion *region = CTX_wm_region(C); - if (data != NULL && data->state == state) { + if (data != nullptr && data->state == state) { return; } @@ -2582,15 +2561,15 @@ static void panel_activate_state(const bContext *C, Panel *panel, const uiHandle else if (state == PANEL_STATE_EXIT) { panel_set_runtime_flag_recursive(panel, PANEL_IS_DRAG_DROP, false); - BLI_assert(data != NULL); + BLI_assert(data != nullptr); if (data->animtimer) { WM_event_remove_timer(CTX_wm_manager(C), win, data->animtimer); - data->animtimer = NULL; + data->animtimer = nullptr; } MEM_freeN(data); - panel->activedata = NULL; + panel->activedata = nullptr; WM_event_remove_ui_handler( &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false); diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc index 09902dd6c35..becdfaf4e25 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.cc +++ b/source/blender/editors/interface/interface_region_menu_pie.cc @@ -27,6 +27,7 @@ #include "WM_types.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "UI_interface.h" @@ -36,7 +37,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Pie Menu diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc index a22f7218203..0647e1a4a70 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.cc +++ b/source/blender/editors/interface/interface_region_menu_popup.cc @@ -39,7 +39,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Utility Functions diff --git a/source/blender/editors/interface/interface_region_popover.cc b/source/blender/editors/interface/interface_region_popover.cc index 2e10261a4f7..c152a9aacd5 100644 --- a/source/blender/editors/interface/interface_region_popover.cc +++ b/source/blender/editors/interface/interface_region_popover.cc @@ -46,7 +46,7 @@ #include "UI_interface.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Popup Menu with Callback or String diff --git a/source/blender/editors/interface/interface_region_popup.cc b/source/blender/editors/interface/interface_region_popup.cc index 74c228e3338..f6b078c033e 100644 --- a/source/blender/editors/interface/interface_region_popup.cc +++ b/source/blender/editors/interface/interface_region_popup.cc @@ -31,7 +31,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" /* -------------------------------------------------------------------- */ /** \name Utility Functions diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc index 81c0c29d09a..f04229609f9 100644 --- a/source/blender/editors/interface/interface_region_search.cc +++ b/source/blender/editors/interface/interface_region_search.cc @@ -41,7 +41,7 @@ #include "GPU_state.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" #define MENU_BORDER (int)(0.3f * U.widget_unit) diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.cc index 88fe866f717..e18d23c8a1c 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.cc @@ -16,9 +16,9 @@ * For now it's not a priority, so leave as-is. */ -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> +#include <cstdarg> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -39,6 +39,7 @@ #include "WM_types.h" #include "RNA_access.h" +#include "RNA_path.h" #include "UI_interface.h" @@ -52,7 +53,7 @@ #include "ED_screen.h" #include "interface_intern.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" #define UI_TIP_PAD_FAC 1.3f #define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y) @@ -60,24 +61,32 @@ #define UI_TIP_STR_MAX 1024 -typedef struct uiTooltipFormat { - enum { - UI_TIP_STYLE_NORMAL = 0, - UI_TIP_STYLE_HEADER, - UI_TIP_STYLE_MONO, - } style : 3; - enum { - UI_TIP_LC_MAIN = 0, /* primary text */ - UI_TIP_LC_VALUE, /* the value of buttons (also shortcuts) */ - UI_TIP_LC_ACTIVE, /* titles of active enum values */ - UI_TIP_LC_NORMAL, /* regular text */ - UI_TIP_LC_PYTHON, /* Python snippet */ - UI_TIP_LC_ALERT, /* description of why operator can't run */ - } color_id : 4; - int is_pad : 1; -} uiTooltipFormat; - -typedef struct uiTooltipField { +struct uiTooltipFormat { + enum class Style : int8_t { + Normal, + Header, + Mono, + }; + enum class ColorID : int8_t { + /** Primary Text. */ + Main = 0, + /** The value of buttons (also shortcuts). */ + Value = 1, + /** Titles of active enum values. */ + Active = 2, + /** Regular text. */ + Normal = 3, + /** Python snippet. */ + Python = 4, + /** Description of why an operator can't run. */ + Alert = 5, + }; + Style style; + ColorID color_id; + bool is_pad; +}; + +struct uiTooltipField { char *text; char *text_suffix; struct { @@ -85,34 +94,47 @@ typedef struct uiTooltipField { uint lines; /* number of lines, 1 or more with word-wrap */ } geom; uiTooltipFormat format; +}; -} uiTooltipField; - -typedef struct uiTooltipData { +struct uiTooltipData { rcti bbox; uiTooltipField *fields; uint fields_len; uiFontStyle fstyle; int wrap_width; int toth, lineh; -} uiTooltipData; +}; #define UI_TIP_LC_MAX 6 -BLI_STATIC_ASSERT(UI_TIP_LC_MAX == UI_TIP_LC_ALERT + 1, "invalid lc-max"); +BLI_STATIC_ASSERT(UI_TIP_LC_MAX == static_cast<int>(uiTooltipFormat::ColorID::Alert) + 1, + "invalid lc-max"); BLI_STATIC_ASSERT(sizeof(uiTooltipFormat) <= sizeof(int), "oversize"); static uiTooltipField *text_field_add_only(uiTooltipData *data) { data->fields_len += 1; - data->fields = MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len); + data->fields = static_cast<uiTooltipField *>( + MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len)); return &data->fields[data->fields_len - 1]; } -static uiTooltipField *text_field_add(uiTooltipData *data, const uiTooltipFormat *format) +// static uiTooltipField *text_field_add(uiTooltipData *data, const uiTooltipFormat *format) +// { +// uiTooltipField *field = text_field_add_only(data); +// field->format = *format; +// return field; +// } + +static uiTooltipField *text_field_add(uiTooltipData *data, + const uiTooltipFormat::Style style, + const uiTooltipFormat::ColorID color, + const bool is_pad = false) { uiTooltipField *field = text_field_add_only(data); - field->format = *format; + field->format = {}; + field->format.style = style; + field->format.color_id = color, field->format.is_pad = is_pad; return field; } @@ -137,25 +159,26 @@ static void rgb_tint(float col[3], float h, float h_strength, float v, float v_s static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region) { const float pad_px = UI_TIP_PADDING; - uiTooltipData *data = region->regiondata; + uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata); const uiWidgetColors *theme = ui_tooltip_get_theme(); rcti bbox = data->bbox; float tip_colors[UI_TIP_LC_MAX][3]; uchar drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */ - float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */ - float *value_color = tip_colors[UI_TIP_LC_VALUE]; - float *active_color = tip_colors[UI_TIP_LC_ACTIVE]; - float *normal_color = tip_colors[UI_TIP_LC_NORMAL]; - float *python_color = tip_colors[UI_TIP_LC_PYTHON]; - float *alert_color = tip_colors[UI_TIP_LC_ALERT]; + /* the color from the theme */ + float *main_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Main)]; + float *value_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Value)]; + float *active_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Active)]; + float *normal_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Normal)]; + float *python_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Python)]; + float *alert_color = tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Alert)]; float background_color[3]; wmOrtho2_region_pixelspace(region); /* draw background */ - ui_draw_tooltip_background(UI_style_get(), NULL, &bbox); + ui_draw_tooltip_background(UI_style_get(), nullptr, &bbox); /* set background_color */ rgb_uchar_to_float(background_color, theme->inner); @@ -189,16 +212,17 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region for (int i = 0; i < data->fields_len; i++) { const uiTooltipField *field = &data->fields[i]; - const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; + const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : + nullptr; bbox.ymin = bbox.ymax - (data->lineh * field->geom.lines); - if (field->format.style == UI_TIP_STYLE_HEADER) { - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; + if (field->format.style == uiTooltipFormat::Style::Header) { + uiFontStyleDraw_Params fs_params{}; + fs_params.align = UI_STYLE_TEXT_LEFT; + fs_params.word_wrap = true; + /* draw header and active data (is done here to be able to change color) */ - rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]); + rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Main)]); UI_fontstyle_set(&data->fstyle); UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); @@ -209,7 +233,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region bbox.xmin += xofs; bbox.ymax -= yofs; - rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]); + rgb_float_to_uchar(drawcol, + tip_colors[static_cast<int>(uiTooltipFormat::ColorID::Active)]); UI_fontstyle_draw( &data->fstyle, &bbox, field->text_suffix, UI_TIP_STR_MAX, drawcol, &fs_params); @@ -218,29 +243,27 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region bbox.ymax += yofs; } } - else if (field->format.style == UI_TIP_STYLE_MONO) { - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; + else if (field->format.style == uiTooltipFormat::Style::Mono) { + uiFontStyleDraw_Params fs_params{}; + fs_params.align = UI_STYLE_TEXT_LEFT; + fs_params.word_wrap = true; uiFontStyle fstyle_mono = data->fstyle; fstyle_mono.uifont_id = blf_mono_font; UI_fontstyle_set(&fstyle_mono); /* XXX, needed because we don't have mono in 'U.uifonts' */ BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi); - rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); + rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(field->format.color_id)]); UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); } else { - BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL); - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; + BLI_assert(field->format.style == uiTooltipFormat::Style::Normal); + uiFontStyleDraw_Params fs_params{}; + fs_params.align = UI_STYLE_TEXT_LEFT; + fs_params.word_wrap = true; /* draw remaining data */ - rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); + rgb_float_to_uchar(drawcol, tip_colors[static_cast<int>(field->format.color_id)]); UI_fontstyle_set(&data->fstyle); UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); } @@ -258,7 +281,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region static void ui_tooltip_region_free_cb(ARegion *region) { - uiTooltipData *data = region->regiondata; + uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata); for (int i = 0; i < data->fields_len; i++) { const uiTooltipField *field = &data->fields[i]; @@ -269,7 +292,7 @@ static void ui_tooltip_region_free_cb(ARegion *region) } MEM_freeN(data->fields); MEM_freeN(data); - region->regiondata = NULL; + region->regiondata = nullptr; } /** \} */ @@ -280,7 +303,7 @@ static void ui_tooltip_region_free_cb(ARegion *region) static char *ui_tooltip_text_python_from_op(bContext *C, wmOperatorType *ot, PointerRNA *opptr) { - char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, opptr); + char *str = WM_operator_pystring_ex(C, nullptr, false, false, ot, opptr); /* Avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary. */ WM_operator_pystring_abbreviate(str, 32); @@ -303,24 +326,17 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data, LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { wmOperatorType *ot = WM_operatortype_find(kmi->idname, true); - if (ot != NULL) { + if (ot != nullptr) { /* Tip */ { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true); field->text = BLI_strdup(ot->description ? ot->description : ot->name); } /* Shortcut */ { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); bool found = false; if (WM_keymap_item_to_string(kmi, false, buf, sizeof(buf))) { found = true; @@ -330,11 +346,8 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data, /* Python */ if (U.flag & USER_TOOLTIPS_PYTHON) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_PYTHON, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Python); char *str = ui_tooltip_text_python_from_op(C, ot, kmi->ptr); field->text = BLI_sprintfN(TIP_("Python: %s"), str); MEM_freeN(str); @@ -352,17 +365,17 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data, */ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is_label) { - if (but->optype == NULL) { - return NULL; + if (but->optype == nullptr) { + return nullptr; } if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_id")) { - return NULL; + return nullptr; } /* Needed to get the space-data's type (below). */ - if (CTX_wm_space_data(C) == NULL) { - return NULL; + if (CTX_wm_space_data(C) == nullptr) { + return nullptr; } char tool_id[MAX_NAME]; @@ -377,7 +390,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is const char *has_valid_context_error = IFACE_("Unsupported context"); { ScrArea *area = CTX_wm_area(C); - if (area == NULL) { + if (area == nullptr) { has_valid_context = false; } else { @@ -392,7 +405,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is } /* We have a tool, now extract the info. */ - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); #ifdef WITH_PYTHON /* it turns out to be most simple to do this via Python since C @@ -401,7 +414,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* Title (when icon-only). */ if (but->drawstr[0] == '\0') { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "bl_ui.space_toolsystem_common.item_from_id(" @@ -409,16 +422,16 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is "bpy.context.space_data.type, " "'%s').label", tool_id); - char *expr_result = NULL; + char *expr_result = nullptr; bool is_error = false; if (has_valid_context == false) { expr_result = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) { if (STREQ(expr_result, "")) { MEM_freeN(expr_result); - expr_result = NULL; + expr_result = nullptr; } } else { @@ -428,7 +441,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is is_error = true; } - if (expr_result != NULL) { + if (expr_result != nullptr) { /* NOTE: This is a very weak hack to get a valid translation most of the time... * Proper way to do would be to get i18n context from the item, somehow. */ const char *label_str = CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, expr_result); @@ -441,23 +454,19 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is expr_result = BLI_strdup(label_str); } - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true); field->text = expr_result; if (UNLIKELY(is_error)) { - field->format.color_id = UI_TIP_LC_ALERT; + field->format.color_id = uiTooltipFormat::ColorID::Alert; } } } /* Tip. */ if (is_label == false) { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "bl_ui.space_toolsystem_common.description_from_id(" @@ -466,16 +475,16 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is "'%s') + '.'", tool_id); - char *expr_result = NULL; + char *expr_result = nullptr; bool is_error = false; if (has_valid_context == false) { expr_result = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_string(C, expr_imports, expr, nullptr, &expr_result)) { if (STREQ(expr_result, ".")) { MEM_freeN(expr_result); - expr_result = NULL; + expr_result = nullptr; } } else { @@ -485,17 +494,13 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is is_error = true; } - if (expr_result != NULL) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); + if (expr_result != nullptr) { + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Main, true); field->text = expr_result; if (UNLIKELY(is_error)) { - field->format.color_id = UI_TIP_LC_ALERT; + field->format.color_id = uiTooltipFormat::ColorID::Alert; } } } @@ -514,18 +519,18 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is * * Either way case it's useful to show the shortcut. */ - char *shortcut = NULL; + char *shortcut = nullptr; { - uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - UI_but_string_info_get(C, but, &op_keymap, NULL); + uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, nullptr}; + UI_but_string_info_get(C, but, &op_keymap, nullptr); shortcut = op_keymap.strinfo; } - if (shortcut == NULL) { + if (shortcut == nullptr) { const ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - if (tool_attr != NULL) { + if (tool_attr != nullptr) { const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); const char *tool_id_lstrip = strrchr(tool_id, '.'); const int tool_id_offset = tool_id_lstrip ? ((tool_id_lstrip - tool_id) + 1) : 0; @@ -542,7 +547,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (WM_key_event_operator_string(C, ot->idname, WM_OP_INVOKE_REGION_WIN, - op_props.data, + static_cast<IDProperty *>(op_props.data), true, shortcut_brush, ARRAY_SIZE(shortcut_brush))) { @@ -553,20 +558,20 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is } } - if (shortcut == NULL) { + if (shortcut == nullptr) { /* Check for direct access to the tool. */ char shortcut_toolbar[128] = ""; if (WM_key_event_operator_string(C, "WM_OT_toolbar", WM_OP_INVOKE_REGION_WIN, - NULL, + nullptr, true, shortcut_toolbar, ARRAY_SIZE(shortcut_toolbar))) { /* Generate keymap in order to inspect it. * NOTE: we could make a utility to avoid the keymap generation part of this. */ const char *expr_imports[] = { - "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", NULL}; + "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", nullptr}; const char *expr = ("getattr(" "bl_keymap_utils.keymap_from_toolbar.generate(" @@ -579,7 +584,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { shortcut = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) { if (expr_result != 0) { wmKeyMap *keymap = (wmKeyMap *)expr_result; LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { @@ -602,13 +607,9 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is } } - if (shortcut != NULL) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + if (shortcut != nullptr) { + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), shortcut); MEM_freeN(shortcut); } @@ -626,11 +627,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is * This is a little involved since the shortcut may be bound to another tool in this group, * instead of the current tool on display. */ - char *expr_result = NULL; + char *expr_result = nullptr; size_t expr_result_len; { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "'\\x00'.join(" @@ -644,12 +645,12 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* pass */ } else if (BPY_run_string_as_string_and_size( - C, expr_imports, expr, NULL, &expr_result, &expr_result_len)) { + C, expr_imports, expr, nullptr, &expr_result, &expr_result_len)) { /* pass. */ } } - if (expr_result != NULL) { + if (expr_result != nullptr) { PointerRNA op_props; WM_operator_properties_create_ptr(&op_props, but->optype); RNA_boolean_set(&op_props, "cycle", true); @@ -664,7 +665,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (WM_key_event_operator_string(C, but->optype->idname, WM_OP_INVOKE_REGION_WIN, - op_props.data, + static_cast<IDProperty *>(op_props.data), true, shortcut, ARRAY_SIZE(shortcut))) { @@ -677,12 +678,8 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is MEM_freeN(expr_result); if (shortcut[0] != '\0') { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut Cycle: %s"), shortcut); } } @@ -690,12 +687,8 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* Python */ if ((is_label == false) && (U.flag & USER_TOOLTIPS_PYTHON)) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Python, true); char *str = ui_tooltip_text_python_from_op(C, but->optype, but->opptr); field->text = BLI_sprintfN(TIP_("Python: %s"), str); MEM_freeN(str); @@ -705,7 +698,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* This is too handy not to expose somehow, let's be sneaky for now. */ if ((is_label == false) && CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + const char *expr_imports[] = {"bpy", "bl_ui", nullptr}; char expr[256]; SNPRINTF(expr, "getattr(" @@ -721,15 +714,11 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { /* pass */ } - else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) { + else if (BPY_run_string_as_intptr(C, expr_imports, expr, nullptr, &expr_result)) { if (expr_result != 0) { { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal, true); field->text = BLI_strdup("Tool Keymap:"); } wmKeyMap *keymap = (wmKeyMap *)expr_result; @@ -746,7 +735,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } @@ -755,26 +744,26 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon) { - uiStringInfo but_label = {BUT_GET_LABEL, NULL}; - uiStringInfo but_tip = {BUT_GET_TIP, NULL}; - uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; - uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; - uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, NULL}; - uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; - uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; + uiStringInfo but_label = {BUT_GET_LABEL, nullptr}; + uiStringInfo but_tip = {BUT_GET_TIP, nullptr}; + uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, nullptr}; + uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, nullptr}; + uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, nullptr}; + uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, nullptr}; + uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, nullptr}; + uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, nullptr}; char buf[512]; wmOperatorType *optype = extra_icon ? UI_but_extra_operator_icon_optype_get(extra_icon) : but->optype; - PropertyRNA *rnaprop = extra_icon ? NULL : but->rnaprop; + PropertyRNA *rnaprop = extra_icon ? nullptr : but->rnaprop; /* create tooltip data */ - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); if (extra_icon) { - UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, NULL); + UI_but_extra_icon_string_info_get(C, extra_icon, &but_label, &but_tip, &op_keymap, nullptr); } else { UI_but_string_info_get(C, @@ -787,7 +776,7 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, &prop_keymap, &rna_struct, &rna_prop, - NULL); + nullptr); } /* Tip Label (only for buttons not already showing the label). @@ -795,22 +784,17 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, * Buttons with dynamic tooltips also don't get their default label here since they * can already provide more accurate and specific tooltip content. */ if (but_label.strinfo && !STRPREFIX(but->drawstr, but_label.strinfo) && !but->tip_func) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal); + field->text = BLI_strdup(but_label.strinfo); } /* Tip */ if (but_tip.strinfo) { { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal); if (enum_label.strinfo) { field->text = BLI_sprintfN("%s: ", but_tip.strinfo); field->text_suffix = BLI_strdup(enum_label.strinfo); @@ -822,44 +806,29 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, /* special case enum rna buttons */ if ((but->type & UI_BTYPE_ROW) && rnaprop && RNA_property_flag(rnaprop) & PROP_ENUM_FLAG) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); field->text = BLI_strdup(TIP_("(Shift-Click/Drag to select multiple)")); } } /* Enum field label & tip */ if (enum_tip.strinfo) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value); field->text = BLI_strdup(enum_tip.strinfo); } /* Op shortcut */ if (op_keymap.strinfo) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), op_keymap.strinfo); } /* Property context-toggle shortcut */ if (prop_keymap.strinfo) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), prop_keymap.strinfo); } @@ -869,12 +838,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, /* full string */ ui_but_string_get(but, buf, sizeof(buf)); if (buf[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Value: %s"), buf); } } @@ -889,22 +854,16 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, RNA_property_float_get_index(&but->rnapoin, rnaprop, but->rnaindex) : RNA_property_float_get(&but->rnapoin, rnaprop); - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value); field->text = BLI_sprintfN(TIP_("Radians: %f"), value); } } if (but->flag & UI_BUT_DRIVEN) { if (ui_but_anim_expression_get(but, buf, sizeof(buf))) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); field->text = BLI_sprintfN(TIP_("Expression: %s"), buf); } } @@ -912,11 +871,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, if (but->rnapoin.owner_id) { const ID *id = but->rnapoin.owner_id; if (ID_IS_LINKED(id)) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal); field->text = BLI_sprintfN(TIP_("Library: %s"), id->lib->filepath); } } @@ -933,12 +889,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, /* operator info */ if (U.flag & USER_TOOLTIPS_PYTHON) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python, true); field->text = BLI_sprintfN(TIP_("Python: %s"), str); } @@ -947,16 +899,18 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, /* button is disabled, we may be able to tell user why */ if ((but->flag & UI_BUT_DISABLED) || extra_icon) { - const char *disabled_msg = NULL; + const char *disabled_msg = nullptr; bool disabled_msg_free = false; /* if operator poll check failed, it can give pretty precise info why */ if (optype) { const wmOperatorCallContext opcontext = extra_icon ? extra_icon->optype_params->opcontext : but->opcontext; + wmOperatorCallParams call_params{}; + call_params.optype = optype; + call_params.opcontext = opcontext; CTX_wm_operator_poll_msg_clear(C); - ui_but_context_poll_operator_ex( - C, but, &(wmOperatorCallParams){.optype = optype, .opcontext = opcontext}); + ui_but_context_poll_operator_ex(C, but, &call_params); disabled_msg = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free); } /* alternatively, buttons can store some reasoning too */ @@ -965,11 +919,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, } if (disabled_msg && disabled_msg[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_ALERT, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Alert); field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg); } if (disabled_msg_free) { @@ -979,12 +930,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, if ((U.flag & USER_TOOLTIPS_PYTHON) && !optype && rna_struct.strinfo) { { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python, true); if (rna_prop.strinfo) { /* Struct and prop */ field->text = BLI_sprintfN(TIP_("Python: %s.%s"), rna_struct.strinfo, rna_prop.strinfo); @@ -996,11 +943,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, } if (but->rnapoin.owner_id) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Mono, uiTooltipFormat::ColorID::Python); /* this could get its own 'BUT_GET_...' type */ @@ -1044,73 +988,66 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) { - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); /* TODO(campbell): a way for gizmos to have their own descriptions (low priority). */ /* Operator Actions */ { const bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part; - const struct { + struct GizmoOpActions { int part; const char *prefix; - } gzop_actions[] = { + }; + GizmoOpActions gzop_actions[] = { { - .part = gz->highlight_part, - .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : NULL, + gz->highlight_part, + use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : nullptr, }, { - .part = use_drag ? gz->drag_part : -1, - .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : NULL, + use_drag ? gz->drag_part : -1, + use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : nullptr, }, }; for (int i = 0; i < ARRAY_SIZE(gzop_actions); i++) { wmGizmoOpElem *gzop = (gzop_actions[i].part != -1) ? WM_gizmo_operator_get(gz, gzop_actions[i].part) : - NULL; - if (gzop != NULL) { + nullptr; + if (gzop != nullptr) { /* Description */ char *info = WM_operatortype_description_or_name(C, gzop->type, &gzop->ptr); - if (info != NULL) { + if (info != nullptr) { char *text = info; - if (gzop_actions[i].prefix != NULL) { + if (gzop_actions[i].prefix != nullptr) { text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info); MEM_freeN(info); } - if (text != NULL) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + if (text != nullptr) { + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Value, true); field->text = text; } } /* Shortcut */ { - IDProperty *prop = gzop->ptr.data; + IDProperty *prop = static_cast<IDProperty *>(gzop->ptr.data); char buf[128]; if (WM_key_event_operator_string( C, gzop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, buf, ARRAY_SIZE(buf))) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_sprintfN(TIP_("Shortcut: %s"), buf); } } @@ -1124,15 +1061,11 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) for (int i = 0; i < gz->type->target_property_defs_len; i++) { /* TODO(campbell): function callback descriptions. */ wmGizmoProperty *gz_prop = &gz_prop_array[i]; - if (gz_prop->prop != NULL) { + if (gz_prop->prop != nullptr) { const char *info = RNA_property_ui_description(gz_prop->prop); if (info && info[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_strdup(info); } } @@ -1141,7 +1074,7 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } @@ -1193,18 +1126,19 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, int i, fonth, fontw; for (i = 0, fontw = 0, fonth = 0; i < data->fields_len; i++) { uiTooltipField *field = &data->fields[i]; - uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; + uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : nullptr; struct ResultBLF info; int w, x_pos = 0; int font_id; - if (field->format.style == UI_TIP_STYLE_MONO) { + if (field->format.style == uiTooltipFormat::Style::Mono) { BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi); font_id = blf_mono_font; } else { - BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER)); + BLI_assert(ELEM( + field->format.style, uiTooltipFormat::Style::Normal, uiTooltipFormat::Style::Header)); font_id = data->fstyle.uifont_id; } w = BLF_width_ex(font_id, field->text, UI_TIP_STR_MAX, &info); @@ -1254,20 +1188,18 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, { /* Ensure at least 5 px above screen bounds * UI_UNIT_Y is just a guess to be above the menu item */ - if (init_rect_overlap != NULL) { + if (init_rect_overlap != nullptr) { const int pad = max_ff(1.0f, U.pixelsize) * 5; - const rcti init_rect = { - .xmin = init_rect_overlap->xmin - pad, - .xmax = init_rect_overlap->xmax + pad, - .ymin = init_rect_overlap->ymin - pad, - .ymax = init_rect_overlap->ymax + pad, - }; - const rcti rect_clamp = { - .xmin = 0, - .xmax = winx, - .ymin = 0, - .ymax = winy, - }; + rcti init_rect; + init_rect.xmin = init_rect_overlap->xmin - pad; + init_rect.xmax = init_rect_overlap->xmax + pad; + init_rect.ymin = init_rect_overlap->ymin - pad; + init_rect.ymax = init_rect_overlap->ymax + pad; + rcti rect_clamp; + rect_clamp.xmin = 0; + rect_clamp.xmax = winx; + rect_clamp.ymin = 0; + rect_clamp.ymax = winy; /* try right. */ const int size_x = BLI_rcti_size_x(&rect_i); const int size_y = BLI_rcti_size_y(&rect_i); @@ -1347,12 +1279,11 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, } else { const int pad = max_ff(1.0f, U.pixelsize) * 5; - const rcti rect_clamp = { - .xmin = pad, - .xmax = winx - pad, - .ymin = pad + (UI_UNIT_Y * 2), - .ymax = winy - pad, - }; + rcti rect_clamp; + rect_clamp.xmin = pad; + rect_clamp.xmax = winx - pad; + rect_clamp.ymin = pad + (UI_UNIT_Y * 2); + rect_clamp.ymax = winy - pad; int offset_dummy[2]; BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy); } @@ -1367,7 +1298,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, { /* Compensate for margin offset, visually this corrects the position. */ const int margin = UI_POPUP_MARGIN; - if (init_rect_overlap != NULL) { + if (init_rect_overlap != nullptr) { BLI_rcti_translate(&rect_i, margin, margin / 2); } @@ -1407,24 +1338,24 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon( float init_position[2]; if (but->drawflag & UI_BUT_NO_TOOLTIP) { - return NULL; + return nullptr; } - uiTooltipData *data = NULL; + uiTooltipData *data = nullptr; - if (data == NULL) { + if (data == nullptr) { data = ui_tooltip_data_from_tool(C, but, is_label); } - if (data == NULL) { + if (data == nullptr) { data = ui_tooltip_data_from_button_or_extra_icon(C, but, extra_icon); } - if (data == NULL) { - data = ui_tooltip_data_from_button_or_extra_icon(C, but, NULL); + if (data == nullptr) { + data = ui_tooltip_data_from_button_or_extra_icon(C, but, nullptr); } - if (data == NULL) { - return NULL; + if (data == nullptr) { + return nullptr; } const bool is_no_overlap = UI_but_has_tooltip_label(but) || UI_but_is_tool(but); @@ -1453,25 +1384,26 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon( } ARegion *region = ui_tooltip_create_with_data( - C, data, init_position, is_no_overlap ? &init_rect : NULL, aspect); + C, data, init_position, is_no_overlap ? &init_rect : nullptr, aspect); return region; } ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label) { - return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label); + return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, nullptr, is_label); } ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) { wmWindow *win = CTX_wm_window(C); const float aspect = 1.0f; - float init_position[2] = {win->eventstate->xy[0], win->eventstate->xy[1]}; + float init_position[2] = {static_cast<float>(win->eventstate->xy[0]), + static_cast<float>(win->eventstate->xy[1])}; uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz); - if (data == NULL) { - return NULL; + if (data == nullptr) { + return nullptr; } /* TODO(harley): @@ -1486,46 +1418,34 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) } } - return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); + return ui_tooltip_create_with_data(C, data, init_position, nullptr, aspect); } static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data( const uiSearchItemTooltipData *item_tooltip_data) { - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + uiTooltipData *data = MEM_cnew<uiTooltipData>(__func__); if (item_tooltip_data->description[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_NORMAL, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Header, uiTooltipFormat::ColorID::Normal, true); field->text = BLI_strdup(item_tooltip_data->description); } if (item_tooltip_data->name && item_tooltip_data->name[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Value, true); field->text = BLI_strdup(item_tooltip_data->name); } if (item_tooltip_data->hint[0]) { - uiTooltipField *field = text_field_add(data, - &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - .is_pad = true, - }); + uiTooltipField *field = text_field_add( + data, uiTooltipFormat::Style::Normal, uiTooltipFormat::ColorID::Normal, true); field->text = BLI_strdup(item_tooltip_data->hint); } if (data->fields_len == 0) { MEM_freeN(data); - return NULL; + return nullptr; } return data; } @@ -1537,8 +1457,8 @@ ARegion *UI_tooltip_create_from_search_item_generic( const uiSearchItemTooltipData *item_tooltip_data) { uiTooltipData *data = ui_tooltip_data_from_search_item_tooltip_data(item_tooltip_data); - if (data == NULL) { - return NULL; + if (data == nullptr) { + return nullptr; } const float aspect = 1.0f; @@ -1547,7 +1467,7 @@ ARegion *UI_tooltip_create_from_search_item_generic( init_position[0] = win->eventstate->xy[0]; init_position[1] = item_rect->ymin + searchbox_region->winrct.ymin - (UI_POPUP_MARGIN / 2); - return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); + return ui_tooltip_create_with_data(C, data, init_position, nullptr, aspect); } void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region) diff --git a/source/blender/editors/interface/interface_regions.cc b/source/blender/editors/interface/interface_regions.cc index 1a2c1f7919c..1770805cf59 100644 --- a/source/blender/editors/interface/interface_regions.cc +++ b/source/blender/editors/interface/interface_regions.cc @@ -21,7 +21,7 @@ #include "ED_screen.h" -#include "interface_regions_intern.h" +#include "interface_regions_intern.hh" ARegion *ui_region_temp_add(bScreen *screen) { diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.hh index 2ed2cb3d68b..6287a031f5c 100644 --- a/source/blender/editors/interface/interface_regions_intern.h +++ b/source/blender/editors/interface/interface_regions_intern.hh @@ -3,23 +3,16 @@ /** \file * \ingroup edinterface * - * Share between interface_region_*.c files. + * Share between interface_region_*.cc files. */ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - -/* interface_region_menu_popup.c */ +/* interface_region_menu_popup.cc */ uint ui_popup_menu_hash(const char *str); -/* interface_regions_intern.h */ +/* interface_regions.cc */ + ARegion *ui_region_temp_add(bScreen *screen); void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index 8588c7cabc0..3147deb5ad1 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -66,7 +66,7 @@ static void asset_view_item_but_drag_set(uiBut *but, } static void asset_view_draw_item(uiList *ui_list, - bContext *UNUSED(C), + const bContext *UNUSED(C), uiLayout *layout, PointerRNA *UNUSED(dataptr), PointerRNA *itemptr, @@ -183,7 +183,7 @@ static void asset_view_template_refresh_asset_collection( } void uiTemplateAssetView(uiLayout *layout, - bContext *C, + const bContext *C, const char *list_id, PointerRNA *asset_library_dataptr, const char *asset_library_propname, diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index e0b6bbb34c4..f0c91588f98 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -83,7 +83,7 @@ struct TemplateListVisualInfo { }; static void uilist_draw_item_default(struct uiList *ui_list, - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct uiLayout *layout, struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, @@ -114,7 +114,7 @@ static void uilist_draw_item_default(struct uiList *ui_list, } static void uilist_draw_filter_default(struct uiList *ui_list, - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct uiLayout *layout) { PointerRNA listptr; @@ -160,7 +160,7 @@ static int cmpstringp(const void *p1, const void *p2) } static void uilist_filter_items_default(struct uiList *ui_list, - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct PointerRNA *dataptr, const char *propname) { @@ -434,7 +434,7 @@ static void ui_template_list_collect_items(PointerRNA *list_ptr, /** * Create the UI-list representation of the list items, sorted and filtered if needed. */ -static void ui_template_list_collect_display_items(bContext *C, +static void ui_template_list_collect_display_items(const bContext *C, uiList *ui_list, TemplateListInputData *input_data, const uiListFilterItemsFunc filter_items_fn, @@ -601,7 +601,7 @@ static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const cha /** * \note that \a layout_type may be null. */ -static uiList *ui_list_ensure(bContext *C, +static uiList *ui_list_ensure(const bContext *C, uiListType *ui_list_type, const char *list_id, int layout_type, @@ -656,7 +656,7 @@ static uiList *ui_list_ensure(bContext *C, return ui_list; } -static void ui_template_list_layout_draw(bContext *C, +static void ui_template_list_layout_draw(const bContext *C, uiList *ui_list, uiLayout *layout, TemplateListInputData *input_data, @@ -1156,7 +1156,7 @@ static void ui_template_list_layout_draw(bContext *C, } uiList *uiTemplateList_ex(uiLayout *layout, - bContext *C, + const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, @@ -1227,7 +1227,7 @@ uiList *uiTemplateList_ex(uiLayout *layout, } void uiTemplateList(uiLayout *layout, - bContext *C, + const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.cc index 41de2ab197d..0d0a5f01744 100644 --- a/source/blender/editors/interface/interface_template_search_operator.c +++ b/source/blender/editors/interface/interface_template_search_operator.cc @@ -7,14 +7,15 @@ * accessed via the #WM_OT_search_operator operator. */ -#include <string.h> +#include <cstring> #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_ghash.h" +#include "BLI_math_vec_types.hh" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -35,10 +36,10 @@ static void operator_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) { - wmOperatorType *ot = arg2; + wmOperatorType *ot = static_cast<wmOperatorType *>(arg2); if (ot) { - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, nullptr, nullptr); } } @@ -53,19 +54,20 @@ static void operator_search_update_fn(const bContext *C, /* Prepare BLI_string_all_words_matched. */ const size_t str_len = strlen(str); const int words_max = BLI_string_max_possible_word_count(str_len); - int(*words)[2] = BLI_array_alloca(words, words_max); - const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max); + blender::Array<blender::int2> words(words_max); + const int words_len = BLI_string_find_split_words( + str, str_len, ' ', (int(*)[2])words.data(), words_max); for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + wmOperatorType *ot = static_cast<wmOperatorType *>(BLI_ghashIterator_getValue(&iter)); const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { continue; } - if (BLI_string_all_words_matched(ot_ui_name, str, words, words_len)) { + if (BLI_string_all_words_matched(ot_ui_name, str, (int(*)[2])words.data(), words_len)) { if (WM_operator_poll((bContext *)C, ot)) { char name[256]; const int len = strlen(ot_ui_name); @@ -78,7 +80,7 @@ static void operator_search_update_fn(const bContext *C, if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, - NULL, + nullptr, true, &name[len + 1], sizeof(name) - len - 1)) { @@ -105,11 +107,11 @@ void UI_but_func_operator_search(uiBut *but) UI_but_func_search_set(but, ui_searchbox_create_operator, operator_search_update_fn, - NULL, + nullptr, false, - NULL, + nullptr, operator_search_exec_fn, - NULL); + nullptr); } void uiTemplateOperatorSearch(uiLayout *layout) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 14da5a7cd62..a9de095a2a8 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6674,7 +6674,7 @@ void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr) } static void cache_file_layer_item(uiList *UNUSED(ui_list), - bContext *UNUSED(C), + const bContext *UNUSED(C), uiLayout *layout, PointerRNA *UNUSED(dataptr), PointerRNA *itemptr, diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.cc index e998eb6dbed..ec54b695cf7 100644 --- a/source/blender/editors/interface/interface_undo.c +++ b/source/blender/editors/interface/interface_undo.cc @@ -7,7 +7,7 @@ * Undo stack to use for UI widgets that manage their own editing state. */ -#include <string.h> +#include <cstring> #include "BLI_listbase.h" @@ -21,39 +21,39 @@ /** \name Text Field Undo Stack * \{ */ -typedef struct uiUndoStack_Text_State { +struct uiUndoStack_Text_State { struct uiUndoStack_Text_State *next, *prev; int cursor_index; char text[0]; -} uiUndoStack_Text_State; +}; -typedef struct uiUndoStack_Text { +struct uiUndoStack_Text { ListBase states; uiUndoStack_Text_State *current; -} uiUndoStack_Text; +}; static const char *ui_textedit_undo_impl(uiUndoStack_Text *stack, int *r_cursor_index) { /* Don't undo if no data has been pushed yet. */ - if (stack->current == NULL) { - return NULL; + if (stack->current == nullptr) { + return nullptr; } /* Travel backwards in the stack and copy information to the caller. */ - if (stack->current->prev != NULL) { + if (stack->current->prev != nullptr) { stack->current = stack->current->prev; *r_cursor_index = stack->current->cursor_index; return stack->current->text; } - return NULL; + return nullptr; } static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_index) { /* Don't redo if no data has been pushed yet. */ - if (stack->current == NULL) { - return NULL; + if (stack->current == nullptr) { + return nullptr; } /* Only redo if new data has not been entered since the last undo. */ @@ -63,7 +63,7 @@ static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_ *r_cursor_index = stack->current->cursor_index; return stack->current->text; } - return NULL; + return nullptr; } const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_cursor_index) @@ -78,7 +78,7 @@ const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_curs void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index) { /* Clear all redo actions from the current state. */ - if (stack->current != NULL) { + if (stack->current != nullptr) { while (stack->current->next) { uiUndoStack_Text_State *state = stack->current->next; BLI_remlink(&stack->states, state); @@ -88,7 +88,8 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor /* Create the new state. */ const int text_size = strlen(text) + 1; - stack->current = MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__); + stack->current = static_cast<uiUndoStack_Text_State *>( + MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__)); stack->current->cursor_index = cursor_index; memcpy(stack->current->text, text, text_size); BLI_addtail(&stack->states, stack->current); @@ -96,8 +97,8 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor uiUndoStack_Text *ui_textedit_undo_stack_create(void) { - uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__); - stack->current = NULL; + uiUndoStack_Text *stack = MEM_new<uiUndoStack_Text>(__func__); + stack->current = nullptr; BLI_listbase_clear(&stack->states); return stack; diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index b69cd8b8606..3608e162727 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -556,7 +556,7 @@ void paintvert_hide(bContext *C, Object *ob, const bool unselected) { Mesh *const me = BKE_mesh_from_object(ob); - if (me == NULL || me->totvert == 0) { + if (me == nullptr || me->totvert == 0) { return; } @@ -584,7 +584,7 @@ void paintvert_reveal(bContext *C, Object *ob, const bool select) { Mesh *const me = BKE_mesh_from_object(ob); - if (me == NULL || me->totvert == 0) { + if (me == nullptr || me->totvert == 0) { return; } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index bf3b71178e8..abf286afa0c 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -50,6 +50,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "ED_keyframing.h" diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index 97bbcaa102f..cd0a05f02bc 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -1771,7 +1771,7 @@ PreviewLoadJob &PreviewLoadJob::ensure_job(wmWindowManager *wm, wmWindow *win) WM_jobs_start(wm, wm_job); } - return *reinterpret_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job)); + return *static_cast<PreviewLoadJob *>(WM_jobs_customdata_get(wm_job)); } void PreviewLoadJob::load_jobless(PreviewImage *preview, const eIconSizes icon_size) @@ -1807,11 +1807,11 @@ void PreviewLoadJob::run_fn(void *customdata, short *do_update, float *UNUSED(progress)) { - PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata); + PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata); IMB_thumb_locks_acquire(); - while (RequestedPreview *request = reinterpret_cast<RequestedPreview *>( + while (RequestedPreview *request = static_cast<RequestedPreview *>( BLI_thread_queue_pop_timeout(job_data->todo_queue_, 100))) { if (*stop) { break; @@ -1864,7 +1864,7 @@ void PreviewLoadJob::finish_request(RequestedPreview &request) void PreviewLoadJob::update_fn(void *customdata) { - PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata); + PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata); for (auto request_it = job_data->requested_previews_.begin(); request_it != job_data->requested_previews_.end();) { @@ -1884,7 +1884,7 @@ void PreviewLoadJob::update_fn(void *customdata) void PreviewLoadJob::end_fn(void *customdata) { - PreviewLoadJob *job_data = reinterpret_cast<PreviewLoadJob *>(customdata); + PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata); /* Finish any possibly remaining queued previews. */ for (RequestedPreview &request : job_data->requested_previews_) { @@ -1895,7 +1895,7 @@ void PreviewLoadJob::end_fn(void *customdata) void PreviewLoadJob::free_fn(void *customdata) { - MEM_delete(reinterpret_cast<PreviewLoadJob *>(customdata)); + MEM_delete(static_cast<PreviewLoadJob *>(customdata)); } static void icon_preview_free(void *customdata) diff --git a/source/blender/editors/render/render_update.cc b/source/blender/editors/render/render_update.cc index 3d26e764211..7cefcf9815e 100644 --- a/source/blender/editors/render/render_update.cc +++ b/source/blender/editors/render/render_update.cc @@ -95,20 +95,20 @@ void ED_render_view3d_update(Depsgraph *depsgraph, CTX_free(C); } - else { - RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); - if (updated) { - DRWUpdateContext drw_context = {nullptr}; - drw_context.bmain = bmain; - drw_context.depsgraph = depsgraph; - drw_context.scene = scene; - drw_context.view_layer = view_layer; - drw_context.region = region; - drw_context.v3d = v3d; - drw_context.engine_type = engine_type; - DRW_notify_view_update(&drw_context); - } + + if (!updated) { + continue; } + + DRWUpdateContext drw_context = {nullptr}; + drw_context.bmain = bmain; + drw_context.depsgraph = depsgraph; + drw_context.scene = scene; + drw_context.view_layer = view_layer; + drw_context.region = region; + drw_context.v3d = v3d; + drw_context.engine_type = ED_view3d_engine_type(scene, v3d->shading.type); + DRW_notify_view_update(&drw_context); } } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 0d6b6ee1d78..83e6c837eac 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -1032,15 +1032,13 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C, CTX_data_id_pointer_set(result, (ID *)action); break; } - else { - if (editable && ID_IS_LINKED(action)) { - continue; - } + if (editable && ID_IS_LINKED(action)) { + continue; + } - /* Add the action to the output list if not already added. */ - if (BLI_gset_add(seen_set, action)) { - CTX_data_id_list_add(result, &action->id); - } + /* Add the action to the output list if not already added. */ + if (BLI_gset_add(seen_set, action)) { + CTX_data_id_list_add(result, &action->id); } } } diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c index 9d66debda6f..01c208bf48d 100644 --- a/source/blender/editors/screen/screen_user_menu.c +++ b/source/blender/editors/screen/screen_user_menu.c @@ -34,6 +34,7 @@ #include "UI_resources.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index c5ebcf870a3..577540725af 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1145,11 +1145,10 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, } GPU_line_width(1.0f); - if (ss->preview_vert_index_count > 0) { - immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count); - for (int i = 0; i < ss->preview_vert_index_count; i++) { - immVertex3fv(gpuattr, - SCULPT_vertex_co_for_grab_active_get(ss, ss->preview_vert_index_list[i])); + if (ss->preview_vert_count > 0) { + immBegin(GPU_PRIM_LINES, ss->preview_vert_count); + for (int i = 0; i < ss->preview_vert_count; i++) { + immVertex3fv(gpuattr, SCULPT_vertex_co_for_grab_active_get(ss, ss->preview_vert_list[i])); } immEnd(); } @@ -1209,7 +1208,7 @@ typedef struct PaintCursorContext { /* Sculpt related data. */ Sculpt *sd; SculptSession *ss; - int prev_active_vertex_index; + PBVHVertRef prev_active_vertex; bool is_stroke_active; bool is_cursor_over_mesh; bool is_multires; @@ -1366,7 +1365,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon /* This updates the active vertex, which is needed for most of the Sculpt/Vertex Colors tools to * work correctly */ - pcontext->prev_active_vertex_index = ss->active_vertex_index; + pcontext->prev_active_vertex = ss->active_vertex; if (!ups->stroke_active) { pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update( C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)); @@ -1549,7 +1548,7 @@ static void paint_cursor_preview_boundary_data_update(PaintCursorContext *pconte } ss->boundary_preview = SCULPT_boundary_data_init( - pcontext->vc.obact, pcontext->brush, ss->active_vertex_index, pcontext->radius); + pcontext->vc.obact, pcontext->brush, ss->active_vertex, pcontext->radius); } static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *pcontext) @@ -1575,8 +1574,8 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * paint_cursor_update_object_space_radius(pcontext); - const bool update_previews = pcontext->prev_active_vertex_index != - SCULPT_active_vertex_get(pcontext->ss); + const bool update_previews = pcontext->prev_active_vertex.i != + SCULPT_active_vertex_get(pcontext->ss).i; /* Setup drawing. */ wmViewport(&pcontext->region->winrct); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 9449cc6eb8d..3e5ad9bdc2d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1223,12 +1223,12 @@ static VertSeam *find_adjacent_seam(const ProjPaintState *ps, /* Circulate through the (sorted) vert seam array, in the direction of the seam normal, * until we find the first opposing seam, matching in UV space. */ if (seam->normal_cw) { - LISTBASE_CIRCULAR_BACKWARD_BEGIN (vert_seams, adjacent, seam) { + LISTBASE_CIRCULAR_BACKWARD_BEGIN (VertSeam *, vert_seams, adjacent, seam) { if ((adjacent->normal_cw != seam->normal_cw) && cmp_uv(adjacent->uv, seam->uv)) { break; } } - LISTBASE_CIRCULAR_BACKWARD_END(vert_seams, adjacent, seam); + LISTBASE_CIRCULAR_BACKWARD_END(VertSeam *, vert_seams, adjacent, seam); } else { LISTBASE_CIRCULAR_FORWARD_BEGIN (vert_seams, adjacent, seam) { diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 89bbf2a3c92..a5389f7fd83 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -663,7 +663,7 @@ static bool sculpt_gesture_is_effected_lasso(SculptGestureContext *sgcontext, co static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, PBVHVertexIter *vd) { float vertex_normal[3]; - SCULPT_vertex_normal_get(sgcontext->ss, vd->index, vertex_normal); + SCULPT_vertex_normal_get(sgcontext->ss, vd->vertex, vertex_normal); float dot = dot_v3v3(sgcontext->view_normal, vertex_normal); const bool is_effected_front_face = !(sgcontext->front_faces_only && dot < 0.0f); @@ -743,7 +743,7 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { - SCULPT_vertex_face_set_set(sgcontext->ss, vd.index, face_set_operation->new_face_set_id); + SCULPT_vertex_face_set_set(sgcontext->ss, vd.vertex, face_set_operation->new_face_set_id); any_updated = true; } } @@ -1025,7 +1025,9 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext) trim_operation->depth_back = -FLT_MAX; for (int i = 0; i < totvert; i++) { - const float *vco = SCULPT_vertex_co_get(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + const float *vco = SCULPT_vertex_co_get(ss, vertex); /* Convert the coordinates to world space to calculate the depth. When generating the trimming * mesh, coordinates are first calculated in world space, then converted to object space to * store them. */ @@ -1437,7 +1439,7 @@ static void project_line_gesture_apply_task_cb(void *__restrict userdata, } add_v3_v3(vd.co, disp); if (vd.mvert) { - BKE_pbvh_vert_mark_update(sgcontext->ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(sgcontext->ss->pbvh, vd.vertex); } any_updated = true; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 7cb370efb94..2366089cefb 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -122,22 +122,22 @@ int SCULPT_vertex_count_get(SculptSession *ss) return 0; } -const float *SCULPT_vertex_co_get(SculptSession *ss, int index) +const float *SCULPT_vertex_co_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { if (ss->shapekey_active || ss->deform_modifiers_active) { const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); - return mverts[index].co; + return mverts[vertex.i].co; } - return ss->mvert[index].co; + return ss->mvert[vertex.i].co; } case PBVH_BMESH: - return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co; + return ((BMVert *)vertex.i)->co; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index)); } @@ -158,31 +158,33 @@ bool SCULPT_has_colors(const SculptSession *ss) return ss->vcol || ss->mcol; } -void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4]) +void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]) { - BKE_pbvh_vertex_color_get(ss->pbvh, index, r_color); + BKE_pbvh_vertex_color_get(ss->pbvh, vertex, r_color); } -void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4]) +void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]) { - BKE_pbvh_vertex_color_set(ss->pbvh, index, color); + BKE_pbvh_vertex_color_set(ss->pbvh, vertex, color); } -void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) +void SCULPT_vertex_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh); - copy_v3_v3(no, vert_normals[index]); + copy_v3_v3(no, vert_normals[vertex.i]); break; } - case PBVH_BMESH: - copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no); + case PBVH_BMESH: { + BMVert *v = (BMVert *)vertex.i; + copy_v3_v3(no, v->no); break; + } case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index))); break; @@ -190,42 +192,42 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) } } -const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index) +const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, PBVHVertRef vertex) { if (ss->persistent_base) { - return ss->persistent_base[index].co; + return ss->persistent_base[BKE_pbvh_vertex_to_index(ss->pbvh, vertex)].co; } - return SCULPT_vertex_co_get(ss, index); + return SCULPT_vertex_co_get(ss, vertex); } -const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index) +const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, PBVHVertRef vertex) { - /* Always grab active shape key if the sculpt happens on shapekey. */ - if (ss->shapekey_active) { - const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); - return mverts[index].co; - } + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { + /* Always grab active shape key if the sculpt happens on shapekey. */ + if (ss->shapekey_active) { + const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); + return mverts[vertex.i].co; + } - /* Sculpting on the base mesh. */ - if (ss->mvert) { - return ss->mvert[index].co; + /* Sculpting on the base mesh. */ + return ss->mvert[vertex.i].co; } /* Everything else, such as sculpting on multires. */ - return SCULPT_vertex_co_get(ss, index); + return SCULPT_vertex_co_get(ss, vertex); } -void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]) +void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, float r_co[3]) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_BMESH: - copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, vertex)); break; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, @@ -236,30 +238,30 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3] } } -void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]) +void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]) { if (ss->persistent_base) { - copy_v3_v3(no, ss->persistent_base[index].no); + copy_v3_v3(no, ss->persistent_base[vertex.i].no); return; } - SCULPT_vertex_normal_get(ss, index, no); + SCULPT_vertex_normal_get(ss, vertex, no); } -float SCULPT_vertex_mask_get(SculptSession *ss, int index) +float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex) { BMVert *v; float *mask; switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return ss->vmask[index]; + return ss->vmask[vertex.i]; case PBVH_BMESH: - v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index); + v = (BMVert *)vertex.i; mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); return *mask; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index)); } @@ -268,12 +270,13 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index) return 0.0f; } -int SCULPT_active_vertex_get(SculptSession *ss) +PBVHVertRef SCULPT_active_vertex_get(SculptSession *ss) { if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) { - return ss->active_vertex_index; + return ss->active_vertex; } - return 0; + + return BKE_pbvh_make_vref(PBVH_REF_NONE); } const float *SCULPT_active_vertex_co_get(SculptSession *ss) @@ -338,32 +341,34 @@ int SCULPT_active_face_set_get(SculptSession *ss) return SCULPT_FACE_SET_NONE; } -void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible) +void SCULPT_vertex_visible_set(SculptSession *ss, PBVHVertRef vertex, bool visible) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - SET_FLAG_FROM_TEST(ss->mvert[index].flag, !visible, ME_HIDE); - BKE_pbvh_vert_mark_update(ss->pbvh, index); + SET_FLAG_FROM_TEST(ss->mvert[vertex.i].flag, !visible, ME_HIDE); + BKE_pbvh_vert_mark_update(ss->pbvh, vertex); break; - case PBVH_BMESH: - BM_elem_flag_set(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN, !visible); + case PBVH_BMESH: { + BMVert *v = (BMVert *)vertex.i; + BM_elem_flag_set(v, BM_ELEM_HIDDEN, !visible); break; + } case PBVH_GRIDS: break; } } -bool SCULPT_vertex_visible_get(SculptSession *ss, int index) +bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return !(ss->mvert[index].flag & ME_HIDE); + return !(ss->mvert[vertex.i].flag & ME_HIDE); case PBVH_BMESH: - return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN); + return !BM_elem_flag_test((BMVert *)vertex.i, BM_ELEM_HIDDEN); case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; BLI_bitmap **grid_hidden = BKE_pbvh_get_grid_visibility(ss->pbvh); if (grid_hidden && grid_hidden[grid_index]) { return !BLI_BITMAP_TEST(grid_hidden[grid_index], vertex_index); @@ -436,12 +441,12 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible) } } -bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index) +bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int j = 0; j < ss->pmap[index].count; j++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] > 0) { return true; } @@ -456,12 +461,12 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index) return true; } -bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index) +bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int j = 0; j < ss->pmap[index].count; j++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] < 0) { return false; } @@ -472,7 +477,7 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index) return true; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); return ss->face_sets[face_index] > 0; } @@ -480,12 +485,12 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index) return true; } -void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set) +void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int j = 0; j < ss->pmap[index].count; j++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] > 0) { ss->face_sets[vert_map->indices[j]] = abs(face_set); } @@ -495,7 +500,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set) break; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); if (ss->face_sets[face_index] > 0) { ss->face_sets[face_index] = abs(face_set); @@ -505,13 +510,13 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set) } } -int SCULPT_vertex_face_set_get(SculptSession *ss, int index) +int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; + MeshElemMap *vert_map = &ss->pmap[vertex.i]; int face_set = 0; - for (int i = 0; i < ss->pmap[index].count; i++) { + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] > face_set) { face_set = abs(ss->face_sets[vert_map->indices[i]]); } @@ -522,7 +527,7 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index) return 0; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); return ss->face_sets[face_index]; } @@ -530,12 +535,12 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index) return 0; } -bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set) +bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - MeshElemMap *vert_map = &ss->pmap[index]; - for (int i = 0; i < ss->pmap[index].count; i++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] == face_set) { return true; } @@ -546,7 +551,7 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set) return true; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; + const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); return ss->face_sets[face_index] == face_set; } @@ -574,11 +579,11 @@ void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob) } static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss, - int index) + PBVHVertRef vertex) { - MeshElemMap *vert_map = &ss->pmap[index]; - const bool visible = SCULPT_vertex_visible_get(ss, index); - for (int i = 0; i < ss->pmap[index].count; i++) { + MeshElemMap *vert_map = &ss->pmap[vertex.i]; + const bool visible = SCULPT_vertex_visible_get(ss, vertex); + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (visible) { ss->face_sets[vert_map->indices[i]] = abs(ss->face_sets[vert_map->indices[i]]); } @@ -586,7 +591,7 @@ static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSe ss->face_sets[vert_map->indices[i]] = -abs(ss->face_sets[vert_map->indices[i]]); } } - BKE_pbvh_vert_mark_update(ss->pbvh, index); + BKE_pbvh_vert_mark_update(ss->pbvh, vertex); } void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) @@ -597,7 +602,7 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) bool poly_visible = true; for (int l = 0; l < poly->totloop; l++) { MLoop *loop = &ss->mloop[poly->loopstart + l]; - if (!SCULPT_vertex_visible_get(ss, (int)loop->v)) { + if (!SCULPT_vertex_visible_get(ss, BKE_pbvh_make_vref(loop->v))) { poly_visible = false; } } @@ -660,18 +665,18 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss return true; } -bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index) +bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - return sculpt_check_unique_face_set_in_base_mesh(ss, index); + return sculpt_check_unique_face_set_in_base_mesh(ss, vertex.i); } case PBVH_BMESH: return true; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; const SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, .y = vertex_index / key->grid_size}; @@ -715,10 +720,12 @@ int SCULPT_face_set_next_available_get(SculptSession *ss) #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 -static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index) +static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, + PBVHVertRef neighbor, + int neighbor_index) { for (int i = 0; i < iter->size; i++) { - if (iter->neighbors[i] == neighbor_index) { + if (iter->neighbors[i].i == neighbor.i) { return; } } @@ -727,63 +734,74 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neigh iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; if (iter->neighbors == iter->neighbors_fixed) { - iter->neighbors = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array"); - memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(int) * iter->size); + iter->neighbors = MEM_mallocN(iter->capacity * sizeof(PBVHVertRef), "neighbor array"); + memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(PBVHVertRef) * iter->size); } else { iter->neighbors = MEM_reallocN_id( - iter->neighbors, iter->capacity * sizeof(int), "neighbor array"); + iter->neighbors, iter->capacity * sizeof(PBVHVertRef), "neighbor array"); + } + + if (iter->neighbor_indices == iter->neighbor_indices_fixed) { + iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array"); + memcpy(iter->neighbor_indices, iter->neighbor_indices_fixed, sizeof(int) * iter->size); + } + else { + iter->neighbor_indices = MEM_reallocN_id( + iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array"); } } - iter->neighbors[iter->size] = neighbor_index; + iter->neighbors[iter->size] = neighbor; + iter->neighbor_indices[iter->size] = neighbor_index; iter->size++; } -static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss, - int index, - SculptVertexNeighborIter *iter) +static void sculpt_vertex_neighbors_get_bmesh(PBVHVertRef vertex, SculptVertexNeighborIter *iter) { - BMVert *v = BM_vert_at_index(ss->bm, index); + BMVert *v = (BMVert *)vertex.i; BMIter liter; BMLoop *l; iter->size = 0; iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + iter->neighbor_indices = iter->neighbor_indices_fixed; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { const BMVert *adj_v[2] = {l->prev->v, l->next->v}; for (int i = 0; i < ARRAY_SIZE(adj_v); i++) { const BMVert *v_other = adj_v[i]; - if (BM_elem_index_get(v_other) != (int)index) { - sculpt_vertex_neighbor_add(iter, BM_elem_index_get(v_other)); + if (v_other != v) { + sculpt_vertex_neighbor_add( + iter, BKE_pbvh_make_vref((intptr_t)v_other), BM_elem_index_get(v_other)); } } } } static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, - int index, + PBVHVertRef vertex, SculptVertexNeighborIter *iter) { - MeshElemMap *vert_map = &ss->pmap[index]; + MeshElemMap *vert_map = &ss->pmap[vertex.i]; iter->size = 0; iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + iter->neighbor_indices = iter->neighbor_indices_fixed; - for (int i = 0; i < ss->pmap[index].count; i++) { + for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] < 0) { /* Skip connectivity from hidden faces. */ continue; } const MPoly *p = &ss->mpoly[vert_map->indices[i]]; uint f_adj_v[2]; - if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) { + if (poly_get_adj_loops_from_vert(p, ss->mloop, vertex.i, f_adj_v) != -1) { for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) { - if (f_adj_v[j] != index) { - sculpt_vertex_neighbor_add(iter, f_adj_v[j]); + if (f_adj_v[j] != vertex.i) { + sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]); } } } @@ -791,14 +809,17 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, if (ss->fake_neighbors.use_fake_neighbors) { BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); - if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) { - sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]); + if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) { + sculpt_vertex_neighbor_add( + iter, + BKE_pbvh_make_vref(ss->fake_neighbors.fake_neighbor_index[vertex.i]), + ss->fake_neighbors.fake_neighbor_index[vertex.i]); } } } static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, - const int index, + const PBVHVertRef vertex, const bool include_duplicates, SculptVertexNeighborIter *iter) { @@ -806,8 +827,8 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, * maybe provide coordinate and mask pointers directly rather than converting * back and forth between #CCGElem and global index. */ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, @@ -820,17 +841,20 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, iter->num_duplicates = neighbors.num_duplicates; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + iter->neighbor_indices = iter->neighbor_indices_fixed; for (int i = 0; i < neighbors.size; i++) { - sculpt_vertex_neighbor_add(iter, - neighbors.coords[i].grid_index * key->grid_area + - neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x); + int v = neighbors.coords[i].grid_index * key->grid_area + + neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x; + + sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v); } if (ss->fake_neighbors.use_fake_neighbors) { BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); - if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) { - sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]); + if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) { + int v = ss->fake_neighbors.fake_neighbor_index[vertex.i]; + sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v); } } @@ -840,19 +864,19 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, } void SCULPT_vertex_neighbors_get(SculptSession *ss, - const int index, + const PBVHVertRef vertex, const bool include_duplicates, SculptVertexNeighborIter *iter) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - sculpt_vertex_neighbors_get_faces(ss, index, iter); + sculpt_vertex_neighbors_get_faces(ss, vertex, iter); return; case PBVH_BMESH: - sculpt_vertex_neighbors_get_bmesh(ss, index, iter); + sculpt_vertex_neighbors_get_bmesh(vertex, iter); return; case PBVH_GRIDS: - sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter); + sculpt_vertex_neighbors_get_grids(ss, vertex, include_duplicates, iter); return; } } @@ -863,24 +887,24 @@ static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss, c return BLI_BITMAP_TEST(ss->vertex_info.boundary, index); } -bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index) +bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) { + if (!SCULPT_vertex_all_face_sets_visible_get(ss, vertex)) { return true; } - return sculpt_check_boundary_vertex_in_base_mesh(ss, index); + return sculpt_check_boundary_vertex_in_base_mesh(ss, vertex.i); } case PBVH_BMESH: { - BMVert *v = BM_vert_at_index(ss->bm, index); + BMVert *v = (BMVert *)vertex.i; return BM_vert_is_boundary(v); } case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); - const int grid_index = index / key->grid_area; - const int vertex_index = index - grid_index * key->grid_area; + const int grid_index = vertex.i / key->grid_area; + const int vertex_index = vertex.i - grid_index * key->grid_area; const SubdivCCGCoord coord = {.grid_index = grid_index, .x = vertex_index % key->grid_size, .y = vertex_index / key->grid_size}; @@ -941,7 +965,7 @@ bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], } typedef struct NearestVertexTLSData { - int nearest_vertex_index; + PBVHVertRef nearest_vertex; float nearest_vertex_distance_squared; } NearestVertexTLSData; @@ -958,7 +982,7 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata, float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co); if (distance_squared < nvtd->nearest_vertex_distance_squared && distance_squared < data->max_distance_squared) { - nvtd->nearest_vertex_index = vd.index; + nvtd->nearest_vertex = vd.vertex; nvtd->nearest_vertex_distance_squared = distance_squared; } } @@ -971,17 +995,17 @@ static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata), { NearestVertexTLSData *join = chunk_join; NearestVertexTLSData *nvtd = chunk; - if (join->nearest_vertex_index == -1) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + if (join->nearest_vertex.i == PBVH_REF_NONE) { + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } } -int SCULPT_nearest_vertex_get( +PBVHVertRef SCULPT_nearest_vertex_get( Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original) { SculptSession *ss = ob->sculpt; @@ -996,7 +1020,7 @@ int SCULPT_nearest_vertex_get( }; BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); if (totnode == 0) { - return -1; + return BKE_pbvh_make_vref(PBVH_REF_NONE); } SculptThreadedTaskData task_data = { @@ -1008,7 +1032,7 @@ int SCULPT_nearest_vertex_get( copy_v3_v3(task_data.nearest_vertex_search_co, co); NearestVertexTLSData nvtd; - nvtd.nearest_vertex_index = -1; + nvtd.nearest_vertex.i = PBVH_REF_NONE; nvtd.nearest_vertex_distance_squared = FLT_MAX; TaskParallelSettings settings; @@ -1020,7 +1044,7 @@ int SCULPT_nearest_vertex_get( MEM_SAFE_FREE(nodes); - return nvtd.nearest_vertex_index; + return nvtd.nearest_vertex; } bool SCULPT_is_symmetry_iteration_valid(char i, char symm) @@ -1075,23 +1099,27 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood) int vertex_count = SCULPT_vertex_count_get(ss); SCULPT_vertex_random_access_ensure(ss); - flood->queue = BLI_gsqueue_new(sizeof(int)); + flood->queue = BLI_gsqueue_new(sizeof(intptr_t)); flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices"); } -void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index) +void SCULPT_floodfill_add_initial(SculptFloodFill *flood, PBVHVertRef vertex) { - BLI_gsqueue_push(flood->queue, &index); + BLI_gsqueue_push(flood->queue, &vertex); } -void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index) +void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex) { - BLI_gsqueue_push(flood->queue, &index); - BLI_BITMAP_ENABLE(flood->visited_vertices, index); + BLI_gsqueue_push(flood->queue, &vertex); + BLI_BITMAP_ENABLE(flood->visited_vertices, vertex.i); } -void SCULPT_floodfill_add_initial_with_symmetry( - Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, int index, float radius) +void SCULPT_floodfill_add_initial_with_symmetry(Sculpt *sd, + Object *ob, + SculptSession *ss, + SculptFloodFill *flood, + PBVHVertRef vertex, + float radius) { /* Add active vertex and symmetric vertices to the queue. */ const char symm = SCULPT_mesh_symmetry_xyz_get(ob); @@ -1099,18 +1127,19 @@ void SCULPT_floodfill_add_initial_with_symmetry( if (!SCULPT_is_symmetry_iteration_valid(i, symm)) { continue; } - int v = -1; + PBVHVertRef v = {PBVH_REF_NONE}; + if (i == 0) { - v = index; + v = vertex; } else if (radius > 0.0f) { float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius; float location[3]; - flip_v3_v3(location, SCULPT_vertex_co_get(ss, index), i); + flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i); v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false); } - if (v != -1) { + if (v.i != PBVH_REF_NONE) { SCULPT_floodfill_add_initial(flood, v); } } @@ -1125,7 +1154,9 @@ void SCULPT_floodfill_add_active( if (!SCULPT_is_symmetry_iteration_valid(i, symm)) { continue; } - int v = -1; + + PBVHVertRef v = {PBVH_REF_NONE}; + if (i == 0) { v = SCULPT_active_vertex_get(ss); } @@ -1135,26 +1166,31 @@ void SCULPT_floodfill_add_active( v = SCULPT_nearest_vertex_get(sd, ob, location, radius, false); } - if (v != -1) { + if (v.i != PBVH_REF_NONE) { SCULPT_floodfill_add_initial(flood, v); } } } -void SCULPT_floodfill_execute( - SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), - void *userdata) +void SCULPT_floodfill_execute(SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool is_duplicate, + void *userdata), + void *userdata) { while (!BLI_gsqueue_is_empty(flood->queue)) { - int from_v; + PBVHVertRef from_v; + BLI_gsqueue_pop(flood->queue, &from_v); SculptVertexNeighborIter ni; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { - const int to_v = ni.index; + const PBVHVertRef to_v = ni.vertex; + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); - if (BLI_BITMAP_TEST(flood->visited_vertices, to_v)) { + if (BLI_BITMAP_TEST(flood->visited_vertices, to_v_i)) { continue; } @@ -1162,7 +1198,7 @@ void SCULPT_floodfill_execute( continue; } - BLI_BITMAP_ENABLE(flood->visited_vertices, to_v); + BLI_BITMAP_ENABLE(flood->visited_vertices, BKE_pbvh_vertex_to_index(ss->pbvh, to_v)); if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { BLI_gsqueue_push(flood->queue, &to_v); @@ -1413,11 +1449,11 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, *vd.mask = orig_data.mask; } else if (orig_data.unode->type == SCULPT_UNDO_COLOR) { - SCULPT_vertex_color_set(ss, vd.index, orig_data.col); + SCULPT_vertex_color_set(ss, vd.vertex, orig_data.col); } if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2361,12 +2397,12 @@ static float brush_strength(const Sculpt *sd, float SCULPT_brush_strength_factor(SculptSession *ss, const Brush *br, const float brush_point[3], - const float len, + float len, const float vno[3], const float fno[3], - const float mask, - const int vertex_index, - const int thread_id) + float mask, + const PBVHVertRef vertex, + int thread_id) { StrokeCache *cache = ss->cache; const Scene *scene = cache->vc->scene; @@ -2450,7 +2486,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, avg *= 1.0f - mask; /* Auto-masking. */ - avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex_index); + avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex); return avg; } @@ -2819,7 +2855,7 @@ typedef struct { float depth; bool original; - int active_vertex_index; + PBVHVertRef active_vertex; float *face_normal; int active_face_grid_index; @@ -3039,13 +3075,13 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -4744,7 +4780,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) srd->ray_normal, &srd->isect_precalc, &srd->depth, - &srd->active_vertex_index, + &srd->active_vertex, &srd->active_face_grid_index, srd->face_normal)) { srd->hit = true; @@ -4878,7 +4914,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C, } /* Update the active vertex of the SculptSession. */ - ss->active_vertex_index = srd.active_vertex_index; + ss->active_vertex = srd.active_vertex; SCULPT_vertex_random_access_ensure(ss); copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss)); @@ -5661,10 +5697,10 @@ enum { SCULPT_TOPOLOGY_ID_DEFAULT, }; -static int SCULPT_vertex_get_connected_component(SculptSession *ss, int index) +static int SCULPT_vertex_get_connected_component(SculptSession *ss, PBVHVertRef vertex) { if (ss->vertex_info.connected_component) { - return ss->vertex_info.connected_component[index]; + return ss->vertex_info.connected_component[vertex.i]; } return SCULPT_TOPOLOGY_ID_DEFAULT; } @@ -5681,8 +5717,11 @@ static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist) ss->fake_neighbors.current_max_distance = max_dist; } -static void SCULPT_fake_neighbor_add(SculptSession *ss, int v_index_a, int v_index_b) +static void SCULPT_fake_neighbor_add(SculptSession *ss, PBVHVertRef v_a, PBVHVertRef v_b) { + int v_index_a = BKE_pbvh_vertex_to_index(ss->pbvh, v_a); + int v_index_b = BKE_pbvh_vertex_to_index(ss->pbvh, v_b); + if (ss->fake_neighbors.fake_neighbor_index[v_index_a] == FAKE_NEIGHBOR_NONE) { ss->fake_neighbors.fake_neighbor_index[v_index_a] = v_index_b; ss->fake_neighbors.fake_neighbor_index[v_index_b] = v_index_a; @@ -5695,7 +5734,7 @@ static void sculpt_pose_fake_neighbors_free(SculptSession *ss) } typedef struct NearestVertexFakeNeighborTLSData { - int nearest_vertex_index; + PBVHVertRef nearest_vertex; float nearest_vertex_distance_squared; int current_topology_id; } NearestVertexFakeNeighborTLSData; @@ -5710,13 +5749,13 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index); + int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.vertex); if (vd_topology_id != nvtd->current_topology_id && ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) { float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co); if (distance_squared < nvtd->nearest_vertex_distance_squared && distance_squared < data->max_distance_squared) { - nvtd->nearest_vertex_index = vd.index; + nvtd->nearest_vertex = vd.vertex; nvtd->nearest_vertex_distance_squared = distance_squared; } } @@ -5730,17 +5769,20 @@ static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata), { NearestVertexFakeNeighborTLSData *join = chunk_join; NearestVertexFakeNeighborTLSData *nvtd = chunk; - if (join->nearest_vertex_index == -1) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + if (join->nearest_vertex.i == PBVH_REF_NONE) { + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { - join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } } -static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, float max_distance) +static PBVHVertRef SCULPT_fake_neighbor_search(Sculpt *sd, + Object *ob, + const PBVHVertRef vertex, + float max_distance) { SculptSession *ss = ob->sculpt; PBVHNode **nodes = NULL; @@ -5750,12 +5792,12 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, .sd = sd, .radius_squared = max_distance * max_distance, .original = false, - .center = SCULPT_vertex_co_get(ss, index), + .center = SCULPT_vertex_co_get(ss, vertex), }; BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); if (totnode == 0) { - return -1; + return BKE_pbvh_make_vref(PBVH_REF_NONE); } SculptThreadedTaskData task_data = { @@ -5765,12 +5807,12 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, .max_distance_squared = max_distance * max_distance, }; - copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, vertex)); NearestVertexFakeNeighborTLSData nvtd; - nvtd.nearest_vertex_index = -1; + nvtd.nearest_vertex.i = -1; nvtd.nearest_vertex_distance_squared = FLT_MAX; - nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, index); + nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, vertex); TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -5781,19 +5823,26 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, MEM_SAFE_FREE(nodes); - return nvtd.nearest_vertex_index; + return nvtd.nearest_vertex; } typedef struct SculptTopologyIDFloodFillData { int next_id; } SculptTopologyIDFloodFillData; -static bool SCULPT_connected_components_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) +static bool SCULPT_connected_components_floodfill_cb(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool UNUSED(is_duplicate), + void *userdata) { SculptTopologyIDFloodFillData *data = userdata; - ss->vertex_info.connected_component[from_v] = data->next_id; - ss->vertex_info.connected_component[to_v] = data->next_id; + + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + + ss->vertex_info.connected_component[from_v_i] = data->next_id; + ss->vertex_info.connected_component[to_v_i] = data->next_id; return true; } @@ -5817,10 +5866,12 @@ void SCULPT_connected_components_ensure(Object *ob) int next_id = 0; for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (ss->vertex_info.connected_component[i] == SCULPT_TOPOLOGY_ID_NONE) { SculptFloodFill flood; SCULPT_floodfill_init(ss, &flood); - SCULPT_floodfill_add_initial(&flood, i); + SCULPT_floodfill_add_initial(&flood, vertex); SculptTopologyIDFloodFillData data; data.next_id = next_id; SCULPT_floodfill_execute(ss, &flood, SCULPT_connected_components_floodfill_cb, &data); @@ -5878,12 +5929,12 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist) SCULPT_fake_neighbor_init(ss, max_dist); for (int i = 0; i < totvert; i++) { - const int from_v = i; + const PBVHVertRef from_v = BKE_pbvh_index_to_vertex(ss->pbvh, i); /* This vertex does not have a fake neighbor yet, search one for it. */ - if (ss->fake_neighbors.fake_neighbor_index[from_v] == FAKE_NEIGHBOR_NONE) { - const int to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist); - if (to_v != -1) { + if (ss->fake_neighbors.fake_neighbor_index[i] == FAKE_NEIGHBOR_NONE) { + const PBVHVertRef to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist); + if (to_v.i != PBVH_REF_NONE) { /* Add the fake neighbor if available. */ SCULPT_fake_neighbor_add(ss, from_v, to_v); } diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index bb101717c9b..a9fe8cc4b2f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -114,16 +114,21 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush return false; } -float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert) +float SCULPT_automasking_factor_get(AutomaskingCache *automasking, + SculptSession *ss, + PBVHVertRef vert) { if (!automasking) { return 1.0f; } + + int index = BKE_pbvh_vertex_to_index(ss->pbvh, vert); + /* If the cache is initialized with valid info, use the cache. This is used when the * automasking information can't be computed in real time per vertex and needs to be * initialized for the whole mesh when the stroke starts. */ if (automasking->factor) { - return automasking->factor[vert]; + return automasking->factor[index]; } if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) { @@ -178,13 +183,18 @@ struct AutomaskFloodFillData { char symm; }; -static bool automask_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) +static bool automask_floodfill_cb(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool UNUSED(is_duplicate), + void *userdata) { AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); - data->automask_factor[to_v] = 1.0f; - data->automask_factor[from_v] = 1.0f; + data->automask_factor[to_v_i] = 1.0f; + data->automask_factor[from_v_i] = 1.0f; return (!data->use_radius || SCULPT_is_vertex_inside_brush_radius_symm( SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); @@ -243,7 +253,9 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a int tot_vert = SCULPT_vertex_count_get(ss); int active_face_set = SCULPT_active_face_set_get(ss); for (int i : IndexRange(tot_vert)) { - if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) { automask_factor[i] *= 0.0f; } } @@ -269,15 +281,17 @@ float *SCULPT_boundary_automasking_init(Object *ob, int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor"); for (int i : IndexRange(totvert)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + edge_distance[i] = EDGE_DISTANCE_INF; switch (mode) { case AUTOMASK_INIT_BOUNDARY_EDGES: - if (SCULPT_vertex_is_boundary(ss, i)) { + if (SCULPT_vertex_is_boundary(ss, vertex)) { edge_distance[i] = 0; } break; case AUTOMASK_INIT_BOUNDARY_FACE_SETS: - if (!SCULPT_vertex_has_unique_face_set(ss, i)) { + if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) { edge_distance[i] = 0; } break; @@ -286,11 +300,13 @@ float *SCULPT_boundary_automasking_init(Object *ob, for (int propagation_it : IndexRange(propagation_steps)) { for (int i : IndexRange(totvert)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (edge_distance[i] != EDGE_DISTANCE_INF) { continue; } SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { if (edge_distance[ni.index] == propagation_it) { edge_distance[i] = propagation_it + 1; } diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index 44e2dfae480..face0be0500 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -46,32 +46,38 @@ #define BOUNDARY_STEPS_NONE -1 typedef struct BoundaryInitialVertexFloodFillData { - int initial_vertex; + PBVHVertRef initial_vertex; + int initial_vertex_i; int boundary_initial_vertex_steps; - int boundary_initial_vertex; + PBVHVertRef boundary_initial_vertex; + int boundary_initial_vertex_i; int *floodfill_steps; float radius_sq; } BoundaryInitialVertexFloodFillData; static bool boundary_initial_vertex_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { BoundaryInitialVertexFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + if (!SCULPT_vertex_visible_get(ss, to_v)) { return false; } if (!is_duplicate) { - data->floodfill_steps[to_v] = data->floodfill_steps[from_v] + 1; + data->floodfill_steps[to_v_i] = data->floodfill_steps[from_v_i] + 1; } else { - data->floodfill_steps[to_v] = data->floodfill_steps[from_v]; + data->floodfill_steps[to_v_i] = data->floodfill_steps[from_v_i]; } if (SCULPT_vertex_is_boundary(ss, to_v)) { - if (data->floodfill_steps[to_v] < data->boundary_initial_vertex_steps) { - data->boundary_initial_vertex_steps = data->floodfill_steps[to_v]; + if (data->floodfill_steps[to_v_i] < data->boundary_initial_vertex_steps) { + data->boundary_initial_vertex_steps = data->floodfill_steps[to_v_i]; + data->boundary_initial_vertex_i = to_v_i; data->boundary_initial_vertex = to_v; } } @@ -83,9 +89,9 @@ static bool boundary_initial_vertex_floodfill_cb( /* From a vertex index anywhere in the mesh, returns the closest vertex in a mesh boundary inside * the given radius, if it exists. */ -static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, - const int initial_vertex, - const float radius) +static PBVHVertRef sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, + const PBVHVertRef initial_vertex, + const float radius) { if (SCULPT_vertex_is_boundary(ss, initial_vertex)) { @@ -98,7 +104,7 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, BoundaryInitialVertexFloodFillData fdata = { .initial_vertex = initial_vertex, - .boundary_initial_vertex = BOUNDARY_VERTEX_NONE, + .boundary_initial_vertex = {BOUNDARY_VERTEX_NONE}, .boundary_initial_vertex_steps = INT_MAX, .radius_sq = radius * radius, }; @@ -119,12 +125,14 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, static int BOUNDARY_INDICES_BLOCK_SIZE = 300; static void sculpt_boundary_index_add(SculptBoundary *boundary, + const PBVHVertRef new_vertex, const int new_index, const float distance, GSet *included_vertices) { - boundary->vertices[boundary->num_vertices] = new_index; + boundary->vertices[boundary->num_vertices] = new_vertex; + if (boundary->distance) { boundary->distance[new_index] = distance; } @@ -135,11 +143,13 @@ static void sculpt_boundary_index_add(SculptBoundary *boundary, if (boundary->num_vertices >= boundary->vertices_capacity) { boundary->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE; boundary->vertices = MEM_reallocN_id( - boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices"); + boundary->vertices, boundary->vertices_capacity * sizeof(PBVHVertRef), "boundary indices"); } }; -static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2) +static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, + const PBVHVertRef v1, + const PBVHVertRef v2) { boundary->edges[boundary->num_edges].v1 = v1; @@ -159,7 +169,7 @@ static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int * as well as to check if the initial vertex is valid. */ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss, - const int initial_vertex) + const PBVHVertRef initial_vertex) { if (!SCULPT_vertex_visible_get(ss, initial_vertex)) { @@ -170,9 +180,9 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss, int boundary_vertex_count = 0; SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, initial_vertex, ni) { - if (SCULPT_vertex_visible_get(ss, ni.index)) { + if (SCULPT_vertex_visible_get(ss, ni.vertex)) { neighbor_count++; - if (SCULPT_vertex_is_boundary(ss, ni.index)) { + if (SCULPT_vertex_is_boundary(ss, ni.vertex)) { boundary_vertex_count++; } } @@ -202,13 +212,16 @@ typedef struct BoundaryFloodFillData { GSet *included_vertices; EdgeSet *preview_edges; - int last_visited_vertex; + PBVHVertRef last_visited_vertex; } BoundaryFloodFillData; static bool boundary_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + BoundaryFloodFillData *data = userdata; SculptBoundary *boundary = data->boundary; if (!SCULPT_vertex_is_boundary(ss, to_v)) { @@ -217,9 +230,10 @@ static bool boundary_floodfill_cb( const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v), SCULPT_vertex_co_get(ss, to_v)); const float distance_boundary_to_dst = boundary->distance ? - boundary->distance[from_v] + edge_len : + boundary->distance[from_v_i] + edge_len : 0.0f; - sculpt_boundary_index_add(boundary, to_v, distance_boundary_to_dst, data->included_vertices); + sculpt_boundary_index_add( + boundary, to_v, to_v_i, distance_boundary_to_dst, data->included_vertices); if (!is_duplicate) { sculpt_boundary_preview_edge_add(boundary, from_v, to_v); } @@ -229,12 +243,13 @@ static bool boundary_floodfill_cb( static void sculpt_boundary_indices_init(SculptSession *ss, SculptBoundary *boundary, const bool init_boundary_distances, - const int initial_boundary_index) + const PBVHVertRef initial_boundary_vertex) { const int totvert = SCULPT_vertex_count_get(ss); boundary->vertices = MEM_malloc_arrayN( - BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices"); + BOUNDARY_INDICES_BLOCK_SIZE, sizeof(PBVHVertRef), "boundary indices"); + if (init_boundary_distances) { boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances"); } @@ -245,16 +260,21 @@ static void sculpt_boundary_indices_init(SculptSession *ss, SculptFloodFill flood; SCULPT_floodfill_init(ss, &flood); - boundary->initial_vertex = initial_boundary_index; + int initial_boundary_index = BKE_pbvh_vertex_to_index(ss->pbvh, initial_boundary_vertex); + + boundary->initial_vertex = initial_boundary_vertex; + boundary->initial_vertex_i = initial_boundary_index; + copy_v3_v3(boundary->initial_vertex_position, SCULPT_vertex_co_get(ss, boundary->initial_vertex)); - sculpt_boundary_index_add(boundary, initial_boundary_index, 0.0f, included_vertices); - SCULPT_floodfill_add_initial(&flood, initial_boundary_index); + sculpt_boundary_index_add( + boundary, initial_boundary_vertex, initial_boundary_index, 0.0f, included_vertices); + SCULPT_floodfill_add_initial(&flood, boundary->initial_vertex); BoundaryFloodFillData fdata = { .boundary = boundary, .included_vertices = included_vertices, - .last_visited_vertex = BOUNDARY_VERTEX_NONE, + .last_visited_vertex = {BOUNDARY_VERTEX_NONE}, }; @@ -262,13 +282,13 @@ static void sculpt_boundary_indices_init(SculptSession *ss, SCULPT_floodfill_free(&flood); /* Check if the boundary loops into itself and add the extra preview edge to close the loop. */ - if (fdata.last_visited_vertex != BOUNDARY_VERTEX_NONE && + if (fdata.last_visited_vertex.i != BOUNDARY_VERTEX_NONE && sculpt_boundary_is_vertex_in_editable_boundary(ss, fdata.last_visited_vertex)) { SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, fdata.last_visited_vertex, ni) { if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.index)) && - sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.index)) { - sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.index); + sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.vertex)) { + sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.vertex); boundary->forms_loop = true; } } @@ -286,7 +306,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss, */ static void sculpt_boundary_edit_data_init(SculptSession *ss, SculptBoundary *boundary, - const int initial_vertex, + const PBVHVertRef initial_vertex, const float radius) { const int totvert = SCULPT_vertex_count_get(ss); @@ -297,19 +317,22 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, totvert, sizeof(SculptBoundaryEditInfo), "Boundary edit info"); for (int i = 0; i < totvert; i++) { - boundary->edit_info[i].original_vertex = BOUNDARY_VERTEX_NONE; + boundary->edit_info[i].original_vertex_i = BOUNDARY_VERTEX_NONE; boundary->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE; } - GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int)); - GSQueue *next_iteration = BLI_gsqueue_new(sizeof(int)); + GSQueue *current_iteration = BLI_gsqueue_new(sizeof(PBVHVertRef)); + GSQueue *next_iteration = BLI_gsqueue_new(sizeof(PBVHVertRef)); /* Initialized the first iteration with the vertices already in the boundary. This is propagation * step 0. */ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); for (int i = 0; i < boundary->num_vertices; i++) { - boundary->edit_info[boundary->vertices[i]].original_vertex = boundary->vertices[i]; - boundary->edit_info[boundary->vertices[i]].num_propagation_steps = 0; + int index = BKE_pbvh_vertex_to_index(ss->pbvh, boundary->vertices[i]); + + boundary->edit_info[index].original_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, + boundary->vertices[i]); + boundary->edit_info[index].num_propagation_steps = 0; /* This ensures that all duplicate vertices in the boundary have the same original_vertex * index, so the deformation for them will be the same. */ @@ -317,7 +340,8 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, SculptVertexNeighborIter ni_duplis; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->vertices[i], ni_duplis) { if (ni_duplis.is_duplicate) { - boundary->edit_info[ni_duplis.index].original_vertex = boundary->vertices[i]; + boundary->edit_info[ni_duplis.index].original_vertex_i = BKE_pbvh_vertex_to_index( + ss->pbvh, boundary->vertices[i]); } } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis); @@ -338,31 +362,33 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, } while (!BLI_gsqueue_is_empty(current_iteration)) { - int from_v; + PBVHVertRef from_v; BLI_gsqueue_pop(current_iteration, &from_v); + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + SculptVertexNeighborIter ni; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { - const bool is_visible = SCULPT_vertex_visible_get(ss, ni.index); + const bool is_visible = SCULPT_vertex_visible_get(ss, ni.vertex); if (!is_visible || boundary->edit_info[ni.index].num_propagation_steps != BOUNDARY_STEPS_NONE) { continue; } - boundary->edit_info[ni.index].original_vertex = - boundary->edit_info[from_v].original_vertex; + boundary->edit_info[ni.index].original_vertex_i = + boundary->edit_info[from_v_i].original_vertex_i; BLI_BITMAP_ENABLE(visited_vertices, ni.index); if (ni.is_duplicate) { /* Grids duplicates handling. */ boundary->edit_info[ni.index].num_propagation_steps = - boundary->edit_info[from_v].num_propagation_steps; + boundary->edit_info[from_v_i].num_propagation_steps; } else { boundary->edit_info[ni.index].num_propagation_steps = - boundary->edit_info[from_v].num_propagation_steps + 1; + boundary->edit_info[from_v_i].num_propagation_steps + 1; - BLI_gsqueue_push(next_iteration, &ni.index); + BLI_gsqueue_push(next_iteration, &ni.vertex); /* When copying the data to the neighbor for the next iteration, it has to be copied to * all its duplicates too. This is because it is not possible to know if the updated @@ -370,12 +396,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, * copy the data in the from_v neighbor iterator. */ if (has_duplicates) { SculptVertexNeighborIter ni_duplis; - SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.index, ni_duplis) { + SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.vertex, ni_duplis) { if (ni_duplis.is_duplicate) { - boundary->edit_info[ni_duplis.index].original_vertex = - boundary->edit_info[from_v].original_vertex; + boundary->edit_info[ni_duplis.index].original_vertex_i = + boundary->edit_info[from_v_i].original_vertex_i; boundary->edit_info[ni_duplis.index].num_propagation_steps = - boundary->edit_info[from_v].num_propagation_steps + 1; + boundary->edit_info[from_v_i].num_propagation_steps + 1; } } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis); @@ -383,11 +409,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, /* Check the distance using the vertex that was propagated from the initial vertex that * was used to initialize the boundary. */ - if (boundary->edit_info[from_v].original_vertex == initial_vertex) { - boundary->pivot_vertex = ni.index; - copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.index)); + if (boundary->edit_info[from_v_i].original_vertex_i == + BKE_pbvh_vertex_to_index(ss->pbvh, initial_vertex)) { + boundary->pivot_vertex = ni.vertex; + copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.vertex)); accum_distance += len_v3v3(SCULPT_vertex_co_get(ss, from_v), - SCULPT_vertex_co_get(ss, ni.index)); + SCULPT_vertex_co_get(ss, ni.vertex)); } } } @@ -427,7 +454,8 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, brush, boundary->edit_info[i].num_propagation_steps, boundary->max_propagation_steps); } - if (boundary->edit_info[i].original_vertex == boundary->initial_vertex) { + if (boundary->edit_info[i].original_vertex_i == + BKE_pbvh_vertex_to_index(ss->pbvh, boundary->initial_vertex)) { /* All vertices that are propagated from the original vertex won't be affected by the * boundary falloff, so there is no need to calculate anything else. */ continue; @@ -439,7 +467,7 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, continue; } - const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex]; + const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex_i]; float falloff_distance = 0.0f; float direction = 1.0f; @@ -473,22 +501,22 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, SculptBoundary *SCULPT_boundary_data_init(Object *object, Brush *brush, - const int initial_vertex, + const PBVHVertRef initial_vertex, const float radius) { SculptSession *ss = object->sculpt; - if (initial_vertex == BOUNDARY_VERTEX_NONE) { + if (initial_vertex.i == PBVH_REF_NONE) { return NULL; } SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_info_ensure(object); - const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex( + const PBVHVertRef boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex( ss, initial_vertex, radius); - if (boundary_initial_vertex == BOUNDARY_VERTEX_NONE) { + if (boundary_initial_vertex.i == BOUNDARY_VERTEX_NONE) { return NULL; } @@ -539,17 +567,22 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) { continue; } + + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float dir[3]; float normal[3]; - SCULPT_vertex_normal_get(ss, i, normal); - sub_v3_v3v3(dir, - SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex), - SCULPT_vertex_co_get(ss, i)); + SCULPT_vertex_normal_get(ss, vertex, normal); + sub_v3_v3v3( + dir, + SCULPT_vertex_co_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, boundary->edit_info[i].original_vertex_i)), + SCULPT_vertex_co_get(ss, vertex)); cross_v3_v3v3( - boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex], dir, normal); - normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]); - copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex], - SCULPT_vertex_co_get(ss, i)); + boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i], dir, normal); + normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]); + copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i], + SCULPT_vertex_co_get(ss, vertex)); } for (int i = 0; i < totvert; i++) { @@ -557,9 +590,9 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo continue; } copy_v3_v3(boundary->bend.pivot_positions[i], - boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex]); + boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i]); copy_v3_v3(boundary->bend.pivot_rotation_axis[i], - boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]); + boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]); } } @@ -572,10 +605,12 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) { continue; } - sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex], - SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex), - SCULPT_vertex_co_get(ss, i)); - normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex]); + sub_v3_v3v3( + boundary->slide.directions[boundary->edit_info[i].original_vertex_i], + SCULPT_vertex_co_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, boundary->edit_info[i].original_vertex_i)), + SCULPT_vertex_co_get(ss, BKE_pbvh_index_to_vertex(ss->pbvh, i))); + normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex_i]); } for (int i = 0; i < totvert; i++) { @@ -583,7 +618,7 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b continue; } copy_v3_v3(boundary->slide.directions[i], - boundary->slide.directions[boundary->edit_info[i].original_vertex]); + boundary->slide.directions[boundary->edit_info[i].original_vertex_i]); } } @@ -660,7 +695,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float t_orig_co[3]; float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]); @@ -671,7 +706,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, add_v3_v3(target_co, boundary->bend.pivot_positions[vd.index]); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -708,7 +743,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -717,7 +752,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, strength); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -754,7 +789,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -763,7 +798,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, strength); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -798,7 +833,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -806,7 +841,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, boundary->edit_info[vd.index].strength_factor * mask * automask * strength); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -849,7 +884,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); float t_orig_co[3]; float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position); @@ -860,7 +895,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, add_v3_v3(target_co, boundary->twist.pivot_position); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -898,9 +933,9 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata, int total_neighbors = 0; const int current_propagation_steps = boundary->edit_info[vd.index].num_propagation_steps; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { if (current_propagation_steps == boundary->edit_info[ni.index].num_propagation_steps) { - add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.vertex)); total_neighbors++; } } @@ -919,7 +954,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata, target_co, vd.co, disp, boundary->edit_info[vd.index].strength_factor * mask * strength); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -933,7 +968,8 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn const int symm_area = ss->cache->mirror_symmetry_pass; if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - int initial_vertex; + PBVHVertRef initial_vertex; + if (ss->cache->mirror_symmetry_pass == 0) { initial_vertex = SCULPT_active_vertex_get(ss); } diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c index cba97f9b968..cd989032f7b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -314,13 +314,13 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -412,13 +412,13 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -510,13 +510,13 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -628,13 +628,13 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -783,13 +783,13 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } } @@ -940,13 +940,13 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1066,13 +1066,13 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1219,7 +1219,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); } @@ -1267,12 +1267,12 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, if (vd.mask) { mul_v3_fl(disp, 1.0f - *vd.mask); } - mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); copy_v3_v3(proxy[vd.i], disp); } if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1352,13 +1352,13 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1426,7 +1426,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); @@ -1436,7 +1436,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, sub_v3_v3(proxy[vd.i], orig_data.co); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1497,7 +1497,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); const int vi = vd.index; @@ -1533,9 +1533,10 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, float normal[3]; if (use_persistent_base) { - SCULPT_vertex_persistent_normal_get(ss, vi, normal); + SCULPT_vertex_persistent_normal_get(ss, vd.vertex, normal); mul_v3_fl(normal, brush->height); - madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor); + madd_v3_v3v3fl( + final_co, SCULPT_vertex_persistent_co_get(ss, vd.vertex), normal, *disp_factor); } else { copy_v3_v3(normal, orig_data.no); @@ -1551,7 +1552,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, SCULPT_clip(sd, ss, vd.co, final_co); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1609,7 +1610,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float val[3]; @@ -1624,7 +1625,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1677,13 +1678,13 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1756,7 +1757,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float val1[3]; float val2[3]; @@ -1777,7 +1778,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, add_v3_v3v3(proxy[vd.i], val1, val2); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1872,7 +1873,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float disp_center[3]; float x_disp[3]; @@ -1896,7 +1897,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(proxy[vd.i], disp_center, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1988,7 +1989,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); if (grab_silhouette) { @@ -2005,7 +2006,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(proxy[vd.i], grab_delta, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2108,12 +2109,12 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, mul_v3_fl(final_disp, 1.0f - *vd.mask); } - mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); copy_v3_v3(proxy[vd.i], final_disp); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2185,13 +2186,13 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2268,7 +2269,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float current_disp[3]; float current_disp_norm[3]; @@ -2290,10 +2291,10 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vertex_disp[3]; float vertex_disp_norm[3]; - sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); + sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co); normalize_v3_v3(vertex_disp_norm, vertex_disp); if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) { madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp)); @@ -2304,7 +2305,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(proxy[vd.i], final_disp, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2323,31 +2324,31 @@ void SCULPT_relax_vertex(SculptSession *ss, int neighbor_count = 0; zero_v3(smooth_pos); zero_v3(boundary_normal); - const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index); + const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->vertex); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) { neighbor_count++; if (!filter_boundary_face_sets || - (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) { + (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.vertex))) { /* When the vertex to relax is boundary, use only connected boundary vertices for the average * position. */ if (is_boundary) { - if (!SCULPT_vertex_is_boundary(ss, ni.index)) { + if (!SCULPT_vertex_is_boundary(ss, ni.vertex)) { continue; } - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex)); avg_count++; /* Calculate a normal for the constraint plane using the edges of the boundary. */ float to_neighbor[3]; - sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co); + sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.vertex), vd->co); normalize_v3(to_neighbor); add_v3_v3(boundary_normal, to_neighbor); } else { - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex)); avg_count++; } } @@ -2376,7 +2377,7 @@ void SCULPT_relax_vertex(SculptSession *ss, normalize_v3_v3(vno, boundary_normal); } else { - SCULPT_vertex_normal_get(ss, vd->index, vno); + SCULPT_vertex_normal_get(ss, vd->vertex, vno); } if (is_zero_v3(vno)) { @@ -2425,12 +2426,12 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2501,17 +2502,17 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float limit_co[3]; float disp[3]; - SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); + SCULPT_vertex_limit_surface_get(ss, vd.vertex, limit_co); sub_v3_v3v3(disp, limit_co, vd.co); mul_v3_v3fl(proxy[vd.i], disp, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2567,7 +2568,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float current_disp[3]; @@ -2594,11 +2595,11 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, float weights_accum = 1.0f; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vertex_disp[3]; float vertex_disp_norm[3]; float neighbor_limit_co[3]; - SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co); + SCULPT_vertex_limit_surface_get(ss, ni.vertex, neighbor_limit_co); sub_v3_v3v3(vertex_disp, ss->cache->limit_surface_co[ni.index], ss->cache->limit_surface_co[vd.index]); @@ -2623,7 +2624,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, interp_v3_v3v3(vd.co, vd.co, new_co, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2638,7 +2639,7 @@ static void do_displacement_smear_store_prev_disp_task_cb_ex( PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sub_v3_v3v3(ss->cache->prev_displacement[vd.index], - SCULPT_vertex_co_get(ss, vd.index), + SCULPT_vertex_co_get(ss, vd.vertex), ss->cache->limit_surface_co[vd.index]); } BKE_pbvh_vertex_iter_end; @@ -2657,9 +2658,11 @@ void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes totvert, sizeof(float[3]), "prev displacement"); ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_limit_surface_get(ss, vertex, ss->cache->limit_surface_co[i]); sub_v3_v3v3(ss->cache->prev_displacement[i], - SCULPT_vertex_co_get(ss, i), + SCULPT_vertex_co_get(ss, vertex), ss->cache->limit_surface_co[i]); } } @@ -2722,7 +2725,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, const float fade = bstrength * SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.vertex, thread_id) * ss->cache->pressure; float avg[3], val[3]; @@ -2736,7 +2739,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, SCULPT_clip(sd, ss, vd.co, val); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -2799,7 +2802,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, } const float fade = SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.vertex, thread_id); if (bstrength > 0.0f) { (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); @@ -2810,7 +2813,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } BKE_pbvh_vertex_iter_end; } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index bf3e8a24fdf..ce8fe507c71 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -220,13 +220,16 @@ static void cloth_brush_add_length_constraint(SculptSession *ss, length_constraint->type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL; + PBVHVertRef vertex1 = BKE_pbvh_index_to_vertex(ss->pbvh, v1); + PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2); + if (use_persistent) { - length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, v1), - SCULPT_vertex_persistent_co_get(ss, v2)); + length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, vertex1), + SCULPT_vertex_persistent_co_get(ss, vertex2)); } else { - length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, v1), - SCULPT_vertex_co_get(ss, v2)); + length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, vertex1), + SCULPT_vertex_co_get(ss, vertex2)); } length_constraint->strength = 1.0f; @@ -370,7 +373,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex( int tot_indices = 0; build_indices[tot_indices] = vd.index; tot_indices++; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { build_indices[tot_indices] = ni.index; tot_indices++; } @@ -540,7 +543,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float brush_disp[3]; @@ -784,7 +787,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor); const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) * - SCULPT_automasking_factor_get(automasking, ss, vd.index); + SCULPT_automasking_factor_get(automasking, ss, vd.vertex); madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v); madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v); @@ -802,7 +805,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( copy_v3_v3(vd.co, cloth_sim->pos[vd.index]); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -852,10 +855,13 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, mul_v3_v3fl(correction_vector_half, correction_vector, 0.5f); - const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1)) * - SCULPT_automasking_factor_get(automasking, ss, v1); - const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) * - SCULPT_automasking_factor_get(automasking, ss, v2); + PBVHVertRef vertex1 = BKE_pbvh_index_to_vertex(ss->pbvh, v1); + PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2); + + const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, vertex1)) * + SCULPT_automasking_factor_get(automasking, ss, vertex1); + const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, vertex2)) * + SCULPT_automasking_factor_get(automasking, ss, vertex2); float sim_location[3]; cloth_brush_simulation_location_get(ss, brush, sim_location); @@ -1129,15 +1135,17 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation const bool has_deformation_pos = cloth_sim->deformation_pos != NULL; const bool has_softbody_pos = cloth_sim->softbody_pos != NULL; for (int i = 0; i < totverts; i++) { - copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i)); - copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i)); - copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, vertex)); + copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, vertex)); + copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, vertex)); if (has_deformation_pos) { - copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i)); + copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, vertex)); cloth_sim->deformation_strength[i] = 1.0f; } if (has_softbody_pos) { - copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, i)); + copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, vertex)); } } } @@ -1146,7 +1154,9 @@ void SCULPT_cloth_brush_store_simulation_state(SculptSession *ss, SculptClothSim { const int totverts = SCULPT_vertex_count_get(ss); for (int i = 0; i < totverts; i++) { - copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex)); } } @@ -1427,13 +1437,13 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { float fade = vd.mask ? *vd.mask : 0.0f; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); fade = 1.0f - fade; float force[3] = {0.0f, 0.0f, 0.0f}; float disp[3], temp[3], transform[3][3]; if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) { - if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) { + if (!SCULPT_vertex_has_face_set(ss, vd.vertex, ss->filter_cache->active_face_set)) { continue; } } @@ -1452,7 +1462,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, break; case CLOTH_FILTER_INFLATE: { float normal[3]; - SCULPT_vertex_normal_get(ss, vd.index, normal); + SCULPT_vertex_normal_get(ss, vd.vertex, normal); mul_v3_v3fl(force, normal, fade * data->filter_strength); } break; case CLOTH_FILTER_EXPAND: @@ -1517,7 +1527,9 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent const int totverts = SCULPT_vertex_count_get(ss); for (int i = 0; i < totverts; i++) { - copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex)); } SculptThreadedTaskData data = { diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index 00503087e39..ebbb0fa429e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -174,13 +174,13 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2]) BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); /* Average the edge length of the connected edges to the active vertex. */ - int active_vertex = SCULPT_active_vertex_get(ss); + PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); const float *active_vertex_co = SCULPT_active_vertex_co_get(ss); float edge_length = 0.0f; int tot = 0; SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { - edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.index)); + edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.vertex)); tot += 1; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -578,14 +578,14 @@ static void dyntopo_detail_size_sample_from_surface(Object *ob, DyntopoDetailSizeEditCustomData *cd) { SculptSession *ss = ob->sculpt; - const int active_vertex = SCULPT_active_vertex_get(ss); + const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); float len_accum = 0; int num_neighbors = 0; SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex), - SCULPT_vertex_co_get(ss, ni.index)); + SCULPT_vertex_co_get(ss, ni.vertex)); num_neighbors++; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 4f884420401..4f91d2215fb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -92,13 +92,16 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss) { int cd_node_layer_index; - char layer_id[] = "_dyntopo_node_id"; + char node_vertex_id[] = "_dyntopo_vnode_id"; + char node_face_id[] = "_dyntopo_fnode_id"; + + cd_node_layer_index = CustomData_get_named_layer_index( + &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); - cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id); if (cd_node_layer_index == -1) { - BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, layer_id); + BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->vdata, CD_PROP_INT32, layer_id); + &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); } ss->cd_vert_node_offset = CustomData_get_n_offset( @@ -108,11 +111,12 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss) ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; - cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT32, layer_id); + cd_node_layer_index = CustomData_get_named_layer_index( + &ss->bm->pdata, CD_PROP_INT32, node_face_id); if (cd_node_layer_index == -1) { - BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, layer_id); + BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, node_face_id); cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->pdata, CD_PROP_INT32, layer_id); + &ss->bm->pdata, CD_PROP_INT32, node_face_id); } ss->cd_face_node_offset = CustomData_get_n_offset( diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 9648f558049..4eb9f93445f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -140,10 +140,12 @@ enum { */ static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss, ExpandCache *expand_cache, - const int v) + const PBVHVertRef v) { + int v_i = BKE_pbvh_vertex_to_index(ss->pbvh, v); + for (int i = 0; i < EXPAND_SYMM_AREAS; i++) { - if (ss->vertex_info.connected_component[v] == expand_cache->active_connected_components[i]) { + if (ss->vertex_info.connected_component[v_i] == expand_cache->active_connected_components[i]) { return true; } } @@ -158,7 +160,7 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss, const int f) { const MLoop *loop = &ss->mloop[ss->mpoly[f].loopstart]; - return sculpt_expand_is_vert_in_active_component(ss, expand_cache, loop->v); + return sculpt_expand_is_vert_in_active_component(ss, expand_cache, BKE_pbvh_make_vref(loop->v)); } /** @@ -167,14 +169,16 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss, */ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss, ExpandCache *expand_cache, - const int v) + const PBVHVertRef v) { + int v_i = BKE_pbvh_vertex_to_index(ss->pbvh, v); + if (expand_cache->texture_distortion_strength == 0.0f) { - return expand_cache->vert_falloff[v]; + return expand_cache->vert_falloff[v_i]; } if (!expand_cache->brush->mtex.tex) { - return expand_cache->vert_falloff[v]; + return expand_cache->vert_falloff[v_i]; } float rgba[4]; @@ -184,7 +188,7 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss, const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength * expand_cache->max_vert_falloff; - return expand_cache->vert_falloff[v] + distortion; + return expand_cache->vert_falloff[v_i] + distortion; } /** @@ -209,7 +213,9 @@ static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache) * Main function to get the state of a vertex for the current state and settings of a #ExpandCache. * Returns true when the target data should be modified by expand. */ -static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const int v) +static bool sculpt_expand_state_get(SculptSession *ss, + ExpandCache *expand_cache, + const PBVHVertRef v) { if (!SCULPT_vertex_visible_get(ss, v)) { return false; @@ -303,7 +309,7 @@ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_ */ static float sculpt_expand_gradient_value_get(SculptSession *ss, ExpandCache *expand_cache, - const int v) + const PBVHVertRef v) { if (!expand_cache->falloff_gradient) { return 1.0f; @@ -347,7 +353,8 @@ static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCa const int totvert = SCULPT_vertex_count_get(ss); BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices"); for (int i = 0; i < totvert; i++) { - const bool enabled = sculpt_expand_state_get(ss, expand_cache, i); + const bool enabled = sculpt_expand_state_get( + ss, expand_cache, BKE_pbvh_index_to_vertex(ss->pbvh, i)); BLI_BITMAP_SET(enabled_vertices, i, enabled); } return enabled_vertices; @@ -369,16 +376,18 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss, continue; } + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + bool is_expand_boundary = false; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { if (!BLI_BITMAP_TEST(enabled_vertices, ni.index)) { is_expand_boundary = true; } } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, i)) { + if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, vertex)) { is_expand_boundary = true; } @@ -394,12 +403,12 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss, * Utility function to get the closet vertex after flipping an original vertex position based on * an symmetry pass iteration index. */ -static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob, - const char symm_it, - const int original_vertex) +static PBVHVertRef sculpt_expand_get_vertex_index_for_symmetry_pass( + Object *ob, const char symm_it, const PBVHVertRef original_vertex) { SculptSession *ss = ob->sculpt; - int symm_vertex = SCULPT_EXPAND_VERTEX_NONE; + PBVHVertRef symm_vertex = {SCULPT_EXPAND_VERTEX_NONE}; + if (symm_it == 0) { symm_vertex = original_vertex; } @@ -415,7 +424,7 @@ static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob, * Geodesic: Initializes the falloff with geodesic distances from the given active vertex, taking * symmetry into account. */ -static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const int v) +static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const PBVHVertRef v) { return SCULPT_geodesic_from_vertex_and_symm(sd, ob, v, FLT_MAX); } @@ -432,20 +441,23 @@ typedef struct ExpandFloodFillData { } ExpandFloodFillData; static bool expand_topology_floodfill_cb( - SculptSession *UNUSED(ss), int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + ExpandFloodFillData *data = userdata; if (!is_duplicate) { - const float to_it = data->dists[from_v] + 1.0f; - data->dists[to_v] = to_it; + const float to_it = data->dists[from_v_i] + 1.0f; + data->dists[to_v_i] = to_it; } else { - data->dists[to_v] = data->dists[from_v]; + data->dists[to_v_i] = data->dists[from_v_i]; } return true; } -static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const int v) +static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); @@ -470,23 +482,26 @@ static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, cons * This creates falloff patterns that follow and snap to the hard edges of the object. */ static bool mask_expand_normal_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + ExpandFloodFillData *data = userdata; if (!is_duplicate) { float current_normal[3], prev_normal[3]; SCULPT_vertex_normal_get(ss, to_v, current_normal); SCULPT_vertex_normal_get(ss, from_v, prev_normal); - const float from_edge_factor = data->edge_factor[from_v]; - data->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * from_edge_factor; - data->dists[to_v] = dot_v3v3(data->original_normal, current_normal) * - powf(from_edge_factor, data->edge_sensitivity); - CLAMP(data->dists[to_v], 0.0f, 1.0f); + const float from_edge_factor = data->edge_factor[from_v_i]; + data->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) * from_edge_factor; + data->dists[to_v_i] = dot_v3v3(data->original_normal, current_normal) * + powf(from_edge_factor, data->edge_sensitivity); + CLAMP(data->dists[to_v_i], 0.0f, 1.0f); } else { /* PBVH_GRIDS duplicate handling. */ - data->edge_factor[to_v] = data->edge_factor[from_v]; - data->dists[to_v] = data->dists[from_v]; + data->edge_factor[to_v_i] = data->edge_factor[from_v_i]; + data->dists[to_v_i] = data->dists[from_v_i]; } return true; @@ -494,7 +509,7 @@ static bool mask_expand_normal_floodfill_cb( static float *sculpt_expand_normal_falloff_create(Sculpt *sd, Object *ob, - const int v, + const PBVHVertRef v, const float edge_sensitivity) { SculptSession *ss = ob->sculpt; @@ -520,9 +535,11 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd, for (int repeat = 0; repeat < 2; repeat++) { for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg = 0.0f; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { avg += dists[ni.index]; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -539,7 +556,7 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd, * Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into * account. */ -static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v) +static float *sculpt_expand_spherical_falloff_create(Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); @@ -554,11 +571,14 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v) if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); - if (symm_vertex != -1) { + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + ob, symm_it, v); + if (symm_vertex.i != SCULPT_EXPAND_VERTEX_NONE) { const float *co = SCULPT_vertex_co_get(ss, symm_vertex); for (int i = 0; i < totvert; i++) { - dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, i))); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, vertex))); } } } @@ -571,13 +591,13 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v) * boundary to a falloff value of 0. Then, it propagates that falloff to the rest of the mesh so it * stays parallel to the boundary, increasing the falloff value by 1 on each step. */ -static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const int v) +static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); float *dists = MEM_calloc_arrayN(totvert, sizeof(float), "spherical dist"); BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices"); - GSQueue *queue = BLI_gsqueue_new(sizeof(int)); + GSQueue *queue = BLI_gsqueue_new(sizeof(PBVHVertRef)); /* Search and initialize a boundary per symmetry pass, then mark those vertices as visited. */ const char symm = SCULPT_mesh_symmetry_xyz_get(ob); @@ -586,7 +606,8 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + ob, symm_it, v); SculptBoundary *boundary = SCULPT_boundary_data_init(ob, NULL, symm_vertex, FLT_MAX); if (!boundary) { @@ -595,7 +616,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i for (int i = 0; i < boundary->num_vertices; i++) { BLI_gsqueue_push(queue, &boundary->vertices[i]); - BLI_BITMAP_ENABLE(visited_vertices, boundary->vertices[i]); + BLI_BITMAP_ENABLE(visited_vertices, boundary->vertices_i[i]); } SCULPT_boundary_data_free(boundary); } @@ -607,17 +628,19 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i /* Propagate the values from the boundaries to the rest of the mesh. */ while (!BLI_gsqueue_is_empty(queue)) { - int v_next; + PBVHVertRef v_next; + BLI_gsqueue_pop(queue, &v_next); + int v_next_i = BKE_pbvh_vertex_to_index(ss->pbvh, v_next); SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_next, ni) { if (BLI_BITMAP_TEST(visited_vertices, ni.index)) { continue; } - dists[ni.index] = dists[v_next] + 1.0f; + dists[ni.index] = dists[v_next_i] + 1.0f; BLI_BITMAP_ENABLE(visited_vertices, ni.index); - BLI_gsqueue_push(queue, &ni.index); + BLI_gsqueue_push(queue, &ni.vertex); } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); } @@ -632,7 +655,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i * the base mesh faces when checking a vertex neighbor. For this reason, this is not implement * using the general flood-fill and sculpt neighbors accessors. */ -static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v) +static float *sculpt_expand_diagonals_falloff_create(Object *ob, const PBVHVertRef v) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); @@ -647,17 +670,19 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v) /* Search and mask as visited the initial vertices using the enabled symmetry passes. */ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices"); - GSQueue *queue = BLI_gsqueue_new(sizeof(int)); + GSQueue *queue = BLI_gsqueue_new(sizeof(PBVHVertRef)); const char symm = SCULPT_mesh_symmetry_xyz_get(ob); for (char symm_it = 0; symm_it <= symm; symm_it++) { if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + ob, symm_it, v); + int symm_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, symm_vertex); BLI_gsqueue_push(queue, &symm_vertex); - BLI_BITMAP_ENABLE(visited_vertices, symm_vertex); + BLI_BITMAP_ENABLE(visited_vertices, symm_vertex_i); } if (BLI_gsqueue_is_empty(queue)) { @@ -667,17 +692,20 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v) /* Propagate the falloff increasing the value by 1 each time a new vertex is visited. */ Mesh *mesh = ob->data; while (!BLI_gsqueue_is_empty(queue)) { - int v_next; + PBVHVertRef v_next; BLI_gsqueue_pop(queue, &v_next); - for (int j = 0; j < ss->pmap[v_next].count; j++) { - MPoly *p = &ss->mpoly[ss->pmap[v_next].indices[j]]; + + int v_next_i = BKE_pbvh_vertex_to_index(ss->pbvh, v_next); + + for (int j = 0; j < ss->pmap[v_next_i].count; j++) { + MPoly *p = &ss->mpoly[ss->pmap[v_next_i].indices[j]]; for (int l = 0; l < p->totloop; l++) { - const int neighbor_v = mesh->mloop[p->loopstart + l].v; - if (BLI_BITMAP_TEST(visited_vertices, neighbor_v)) { + const PBVHVertRef neighbor_v = BKE_pbvh_make_vref(mesh->mloop[p->loopstart + l].v); + if (BLI_BITMAP_TEST(visited_vertices, neighbor_v.i)) { continue; } - dists[neighbor_v] = dists[v_next] + 1.0f; - BLI_BITMAP_ENABLE(visited_vertices, neighbor_v); + dists[neighbor_v.i] = dists[v_next_i] + 1.0f; + BLI_BITMAP_ENABLE(visited_vertices, neighbor_v.i); BLI_gsqueue_push(queue, &neighbor_v); } } @@ -701,11 +729,13 @@ static void sculpt_expand_update_max_vert_falloff_value(SculptSession *ss, const int totvert = SCULPT_vertex_count_get(ss); expand_cache->max_vert_falloff = -FLT_MAX; for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (expand_cache->vert_falloff[i] == FLT_MAX) { continue; } - if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) { + if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex)) { continue; } @@ -856,7 +886,9 @@ static void sculpt_expand_topology_from_state_boundary(Object *ob, if (!BLI_BITMAP_TEST(boundary_vertices, i)) { continue; } - SCULPT_floodfill_add_and_skip_initial(&flood, i); + + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + SCULPT_floodfill_add_and_skip_initial(&flood, vertex); } MEM_freeN(boundary_vertices); @@ -921,10 +953,12 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob, BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices"); for (int i = 0; i < totvert; i++) { - if (!SCULPT_vertex_has_unique_face_set(ss, i)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) { continue; } - if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { + if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) { continue; } BLI_BITMAP_ENABLE(enabled_vertices, i); @@ -941,8 +975,10 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob, if (internal_falloff) { for (int i = 0; i < totvert; i++) { - if (!(SCULPT_vertex_has_face_set(ss, i, active_face_set) && - SCULPT_vertex_has_unique_face_set(ss, i))) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!(SCULPT_vertex_has_face_set(ss, vertex, active_face_set) && + SCULPT_vertex_has_unique_face_set(ss, vertex))) { continue; } expand_cache->vert_falloff[i] *= -1.0f; @@ -960,7 +996,9 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob, } else { for (int i = 0; i < totvert; i++) { - if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) { continue; } expand_cache->vert_falloff[i] = 0.0f; @@ -976,7 +1014,7 @@ static void sculpt_expand_falloff_factors_from_vertex_and_symm_create( ExpandCache *expand_cache, Sculpt *sd, Object *ob, - const int v, + const PBVHVertRef v, eSculptExpandFalloffType falloff_type) { MEM_SAFE_FREE(expand_cache->vert_falloff); @@ -1128,7 +1166,7 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *exp PBVHNode *node = nodes[n]; PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { - SCULPT_vertex_color_set(ss, vd.index, expand_cache->original_colors[vd.index]); + SCULPT_vertex_color_set(ss, vd.vertex, expand_cache->original_colors[vd.index]); } BKE_pbvh_vertex_iter_end; BKE_pbvh_node_mark_redraw(node); @@ -1215,12 +1253,12 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { const float initial_mask = *vd.mask; - const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index); + const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex); float new_mask; if (enabled) { - new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index); + new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex); } else { new_mask = 0.0f; @@ -1237,7 +1275,7 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata, *vd.mask = clamp_f(new_mask, 0.0f, 1.0f); any_changed = true; if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1287,13 +1325,13 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { float initial_color[4]; - SCULPT_vertex_color_get(ss, vd.index, initial_color); + SCULPT_vertex_color_get(ss, vd.vertex, initial_color); - const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index); + const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex); float fade; if (enabled) { - fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index); + fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex); } else { fade = 0.0f; @@ -1314,11 +1352,11 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata, continue; } - SCULPT_vertex_color_set(ss, vd.index, final_color); + SCULPT_vertex_color_set(ss, vd.vertex, final_color); any_changed = true; if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1364,14 +1402,18 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c if (expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { expand_cache->original_mask = MEM_malloc_arrayN(totvert, sizeof(float), "initial mask"); for (int i = 0; i < totvert; i++) { - expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, vertex); } } if (expand_cache->target == SCULPT_EXPAND_TARGET_COLORS) { expand_cache->original_colors = MEM_malloc_arrayN(totvert, sizeof(float[4]), "initial colors"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_color_get(ss, i, expand_cache->original_colors[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_color_get(ss, vertex, expand_cache->original_colors[i]); } } } @@ -1394,14 +1436,16 @@ static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expa } } -static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int vertex) +static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const PBVHVertRef vertex) { SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; ExpandCache *expand_cache = ss->expand_cache; + int vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, vertex); + /* Update the active factor in the cache. */ - if (vertex == SCULPT_EXPAND_VERTEX_NONE) { + if (vertex.i == SCULPT_EXPAND_VERTEX_NONE) { /* This means that the cursor is not over the mesh, so a valid active falloff can't be * determined. In this situations, don't evaluate enabled states and default all vertices in * connected components to enabled. */ @@ -1409,7 +1453,7 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v expand_cache->all_enabled = true; } else { - expand_cache->active_falloff = expand_cache->vert_falloff[vertex]; + expand_cache->active_falloff = expand_cache->vert_falloff[vertex_i]; expand_cache->all_enabled = false; } @@ -1450,14 +1494,16 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v * Updates the #SculptSession cursor data and gets the active vertex * if the cursor is over the mesh. */ -static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const float mval[2]) +static PBVHVertRef sculpt_expand_target_vertex_update_and_get(bContext *C, + Object *ob, + const float mval[2]) { SculptSession *ss = ob->sculpt; SculptCursorGeometryInfo sgi; if (SCULPT_cursor_geometry_info_update(C, &sgi, mval, false)) { return SCULPT_active_vertex_get(ss); } - return SCULPT_EXPAND_VERTEX_NONE; + return BKE_pbvh_make_vref(SCULPT_EXPAND_VERTEX_NONE); } /** @@ -1493,15 +1539,17 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache const float *expand_init_co = SCULPT_vertex_co_get(ss, expand_cache->initial_active_vertex); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (!BLI_BITMAP_TEST(boundary_vertices, i)) { continue; } - if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) { + if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, vertex)) { continue; } - const float *vertex_co = SCULPT_vertex_co_get(ss, i); + const float *vertex_co = SCULPT_vertex_co_get(ss, vertex); if (!SCULPT_check_vertex_pivot_symmetry(vertex_co, expand_init_co, symm)) { continue; @@ -1556,9 +1604,8 @@ static void sculpt_expand_finish(bContext *C) * Finds and stores in the #ExpandCache the sculpt connected component index for each symmetry pass * needed for expand. */ -static void sculpt_expand_find_active_connected_components_from_vert(Object *ob, - ExpandCache *expand_cache, - const int initial_vertex) +static void sculpt_expand_find_active_connected_components_from_vert( + Object *ob, ExpandCache *expand_cache, const PBVHVertRef initial_vertex) { SculptSession *ss = ob->sculpt; for (int i = 0; i < EXPAND_SYMM_AREAS; i++) { @@ -1571,11 +1618,13 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob, continue; } - const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + const PBVHVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( ob, symm_it, initial_vertex); + int symm_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, symm_vertex); + expand_cache->active_connected_components[(int)symm_it] = - ss->vertex_info.connected_component[symm_vertex]; + ss->vertex_info.connected_component[symm_vertex_i]; } } @@ -1589,14 +1638,20 @@ static void sculpt_expand_set_initial_components_for_mouse(bContext *C, const float mval[2]) { SculptSession *ss = ob->sculpt; - int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval); - if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) { + + PBVHVertRef initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval); + + if (initial_vertex.i == SCULPT_EXPAND_VERTEX_NONE) { /* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active * vertex in the sculpt session. */ initial_vertex = SCULPT_active_vertex_get(ss); } + + int initial_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, initial_vertex); + copy_v2_v2(ss->expand_cache->initial_mouse, mval); expand_cache->initial_active_vertex = initial_vertex; + expand_cache->initial_active_vertex_i = initial_vertex_i; expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss); if (expand_cache->next_face_set == SCULPT_FACE_SET_NONE) { @@ -1696,7 +1751,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event /* Update and get the active vertex (and face) from the cursor. */ const float mval_fl[2] = {UNPACK2(event->mval)}; - const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval_fl); + const PBVHVertRef target_expand_vertex = sculpt_expand_target_vertex_update_and_get( + C, ob, mval_fl); /* Handle the modal keymap state changes. */ ExpandCache *expand_cache = ss->expand_cache; diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index ce704e619ea..57a8bb1d72d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -142,7 +142,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) { @@ -161,11 +161,11 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); if (fade > 0.05f) { - SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set); + SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set); } } } @@ -199,7 +199,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } - if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) { + if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) { continue; } @@ -210,12 +210,12 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -324,8 +324,11 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) if (mode == SCULPT_FACE_SET_MASKED) { for (int i = 0; i < tot_vert; i++) { - if (SCULPT_vertex_mask_get(ss, i) >= threshold && SCULPT_vertex_visible_get(ss, i)) { - SCULPT_vertex_face_set_set(ss, i, next_face_set); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (SCULPT_vertex_mask_get(ss, vertex) >= threshold && + SCULPT_vertex_visible_get(ss, vertex)) { + SCULPT_vertex_face_set_set(ss, vertex, next_face_set); } } } @@ -337,7 +340,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) * sets and the performance hit of rendering the overlay. */ bool all_visible = true; for (int i = 0; i < tot_vert; i++) { - if (!SCULPT_vertex_visible_get(ss, i)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_visible_get(ss, vertex)) { all_visible = false; break; } @@ -351,15 +356,19 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } for (int i = 0; i < tot_vert; i++) { - if (SCULPT_vertex_visible_get(ss, i)) { - SCULPT_vertex_face_set_set(ss, i, next_face_set); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (SCULPT_vertex_visible_get(ss, vertex)) { + SCULPT_vertex_face_set_set(ss, vertex, next_face_set); } } } if (mode == SCULPT_FACE_SET_ALL) { for (int i = 0; i < tot_vert; i++) { - SCULPT_vertex_face_set_set(ss, i, next_face_set); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_face_set_set(ss, vertex, next_face_set); } } @@ -869,7 +878,9 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) * be synced from face sets to non-manifold vertices. */ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { for (int i = 0; i < tot_vert; i++) { - if (!SCULPT_vertex_visible_get(ss, i)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_visible_get(ss, vertex)) { hidden_vertex = true; break; } @@ -1222,9 +1233,11 @@ static void sculpt_face_set_edit_fair_face_set(Object *ob, SCULPT_boundary_info_ensure(ob); for (int i = 0; i < totvert; i++) { - fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, i) && - SCULPT_vertex_has_face_set(ss, i, active_face_set_id) && - SCULPT_vertex_has_unique_face_set(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, vertex) && + SCULPT_vertex_has_face_set(ss, vertex, active_face_set_id) && + SCULPT_vertex_has_unique_face_set(ss, vertex); } MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index a9186010a9f..380c093b871 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -104,7 +104,7 @@ static void color_filter_task_cb(void *__restrict userdata, float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); if (fade == 0.0f) { continue; } @@ -189,10 +189,10 @@ static void color_filter_task_cb(void *__restrict userdata, case COLOR_FILTER_SMOOTH: { fade = clamp_f(fade, -1.0f, 1.0f); float smooth_color[4]; - SCULPT_neighbor_color_average(ss, smooth_color, vd.index); + SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); if (fade < 0.0f) { interp_v4_v4v4(smooth_color, smooth_color, col, 0.5f); @@ -224,10 +224,10 @@ static void color_filter_task_cb(void *__restrict userdata, } } - SCULPT_vertex_color_set(ss, vd.index, final_color); + SCULPT_vertex_color_set(ss, vd.vertex, final_color); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -244,7 +244,8 @@ static void sculpt_color_presmooth_init(SculptSession *ss) } for (int i = 0; i < totvert; i++) { - SCULPT_vertex_color_get(ss, i, ss->filter_cache->pre_smoothed_color[i]); + SCULPT_vertex_color_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, i), ss->filter_cache->pre_smoothed_color[i]); } for (int iteration = 0; iteration < 2; iteration++) { @@ -253,7 +254,7 @@ static void sculpt_color_presmooth_init(SculptSession *ss) int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, BKE_pbvh_index_to_vertex(ss->pbvh, i), ni) { float col[4] = {0}; copy_v4_v4(col, ss->filter_cache->pre_smoothed_color[ni.index]); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index ea3f56d0859..adc3887a365 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -103,7 +103,7 @@ static void mask_filter_task_cb(void *__restrict userdata, switch (mode) { case MASK_FILTER_SMOOTH: case MASK_FILTER_SHARPEN: { - float val = SCULPT_neighbor_mask_average(ss, vd.index); + float val = SCULPT_neighbor_mask_average(ss, vd.vertex); val -= *vd.mask; @@ -123,7 +123,7 @@ static void mask_filter_task_cb(void *__restrict userdata, } case MASK_FILTER_GROW: max = 0.0f; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vmask_f = data->prev_mask[ni.index]; if (vmask_f > max) { max = vmask_f; @@ -134,7 +134,7 @@ static void mask_filter_task_cb(void *__restrict userdata, break; case MASK_FILTER_SHRINK: min = 1.0f; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vmask_f = data->prev_mask[ni.index]; if (vmask_f < min) { min = vmask_f; @@ -163,7 +163,7 @@ static void mask_filter_task_cb(void *__restrict userdata, update = true; } if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -217,7 +217,8 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask"); for (int j = 0; j < num_verts; j++) { - prev_mask[j] = SCULPT_vertex_mask_get(ss, j); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, j); + prev_mask[j] = SCULPT_vertex_mask_get(ss, vertex); } } @@ -308,9 +309,9 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd) zero_v3(avg); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) { float normalized[3]; - sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co); + sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.vertex), vd->co); normalize_v3(normalized); add_v3_v3(avg, normalized); total++; @@ -388,7 +389,7 @@ static void dirty_mask_apply_task_cb(void *__restrict userdata, *vd.mask = CLAMPIS(mask, 0.0f, 1.0f); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index c0adf5aef20..326bb3d1d15 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -296,7 +296,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); if (fade == 0.0f && filter_type != MESH_FILTER_SURFACE_SMOOTH) { /* Surface Smooth can't skip the loop for this vertex as it needs to calculate its @@ -314,7 +314,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, } if (filter_type == MESH_FILTER_RELAX_FACE_SETS) { - if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) { + if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) { continue; } } @@ -322,7 +322,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, switch (filter_type) { case MESH_FILTER_SMOOTH: fade = clamp_f(fade, -1.0f, 1.0f); - SCULPT_neighbor_coords_average_interior(ss, avg, vd.index); + SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex); sub_v3_v3v3(val, avg, orig_co); madd_v3_v3v3fl(val, orig_co, val, fade); sub_v3_v3v3(disp, val, orig_co); @@ -385,7 +385,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, disp, vd.co, ss->filter_cache->surface_smooth_laplacian_disp, - vd.index, + vd.vertex, orig_data.co, ss->filter_cache->surface_smooth_shape_preservation); break; @@ -399,10 +399,10 @@ static void mesh_filter_task_cb(void *__restrict userdata, float disp_sharpen[3] = {0.0f, 0.0f, 0.0f}; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float disp_n[3]; sub_v3_v3v3( - disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index)); + disp_n, SCULPT_vertex_co_get(ss, ni.vertex), SCULPT_vertex_co_get(ss, vd.vertex)); mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]); add_v3_v3(disp_sharpen, disp_n); } @@ -412,7 +412,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, float disp_avg[3]; float avg_co[3]; - SCULPT_neighbor_coords_average(ss, avg_co, vd.index); + SCULPT_neighbor_coords_average(ss, avg_co, vd.vertex); sub_v3_v3v3(disp_avg, avg_co, vd.co); mul_v3_v3fl( disp_avg, disp_avg, smooth_ratio * pow2f(ss->filter_cache->sharpen_factor[vd.index])); @@ -457,7 +457,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, } copy_v3_v3(vd.co, final_pos); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -473,9 +473,11 @@ static void mesh_filter_enhance_details_init_directions(SculptSession *ss) filter_cache->detail_directions = MEM_malloc_arrayN( totvert, sizeof(float[3]), "detail directions"); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg[3]; - SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + SCULPT_neighbor_coords_average(ss, avg, vertex); + sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex)); } } @@ -500,7 +502,9 @@ static void mesh_filter_init_limit_surface_co(SculptSession *ss) filter_cache->limit_surface_co = MEM_malloc_arrayN( totvert, sizeof(float[3]), "limit surface co"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_limit_surface_get(ss, i, filter_cache->limit_surface_co[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_limit_surface_get(ss, vertex, filter_cache->limit_surface_co[i]); } } @@ -520,9 +524,11 @@ static void mesh_filter_sharpen_init(SculptSession *ss, totvert, sizeof(float[3]), "sharpen detail direction"); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg[3]; - SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + SCULPT_neighbor_coords_average(ss, avg, vertex); + sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex)); filter_cache->sharpen_factor[i] = len_v3(filter_cache->detail_directions[i]); } @@ -544,12 +550,14 @@ static void mesh_filter_sharpen_init(SculptSession *ss, smooth_iterations < filter_cache->sharpen_curvature_smooth_iterations; smooth_iterations++) { for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float direction_avg[3] = {0.0f, 0.0f, 0.0f}; float sharpen_avg = 0; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { add_v3_v3(direction_avg, filter_cache->detail_directions[ni.index]); sharpen_avg += filter_cache->sharpen_factor[ni.index]; total++; @@ -576,7 +584,7 @@ static void mesh_filter_surface_smooth_displace_task_cb( float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index); + fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); if (fade == 0.0f) { continue; } @@ -584,7 +592,7 @@ static void mesh_filter_surface_smooth_displace_task_cb( SCULPT_surface_smooth_displace_step(ss, vd.co, ss->filter_cache->surface_smooth_laplacian_disp, - vd.index, + vd.vertex, ss->filter_cache->surface_smooth_current_vertex, clamp_f(fade, 0.0f, 1.0f)); } diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.c b/source/blender/editors/sculpt_paint/sculpt_geodesic.c index 1beb5d48961..ecf8c4586ae 100644 --- a/source/blender/editors/sculpt_paint/sculpt_geodesic.c +++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.c @@ -279,9 +279,12 @@ static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices return dists; } - const float *first_affected_co = SCULPT_vertex_co_get(ss, first_affected); + const float *first_affected_co = SCULPT_vertex_co_get( + ss, BKE_pbvh_index_to_vertex(ss->pbvh, first_affected)); for (int i = 0; i < totvert; i++) { - dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, vertex)); } return dists; @@ -305,7 +308,7 @@ float *SCULPT_geodesic_distances_create(Object *ob, float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, Object *ob, - const int vertex, + const PBVHVertRef vertex, const float limit_radius) { SculptSession *ss = ob->sculpt; @@ -314,7 +317,8 @@ float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, const char symm = SCULPT_mesh_symmetry_xyz_get(ob); for (char i = 0; i <= symm; ++i) { if (SCULPT_is_symmetry_iteration_valid(i, symm)) { - int v = -1; + PBVHVertRef v = {PBVH_REF_NONE}; + if (i == 0) { v = vertex; } @@ -323,8 +327,8 @@ float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i); v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false); } - if (v != -1) { - BLI_gset_add(initial_vertices, POINTER_FROM_INT(v)); + if (v.i != PBVH_REF_NONE) { + BLI_gset_add(initial_vertices, POINTER_FROM_INT(BKE_pbvh_vertex_to_index(ss->pbvh, v))); } } } @@ -334,10 +338,11 @@ float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, return dists; } -float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius) +float *SCULPT_geodesic_from_vertex(Object *ob, const PBVHVertRef vertex, const float limit_radius) { GSet *initial_vertices = BLI_gset_int_new("initial_vertices"); - BLI_gset_add(initial_vertices, POINTER_FROM_INT(vertex)); + BLI_gset_add(initial_vertices, + POINTER_FROM_INT(BKE_pbvh_vertex_to_index(ob->sculpt->pbvh, vertex))); float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius); BLI_gset_free(initial_vertices, NULL); return dists; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 179e07cc7fa..86f89c3c2fa 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -59,10 +59,13 @@ typedef struct SculptCursorGeometryInfo { typedef struct SculptVertexNeighborIter { /* Storage */ - int *neighbors; + PBVHVertRef *neighbors; + int *neighbor_indices; int size; int capacity; - int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; + + PBVHVertRef neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; + int neighbor_indices_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; /* Internal iterator. */ int num_duplicates; @@ -70,6 +73,7 @@ typedef struct SculptVertexNeighborIter { /* Public */ int index; + PBVHVertRef vertex; bool is_duplicate; } SculptVertexNeighborIter; @@ -318,7 +322,7 @@ typedef struct SculptThreadedTaskData { bool mask_by_color_preserve_mask; /* Index of the vertex that is going to be used as a reference for the colors. */ - int mask_by_color_vertex; + PBVHVertRef mask_by_color_vertex; float *mask_by_color_floodfill; int face_set; @@ -690,7 +694,8 @@ typedef struct ExpandCache { * during the execution of Expand by moving the origin. */ float initial_mouse_move[2]; float initial_mouse[2]; - int initial_active_vertex; + PBVHVertRef initial_active_vertex; + int initial_active_vertex_i; int initial_active_face_set; /* Maximum number of vertices allowed in the SculptSession for previewing the falloff using @@ -898,14 +903,14 @@ bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cach void SCULPT_vertex_random_access_ensure(struct SculptSession *ss); int SCULPT_vertex_count_get(struct SculptSession *ss); -const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index); +const float *SCULPT_vertex_co_get(struct SculptSession *ss, PBVHVertRef vertex); /** Get the normal for a given sculpt vertex; do not modify the result */ -void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]); +void SCULPT_vertex_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]); -float SCULPT_vertex_mask_get(struct SculptSession *ss, int index); -void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4]); -void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4]); +float SCULPT_vertex_mask_get(struct SculptSession *ss, PBVHVertRef vertex); +void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]); +void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]); /** Returns true if a color attribute exists in the current sculpt session. */ bool SCULPT_has_colors(const SculptSession *ss); @@ -913,19 +918,19 @@ bool SCULPT_has_colors(const SculptSession *ss); /** Returns true if the active color attribute is on loop (ATTR_DOMAIN_CORNER) domain. */ bool SCULPT_has_loop_colors(const struct Object *ob); -const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index); -void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]); +const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, PBVHVertRef vertex); +void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]); /** * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */ -const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index); +const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, PBVHVertRef vertex); /** * Returns the info of the limit surface when multi-res is available, * otherwise it returns the current coordinate of the vertex. */ -void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]); +void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, float r_co[3]); /** * Returns the pointer to the coordinates that should be edited from a brush tool iterator @@ -936,7 +941,7 @@ float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, PBVHVertexIter *iter); void SCULPT_vertex_neighbors_get(struct SculptSession *ss, - int index, + PBVHVertRef vertex, bool include_duplicates, SculptVertexNeighborIter *iter); @@ -945,7 +950,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ neighbor_iterator.i++) { \ - neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; + neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; /** Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come * first since they are nearest for floodfill. */ @@ -953,7 +959,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ neighbor_iterator.i--) { \ - neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \ neighbor_iterator.size - neighbor_iterator.num_duplicates); @@ -964,7 +971,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, } \ ((void)0) -int SCULPT_active_vertex_get(SculptSession *ss); +PBVHVertRef SCULPT_active_vertex_get(SculptSession *ss); const float *SCULPT_active_vertex_co_get(SculptSession *ss); void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]); @@ -984,7 +991,7 @@ void SCULPT_fake_neighbors_free(struct Object *ob); /* Vertex Info. */ void SCULPT_boundary_info_ensure(Object *object); /* Boundary Info needs to be initialized in order to use this function. */ -bool SCULPT_vertex_is_boundary(const SculptSession *ss, int index); +bool SCULPT_vertex_is_boundary(const SculptSession *ss, PBVHVertRef vertex); void SCULPT_connected_components_ensure(Object *ob); @@ -994,8 +1001,8 @@ void SCULPT_connected_components_ensure(Object *ob); /** \name Sculpt Visibility API * \{ */ -void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible); -bool SCULPT_vertex_visible_get(SculptSession *ss, int index); +void SCULPT_vertex_visible_set(SculptSession *ss, PBVHVertRef vertex, bool visible); +bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex); void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob); void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss); @@ -1007,17 +1014,17 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss); * \{ */ int SCULPT_active_face_set_get(SculptSession *ss); -int SCULPT_vertex_face_set_get(SculptSession *ss, int index); -void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set); +int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex); +void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_set); -bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set); -bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index); +bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set); +bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex); int SCULPT_face_set_next_available_get(SculptSession *ss); void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible); -bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index); -bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index); +bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex); +bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex); void SCULPT_face_sets_visibility_invert(SculptSession *ss); void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible); @@ -1103,11 +1110,11 @@ void SCULPT_calc_area_normal_and_center( void SCULPT_calc_area_center( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]); -int SCULPT_nearest_vertex_get(struct Sculpt *sd, - struct Object *ob, - const float co[3], - float max_distance, - bool use_original); +PBVHVertRef SCULPT_nearest_vertex_get(struct Sculpt *sd, + struct Object *ob, + const float co[3], + float max_distance, + bool use_original); int SCULPT_plane_point_side(const float co[3], const float plane[4]); int SCULPT_plane_trim(const struct StrokeCache *cache, @@ -1186,7 +1193,7 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss, const float vno[3], const float fno[3], float mask, - int vertex_index, + const PBVHVertRef vertex, int thread_id); /** @@ -1217,15 +1224,18 @@ void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd, struct Object *ob, struct SculptSession *ss, SculptFloodFill *flood, - int index, + PBVHVertRef vertex, float radius); -void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index); -void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index); -void SCULPT_floodfill_execute( - struct SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), - void *userdata); +void SCULPT_floodfill_add_initial(SculptFloodFill *flood, PBVHVertRef vertex); +void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex); +void SCULPT_floodfill_execute(struct SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, + PBVHVertRef from_v, + PBVHVertRef to_v, + bool is_duplicate, + void *userdata), + void *userdata); void SCULPT_floodfill_free(SculptFloodFill *flood); /** \} */ @@ -1275,7 +1285,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob); float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking, SculptSession *ss, - int vert); + PBVHVertRef vertex); /* Returns the automasking cache depending on the active tool. Used for code that can run both for * brushes and filter. */ @@ -1308,9 +1318,9 @@ float *SCULPT_geodesic_distances_create(struct Object *ob, float limit_radius); float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd, struct Object *ob, - int vertex, + PBVHVertRef vertex, float limit_radius); -float *SCULPT_geodesic_from_vertex(Object *ob, int vertex, float limit_radius); +float *SCULPT_geodesic_from_vertex(Object *ob, PBVHVertRef vertex, float limit_radius); /** \} */ /* -------------------------------------------------------------------- */ @@ -1416,14 +1426,16 @@ BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) */ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v); -void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index); -float SCULPT_neighbor_mask_average(SculptSession *ss, int index); -void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index); +void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef vertex); +float SCULPT_neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex); +void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex); /** * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking. */ -void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index); +void SCULPT_neighbor_coords_average_interior(SculptSession *ss, + float result[3], + PBVHVertRef vertex); void SCULPT_smooth( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength, bool smooth_mask); @@ -1435,11 +1447,15 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, float *disp, const float co[3], float (*laplacian_disp)[3], - int v_index, + PBVHVertRef vertex, const float origco[3], float alpha); -void SCULPT_surface_smooth_displace_step( - SculptSession *ss, float *co, float (*laplacian_disp)[3], int v_index, float beta, float fade); +void SCULPT_surface_smooth_displace_step(SculptSession *ss, + float *co, + float (*laplacian_disp)[3], + PBVHVertRef vertex, + float beta, + float fade); void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); /* Slide/Relax */ @@ -1645,7 +1661,7 @@ void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain); */ struct SculptBoundary *SCULPT_boundary_data_init(Object *object, Brush *brush, - int initial_vertex, + PBVHVertRef initial_vertex, float radius); void SCULPT_boundary_data_free(struct SculptBoundary *boundary); /* Main Brush Function. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 4593c6a8b60..68aa0031940 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -97,11 +97,14 @@ static void sculpt_expand_task_cb(void *__restrict userdata, PBVHVertexIter vd; int update_it = data->mask_expand_update_it; + PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); + int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, active_vertex); + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) { int vi = vd.index; float final_mask = *vd.mask; if (data->mask_expand_use_normals) { - if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] < + if (ss->filter_cache->normal_factor[active_vertex_i] < ss->filter_cache->normal_factor[vd.index]) { final_mask = 1.0f; } @@ -121,7 +124,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata, if (data->mask_expand_create_face_set) { if (final_mask == 1.0f) { - SCULPT_vertex_face_set_set(ss, vd.index, ss->filter_cache->new_face_set); + SCULPT_vertex_face_set_set(ss, vd.vertex, ss->filter_cache->new_face_set); } BKE_pbvh_node_mark_redraw(node); } @@ -137,7 +140,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata, if (*vd.mask != final_mask) { if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } *vd.mask = final_mask; BKE_pbvh_node_mark_update_mask(node); @@ -167,10 +170,13 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * if (RNA_boolean_get(op->ptr, "use_cursor")) { SculptCursorGeometryInfo sgi; + const float mval_fl[2] = {UNPACK2(event->mval)}; if (SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) { + int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, SCULPT_active_vertex_get(ss)); + /* The cursor is over the mesh, get the update iteration from the updated active vertex. */ - mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)]; + mask_expand_update_it = ss->filter_cache->mask_update_it[active_vertex_i]; } else { /* When the cursor is outside the mesh, affect the entire connected component. */ @@ -291,13 +297,16 @@ typedef struct MaskExpandFloodFillData { } MaskExpandFloodFillData; static bool mask_expand_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { MaskExpandFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + if (!is_duplicate) { - int to_it = ss->filter_cache->mask_update_it[from_v] + 1; - ss->filter_cache->mask_update_it[to_v] = to_it; + int to_it = ss->filter_cache->mask_update_it[from_v_i] + 1; + ss->filter_cache->mask_update_it[to_v_i] = to_it; if (to_it > ss->filter_cache->mask_update_last_it) { ss->filter_cache->mask_update_last_it = to_it; } @@ -306,20 +315,20 @@ static bool mask_expand_floodfill_cb( float current_normal[3], prev_normal[3]; SCULPT_vertex_normal_get(ss, to_v, current_normal); SCULPT_vertex_normal_get(ss, from_v, prev_normal); - const float from_edge_factor = ss->filter_cache->edge_factor[from_v]; - ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * - from_edge_factor; - ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) * - powf(from_edge_factor, data->edge_sensitivity); - CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f); + const float from_edge_factor = ss->filter_cache->edge_factor[from_v_i]; + ss->filter_cache->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) * + from_edge_factor; + ss->filter_cache->normal_factor[to_v_i] = dot_v3v3(data->original_normal, current_normal) * + powf(from_edge_factor, data->edge_sensitivity); + CLAMP(ss->filter_cache->normal_factor[to_v_i], 0.0f, 1.0f); } } else { /* PBVH_GRIDS duplicate handling. */ - ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v]; + ss->filter_cache->mask_update_it[to_v_i] = ss->filter_cache->mask_update_it[from_v_i]; if (data->use_normals) { - ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v]; - ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v]; + ss->filter_cache->edge_factor[to_v_i] = ss->filter_cache->edge_factor[from_v_i]; + ss->filter_cache->normal_factor[to_v_i] = ss->filter_cache->normal_factor[from_v_i]; } } @@ -392,13 +401,17 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent else { ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask"); for (int i = 0; i < vertex_count; i++) { - ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, i); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, vertex); } } + int active_vertex_i = BKE_pbvh_vertex_to_index(ss->pbvh, SCULPT_active_vertex_get(ss)); + ss->filter_cache->mask_update_last_it = 1; ss->filter_cache->mask_update_current_it = 1; - ss->filter_cache->mask_update_it[SCULPT_active_vertex_get(ss)] = 0; + ss->filter_cache->mask_update_it[active_vertex_i] = 0; copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss)); @@ -417,9 +430,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent if (use_normals) { for (int repeat = 0; repeat < 2; repeat++) { for (int i = 0; i < vertex_count; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg = 0.0f; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { avg += ss->filter_cache->normal_factor[ni.index]; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c index 025f34ab2d7..cc27623adb0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_init.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c @@ -99,7 +99,7 @@ static void mask_init_task_cb(void *__restrict userdata, *vd.mask = BLI_hash_int_01(vd.index + seed); break; case SCULPT_MASK_INIT_RANDOM_PER_FACE_SET: { - const int face_set = SCULPT_vertex_face_set_get(ss, vd.index); + const int face_set = SCULPT_vertex_face_set_get(ss, vd.vertex); *vd.mask = BLI_hash_int_01(face_set + seed); break; } diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index ddc1a0e1db0..48a9d7a7f9b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -86,7 +86,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); /* Sample the normal and area of the +X and -X axis individually. */ @@ -194,13 +194,13 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index f16763be735..3279d54e6f1 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -129,8 +129,10 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) "layer persistent base"); for (int i = 0; i < totvert; i++) { - copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i)); - SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, vertex)); + SCULPT_vertex_normal_get(ss, vertex, ss->persistent_base[i].no); ss->persistent_base[i].disp = 0.0f; } @@ -543,7 +545,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Object *ob = CTX_data_active_object(C); - ss->preview_vert_index_count = 0; + ss->preview_vert_count = 0; int totpoints = 0; /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */ @@ -573,29 +575,32 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; - if (ss->preview_vert_index_list == NULL) { - ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines"); + if (ss->preview_vert_list == NULL) { + ss->preview_vert_list = MEM_callocN(max_preview_vertices * sizeof(PBVHVertRef), + "preview lines"); } - GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int)); - int active_v = SCULPT_active_vertex_get(ss); + GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(PBVHVertRef)); + PBVHVertRef active_v = SCULPT_active_vertex_get(ss); BLI_gsqueue_push(not_visited_vertices, &active_v); while (!BLI_gsqueue_is_empty(not_visited_vertices)) { - int from_v; + PBVHVertRef from_v; + BLI_gsqueue_pop(not_visited_vertices, &from_v); SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { if (totpoints + (ni.size * 2) < max_preview_vertices) { - int to_v = ni.index; - ss->preview_vert_index_list[totpoints] = from_v; + PBVHVertRef to_v = ni.vertex; + int to_v_i = ni.index; + ss->preview_vert_list[totpoints] = from_v; totpoints++; - ss->preview_vert_index_list[totpoints] = to_v; + ss->preview_vert_list[totpoints] = to_v; totpoints++; - if (BLI_BITMAP_TEST(visited_vertices, to_v)) { + if (BLI_BITMAP_TEST(visited_vertices, to_v_i)) { continue; } - BLI_BITMAP_ENABLE(visited_vertices, to_v); + BLI_BITMAP_ENABLE(visited_vertices, to_v_i); const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v); if (len_squared_v3v3(brush_co, co) < radius * radius) { BLI_gsqueue_push(not_visited_vertices, &to_v); @@ -609,7 +614,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float MEM_freeN(visited_vertices); - ss->preview_vert_index_count = totpoints; + ss->preview_vert_count = totpoints; } static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op)) @@ -764,7 +769,7 @@ static int sculpt_sample_color_invoke(bContext *C, wmOperator *op, const wmEvent Object *ob = CTX_data_active_object(C); Brush *brush = BKE_paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; - int active_vertex = SCULPT_active_vertex_get(ss); + PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); float active_vertex_color[4]; if (!SCULPT_handles_colors_report(ss, op->reports)) { @@ -883,7 +888,7 @@ static void do_mask_by_color_contiguous_update_nodes_cb( } update_node = true; if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -893,8 +898,11 @@ static void do_mask_by_color_contiguous_update_nodes_cb( } static bool sculpt_mask_by_color_contiguous_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + MaskByColorContiguousFloodFillData *data = userdata; float current_color[4]; @@ -902,10 +910,10 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb( float new_vertex_mask = sculpt_mask_by_color_delta_get( current_color, data->initial_color, data->threshold, data->invert); - data->new_mask[to_v] = new_vertex_mask; + data->new_mask[to_v_i] = new_vertex_mask; if (is_duplicate) { - data->new_mask[to_v] = data->new_mask[from_v]; + data->new_mask[to_v_i] = data->new_mask[from_v_i]; } float len = len_v3v3(current_color, data->initial_color); @@ -914,7 +922,7 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb( } static void sculpt_mask_by_color_contiguous(Object *object, - const int vertex, + const PBVHVertRef vertex, const float threshold, const bool invert, const bool preserve_mask) @@ -991,7 +999,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); const float current_mask = *vd.mask; const float new_mask = sculpt_mask_by_color_delta_get(active_color, col, threshold, invert); @@ -1002,7 +1010,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata, } update_node = true; if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -1012,7 +1020,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata, } static void sculpt_mask_by_color_full_mesh(Object *object, - const int vertex, + const PBVHVertRef vertex, const float threshold, const bool invert, const bool preserve_mask) @@ -1067,7 +1075,7 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven SCULPT_undo_push_begin(ob, "Mask by color"); BKE_sculpt_color_layer_create_if_needed(ob); - const int active_vertex = SCULPT_active_vertex_get(ss); + const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); const float threshold = RNA_float_get(op->ptr, "threshold"); const bool invert = RNA_boolean_get(op->ptr, "invert"); const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index 7e813590e21..bf64ff39ae7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -80,19 +80,19 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float smooth_color[4]; - SCULPT_neighbor_color_average(ss, smooth_color, vd.index); + SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); blend_color_interpolate_float(col, col, smooth_color, fade); - SCULPT_vertex_color_set(ss, vd.index, col); + SCULPT_vertex_color_set(ss, vd.vertex, col); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -151,7 +151,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); /* Density. */ @@ -182,13 +182,13 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); IMB_blend_color_float(col, orig_data.col, buffer_color, brush->blend); CLAMP4(col, 0.0f, 1.0f); - SCULPT_vertex_color_set(ss, vd.index, col); + SCULPT_vertex_color_set(ss, vd.vertex, col); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -221,7 +221,7 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata, } float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); add_v4_v4(swptd->color, col); swptd->tot_samples++; @@ -400,7 +400,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float current_disp[3]; @@ -409,7 +409,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]); float no[3]; - SCULPT_vertex_normal_get(ss, vd.index, no); + SCULPT_vertex_normal_get(ss, vd.vertex, no); switch (brush->smear_deform_type) { case BRUSH_SMEAR_DEFORM_DRAG: @@ -442,11 +442,11 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, */ SculptVertexNeighborIter ni2; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni2) { - const float *nco = SCULPT_vertex_co_get(ss, ni2.index); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni2) { + const float *nco = SCULPT_vertex_co_get(ss, ni2.vertex); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, ni2.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, ni2.vertex, ni) { if (ni.index == vd.index) { continue; } @@ -454,13 +454,13 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, float vertex_disp[3]; float vertex_disp_norm[3]; - sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); + sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co); /* Weight by how close we are to our target distance from vd.co. */ float w = (1.0f + fabsf(len_v3(vertex_disp) / bstrength - 1.0f)); /* TODO: use cotangents (or at least face areas) here. */ - float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.index), nco); + float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.vertex), nco); if (len > 0.0f) { len = bstrength / len; } @@ -502,12 +502,12 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, blend_color_mix_float(interp_color, interp_color, accum); float col[4]; - SCULPT_vertex_color_get(ss, vd.index, col); + SCULPT_vertex_color_get(ss, vd.vertex, col); blend_color_interpolate_float(col, ss->cache->prev_colors[vd.index], interp_color, fade); - SCULPT_vertex_color_set(ss, vd.index, col); + SCULPT_vertex_color_set(ss, vd.vertex, col); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -522,7 +522,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_vertex_color_get(ss, vd.index, ss->cache->prev_colors[vd.index]); + SCULPT_vertex_color_get(ss, vd.vertex, ss->cache->prev_colors[vd.index]); } BKE_pbvh_vertex_iter_end; } @@ -541,7 +541,9 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode if (!ss->cache->prev_colors) { ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_color_get(ss, vertex, ss->cache->prev_colors[i]); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc index f51a603ee5d..8a3a3fe7adc 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc +++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc @@ -172,7 +172,15 @@ template<typename ImageBuffer> class PaintingKernel { const float3 face_normal(0.0f, 0.0f, 0.0f); const float mask = 0.0f; const float falloff_strength = SCULPT_brush_strength_factor( - ss, brush, pixel_pos, sqrtf(test.dist), normal, face_normal, mask, 0, thread_id); + ss, + brush, + pixel_pos, + sqrtf(test.dist), + normal, + face_normal, + mask, + BKE_pbvh_make_vref(PBVH_REF_NONE), + thread_id); float4 paint_color = brush_color * falloff_strength * brush_strength; float4 buffer_color; blend_color_mix_float(buffer_color, color, paint_color); diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index 479ed43c6bf..f898f53f3ac 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -182,7 +182,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, /* Apply the vertex mask to the displacement. */ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); + const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); mul_v3_fl(disp, mask * automask); /* Accumulate the displacement. */ @@ -196,7 +196,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, copy_v3_v3(target_co, final_pos); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -221,7 +221,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, float max = 0.0f; /* Grow the factor. */ - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { float vmask_f = data->prev_mask[ni.index]; max = MAX2(vmask_f, max); } @@ -367,7 +367,7 @@ typedef struct PoseFloodFillData { int current_face_set; int next_face_set; int prev_face_set; - int next_vertex; + PBVHVertRef next_vertex; bool next_face_set_found; @@ -397,14 +397,19 @@ typedef struct PoseFloodFillData { int target_face_set; } PoseFloodFillData; -static bool pose_topology_floodfill_cb( - SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) +static bool pose_topology_floodfill_cb(SculptSession *ss, + PBVHVertRef UNUSED(from_v), + PBVHVertRef to_v, + bool is_duplicate, + void *userdata) { + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + PoseFloodFillData *data = userdata; const float *co = SCULPT_vertex_co_get(ss, to_v); if (data->pose_factor) { - data->pose_factor[to_v] = 1.0f; + data->pose_factor[to_v_i] = 1.0f; } if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) < @@ -426,15 +431,19 @@ static bool pose_topology_floodfill_cb( return false; } -static bool pose_face_sets_floodfill_cb( - SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) +static bool pose_face_sets_floodfill_cb(SculptSession *ss, + PBVHVertRef UNUSED(from_v), + PBVHVertRef to_v, + bool is_duplicate, + void *userdata) { PoseFloodFillData *data = userdata; - const int index = to_v; + const int index = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + const PBVHVertRef vertex = to_v; bool visit_next = false; - const float *co = SCULPT_vertex_co_get(ss, index); + const float *co = SCULPT_vertex_co_get(ss, vertex); const bool symmetry_check = SCULPT_check_vertex_pivot_symmetry( co, data->pose_initial_co, data->symm) && !is_duplicate; @@ -448,11 +457,11 @@ static bool pose_face_sets_floodfill_cb( if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { - const int visited_face_set = SCULPT_vertex_face_set_get(ss, index); + const int visited_face_set = SCULPT_vertex_face_set_get(ss, vertex); BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(visited_face_set)); } else if (symmetry_check) { - data->current_face_set = SCULPT_vertex_face_set_get(ss, index); + data->current_face_set = SCULPT_vertex_face_set_get(ss, vertex); BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(data->current_face_set)); } return true; @@ -466,11 +475,11 @@ static bool pose_face_sets_floodfill_cb( GSetIterator gs_iter; GSET_ITER (gs_iter, data->visited_face_sets) { const int visited_face_set = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); - is_vertex_valid |= SCULPT_vertex_has_face_set(ss, index, visited_face_set); + is_vertex_valid |= SCULPT_vertex_has_face_set(ss, vertex, visited_face_set); } } else { - is_vertex_valid = SCULPT_vertex_has_face_set(ss, index, data->current_face_set); + is_vertex_valid = SCULPT_vertex_has_face_set(ss, vertex, data->current_face_set); } if (!is_vertex_valid) { @@ -485,11 +494,11 @@ static bool pose_face_sets_floodfill_cb( /* Fallback origin accumulation. */ if (symmetry_check) { - add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, index)); + add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, vertex)); data->fallback_count++; } - if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, index)) { + if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, vertex)) { return visit_next; } @@ -498,15 +507,15 @@ static bool pose_face_sets_floodfill_cb( bool count_as_boundary = false; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { - int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.index); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.vertex); /* Check if we can get a valid face set for the next iteration from this neighbor. */ - if (SCULPT_vertex_has_unique_face_set(ss, ni.index) && + if (SCULPT_vertex_has_unique_face_set(ss, ni.vertex) && !BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(next_face_set_candidate))) { if (!data->next_face_set_found) { data->next_face_set = next_face_set_candidate; - data->next_vertex = ni.index; + data->next_vertex = ni.vertex; data->next_face_set_found = true; } count_as_boundary = true; @@ -516,7 +525,7 @@ static bool pose_face_sets_floodfill_cb( /* Origin accumulation. */ if (count_as_boundary) { - add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, index)); + add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, vertex)); data->tot_co++; } return visit_next; @@ -585,7 +594,7 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata, SculptVertexNeighborIter ni; float avg = 0.0f; int total = 0; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { avg += data->pose_factor[ni.index]; total++; } @@ -660,7 +669,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, float next_chain_segment_target[3]; int totvert = SCULPT_vertex_count_get(ss); - int nearest_vertex_index = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true); + PBVHVertRef nearest_vertex = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true); + int nearest_vertex_index = BKE_pbvh_vertex_to_index(ss->pbvh, nearest_vertex); /* Init the buffers used to keep track of the changes in the pose factors as more segments are * added to the IK chain. */ @@ -745,7 +755,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( int current_face_set = SCULPT_FACE_SET_NONE; int prev_face_set = SCULPT_FACE_SET_NONE; - int current_vertex = SCULPT_active_vertex_get(ss); + PBVHVertRef current_vertex = SCULPT_active_vertex_get(ss); for (int s = 0; s < ik_chain->tot_segments; s++) { @@ -801,15 +811,18 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( } static bool pose_face_sets_fk_find_masked_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + if (!is_duplicate) { - data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1; + data->floodfill_it[to_v_i] = data->floodfill_it[from_v_i] + 1; } else { - data->floodfill_it[to_v] = data->floodfill_it[from_v]; + data->floodfill_it[to_v_i] = data->floodfill_it[from_v_i]; } const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v); @@ -820,9 +833,9 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb( BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(to_face_set)); - if (data->floodfill_it[to_v] >= data->masked_face_set_it) { + if (data->floodfill_it[to_v_i] >= data->masked_face_set_it) { data->masked_face_set = to_face_set; - data->masked_face_set_it = data->floodfill_it[to_v]; + data->masked_face_set_it = data->floodfill_it[to_v_i]; } if (data->target_face_set == SCULPT_FACE_SET_NONE) { @@ -834,11 +847,17 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb( return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set); } -static bool pose_face_sets_fk_set_weights_floodfill_cb( - SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata) +static bool pose_face_sets_fk_set_weights_floodfill_cb(SculptSession *ss, + PBVHVertRef UNUSED(from_v), + PBVHVertRef to_v, + bool UNUSED(is_duplicate), + void *userdata) { PoseFloodFillData *data = userdata; - data->fk_weights[to_v] = 1.0f; + + int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); + + data->fk_weights[to_v_i] = 1.0f; return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set); } @@ -849,7 +868,9 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert); - const int active_vertex = SCULPT_active_vertex_get(ss); + const PBVHVertRef active_vertex = SCULPT_active_vertex_get(ss); + int active_vertex_index = BKE_pbvh_vertex_to_index(ss->pbvh, active_vertex); + const int active_face_set = SCULPT_active_face_set_get(ss); SculptFloodFill flood; @@ -857,7 +878,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( SCULPT_floodfill_add_initial(&flood, active_vertex); PoseFloodFillData fdata; fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration"); - fdata.floodfill_it[active_vertex] = 1; + fdata.floodfill_it[active_vertex_index] = 1; fdata.initial_face_set = active_face_set; fdata.masked_face_set = SCULPT_FACE_SET_NONE; fdata.target_face_set = SCULPT_FACE_SET_NONE; @@ -870,9 +891,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( int origin_count = 0; float origin_acc[3] = {0.0f}; for (int i = 0; i < totvert; i++) { - if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) && - SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) { - add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i)); + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (fdata.floodfill_it[i] != 0 && + SCULPT_vertex_has_face_set(ss, vertex, fdata.initial_face_set) && + SCULPT_vertex_has_face_set(ss, vertex, fdata.masked_face_set)) { + add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, vertex)); origin_count++; } } @@ -881,10 +905,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk( float target_acc[3] = {0.0f}; if (fdata.target_face_set != fdata.masked_face_set) { for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (fdata.floodfill_it[i] != 0 && - SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) && - SCULPT_vertex_has_face_set(ss, i, fdata.target_face_set)) { - add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i)); + SCULPT_vertex_has_face_set(ss, vertex, fdata.initial_face_set) && + SCULPT_vertex_has_face_set(ss, vertex, fdata.target_face_set)) { + add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, vertex)); target_count++; } } diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index c31863d892f..1ebb33ec690 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -46,26 +46,28 @@ #include <math.h> #include <stdlib.h> -void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index) +void SCULPT_neighbor_coords_average_interior(SculptSession *ss, + float result[3], + PBVHVertRef vertex) { float avg[3] = {0.0f, 0.0f, 0.0f}; int total = 0; int neighbor_count = 0; - const bool is_boundary = SCULPT_vertex_is_boundary(ss, index); + const bool is_boundary = SCULPT_vertex_is_boundary(ss, vertex); SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { neighbor_count++; if (is_boundary) { /* Boundary vertices use only other boundary vertices. */ - if (SCULPT_vertex_is_boundary(ss, ni.index)) { - add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index)); + if (SCULPT_vertex_is_boundary(ss, ni.vertex)) { + add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex)); total++; } } else { /* Interior vertices use all neighbors. */ - add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index)); + add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex)); total++; } } @@ -73,13 +75,13 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], /* Do not modify corner vertices. */ if (neighbor_count <= 2 && is_boundary) { - copy_v3_v3(result, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); return; } /* Avoid division by 0 when there are no neighbors. */ if (total == 0) { - copy_v3_v3(result, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); return; } @@ -134,14 +136,14 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert /* Generic functions for laplacian smoothing. These functions do not take boundary vertices into * account. */ -void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index) +void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], PBVHVertRef vertex) { float avg[3] = {0.0f, 0.0f, 0.0f}; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { - add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index)); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex)); total++; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -150,18 +152,18 @@ void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int inde mul_v3_v3fl(result, avg, 1.0f / total); } else { - copy_v3_v3(result, SCULPT_vertex_co_get(ss, index)); + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); } } -float SCULPT_neighbor_mask_average(SculptSession *ss, int index) +float SCULPT_neighbor_mask_average(SculptSession *ss, PBVHVertRef vertex) { float avg = 0.0f; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { - avg += SCULPT_vertex_mask_get(ss, ni.index); + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + avg += SCULPT_vertex_mask_get(ss, ni.vertex); total++; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); @@ -169,19 +171,19 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, int index) if (total > 0) { return avg / total; } - return SCULPT_vertex_mask_get(ss, index); + return SCULPT_vertex_mask_get(ss, vertex); } -void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index) +void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], PBVHVertRef vertex) { float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f}; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { float tmp[4] = {0}; - SCULPT_vertex_color_get(ss, ni.index, tmp); + SCULPT_vertex_color_get(ss, ni.vertex, tmp); add_v4_v4(avg, tmp); total++; @@ -192,7 +194,7 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index mul_v4_v4fl(result, avg, 1.0f / total); } else { - SCULPT_vertex_color_get(ss, index, result); + SCULPT_vertex_color_get(ss, vertex, result); } } @@ -227,7 +229,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float disp[3]; @@ -235,7 +237,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata, SCULPT_clip(sd, ss, vd.co, disp); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -258,9 +260,11 @@ static void SCULPT_enhance_details_brush(Sculpt *sd, totvert, sizeof(float[3]), "details directions"); for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + float avg[3]; - SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + SCULPT_neighbor_coords_average(ss, avg, vertex); + sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex)); } } @@ -309,23 +313,23 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata, vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), - vd.index, + vd.vertex, thread_id); if (smooth_mask) { - float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask; + float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask; val *= fade * bstrength; *vd.mask += val; CLAMP(*vd.mask, 0.0f, 1.0f); } else { float avg[3], val[3]; - SCULPT_neighbor_coords_average_interior(ss, avg, vd.index); + SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex); sub_v3_v3v3(val, avg, vd.co); madd_v3_v3v3fl(val, vd.co, val, fade); SCULPT_clip(sd, ss, vd.co, val); } if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -403,13 +407,15 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, float *disp, const float co[3], float (*laplacian_disp)[3], - const int v_index, + const PBVHVertRef vertex, const float origco[3], const float alpha) { float laplacian_smooth_co[3]; float weigthed_o[3], weigthed_q[3], d[3]; - SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index); + int v_index = BKE_pbvh_vertex_to_index(ss->pbvh, vertex); + + SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, vertex); mul_v3_v3fl(weigthed_o, origco, alpha); mul_v3_v3fl(weigthed_q, co, 1.0f - alpha); @@ -422,7 +428,7 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, void SCULPT_surface_smooth_displace_step(SculptSession *ss, float *co, float (*laplacian_disp)[3], - const int v_index, + const PBVHVertRef vertex, const float beta, const float fade) { @@ -430,12 +436,15 @@ void SCULPT_surface_smooth_displace_step(SculptSession *ss, float b_current_vertex[3]; int total = 0; SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_index, ni) { + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { add_v3_v3(b_avg, laplacian_disp[ni.index]); total++; } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { + int v_index = BKE_pbvh_vertex_to_index(ss->pbvh, vertex); + mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / total); madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta); mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f)); @@ -474,15 +483,15 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); float disp[3]; SCULPT_surface_smooth_laplacian_step( - ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, orig_data.co, alpha); + ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, orig_data.co, alpha); madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f)); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -515,10 +524,10 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - vd.index, + vd.vertex, thread_id); SCULPT_surface_smooth_displace_step( - ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade); + ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade); } BKE_pbvh_vertex_iter_end; } diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index 3b810d02b84..1f0c7791cf5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -179,7 +179,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata, add_v3_v3v3(vd.co, start_co, disp); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; @@ -253,7 +253,7 @@ static void sculpt_elastic_transform_task_cb(void *__restrict userdata, copy_v3_v3(proxy[vd.i], final_disp); if (vd.mvert) { - BKE_pbvh_vert_mark_update(ss->pbvh, vd.index); + BKE_pbvh_vert_mark_update(ss->pbvh, vd.vertex); } } BKE_pbvh_vertex_iter_end; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 1e050fedf8e..60739dad40f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -263,20 +263,20 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); - BKE_pbvh_vert_mark_update(ss->pbvh, index[i]); + BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); } } else { for (int i = 0; i < unode->totvert; i++) { swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); - BKE_pbvh_vert_mark_update(ss->pbvh, index[i]); + BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); } } } else { for (int i = 0; i < unode->totvert; i++) { swap_v3_v3(mvert[index[i]].co, unode->co[i]); - BKE_pbvh_vert_mark_update(ss->pbvh, index[i]); + BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); } } } @@ -320,7 +320,7 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode) if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) { BLI_BITMAP_FLIP(unode->vert_hidden, i); v->flag ^= ME_HIDE; - BKE_pbvh_vert_mark_update(ss->pbvh, unode->index[i]); + BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(unode->index[i])); } } } @@ -360,7 +360,7 @@ static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode) if (modified) { for (int i = 0; i < unode->totvert; i++) { - BKE_pbvh_vert_mark_update(ss->pbvh, unode->index[i]); + BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_index_to_vertex(ss->pbvh, unode->index[i])); } } @@ -385,7 +385,7 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode) for (int i = 0; i < unode->totvert; i++) { if (vmask[index[i]] != unode->mask[i]) { SWAP(float, vmask[index[i]], unode->mask[i]); - BKE_pbvh_vert_mark_update(ss->pbvh, index[i]); + BKE_pbvh_vert_mark_update(ss->pbvh, BKE_pbvh_make_vref(index[i])); } } } diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index 7d4f38b1841..b509eae8ea6 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -11,6 +11,7 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index c69b73e377d..90b3cec437c 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -20,6 +20,7 @@ #include "ED_space_api.h" #include "RNA_access.h" +#include "RNA_path.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 3b8c6cbd1d0..d41904d9790 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -41,6 +41,7 @@ #include "WM_types.h" #include "RNA_access.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "ED_anim_api.h" diff --git a/source/blender/editors/space_image/image_undo.cc b/source/blender/editors/space_image/image_undo.cc index 0fe0414c177..9e8db58ccc2 100644 --- a/source/blender/editors/space_image/image_undo.cc +++ b/source/blender/editors/space_image/image_undo.cc @@ -432,7 +432,7 @@ static void utile_decref(UndoImageTile *utile) /** \name Image Undo Buffer * \{ */ -typedef struct UndoImageBuf { +struct UndoImageBuf { struct UndoImageBuf *next, *prev; /** @@ -456,8 +456,7 @@ typedef struct UndoImageBuf { bool use_float; char gen_type; } image_state; - -} UndoImageBuf; +}; static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf) { @@ -552,7 +551,7 @@ static void ubuf_free(UndoImageBuf *ubuf) /** \name Image Undo Handle * \{ */ -typedef struct UndoImageHandle { +struct UndoImageHandle { struct UndoImageHandle *next, *prev; /** Each undo handle refers to a single image which may have multiple buffers. */ @@ -567,8 +566,7 @@ typedef struct UndoImageHandle { * List of #UndoImageBuf's to support multiple buffers per image. */ ListBase buffers; - -} UndoImageHandle; +}; static void uhandle_restore_list(ListBase *undo_handles, bool use_init) { diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index 29a7eb150a1..e41ff02254b 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -439,14 +439,7 @@ static void stats_update(Depsgraph *depsgraph, } else if (ob && (ob->mode & OB_MODE_SCULPT)) { /* Sculpt Mode. */ - if (stats_is_object_dynamic_topology_sculpt(ob)) { - /* Dynamic topology. Do not count all vertices, - * dynamic topology stats are initialized later as part of sculpt stats. */ - } - else { - /* When dynamic topology is not enabled both sculpt stats and scene stats are collected. */ - stats_object_sculpt(ob, stats); - } + stats_object_sculpt(ob, stats); } else { /* Objects. */ diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 160a379d3c6..bb520c0537e 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -36,6 +36,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "WM_api.h" @@ -44,7 +45,12 @@ #include "UI_resources.h" #include "NOD_common.h" +#include "NOD_composite.h" +#include "NOD_geometry.h" +#include "NOD_shader.h" #include "NOD_socket.h" +#include "NOD_texture.h" + #include "node_intern.hh" /* own include */ namespace blender::ed::space_node { @@ -99,16 +105,16 @@ const char *node_group_idname(bContext *C) SpaceNode *snode = CTX_wm_space_node(C); if (ED_node_is_shader(snode)) { - return "ShaderNodeGroup"; + return ntreeType_Shader->group_idname; } if (ED_node_is_compositor(snode)) { - return "CompositorNodeGroup"; + return ntreeType_Composite->group_idname; } if (ED_node_is_texture(snode)) { - return "TextureNodeGroup"; + return ntreeType_Texture->group_idname; } if (ED_node_is_geometry(snode)) { - return "GeometryNodeGroup"; + return ntreeType_Geometry->group_idname; } return ""; diff --git a/source/blender/editors/space_outliner/outliner_collections.cc b/source/blender/editors/space_outliner/outliner_collections.cc index 8ca2ffe6a9c..7d0a0a921e4 100644 --- a/source/blender/editors/space_outliner/outliner_collections.cc +++ b/source/blender/editors/space_outliner/outliner_collections.cc @@ -72,7 +72,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) } if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *lc = static_cast<LayerCollection *>(te->directdata); return lc->collection; } if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { @@ -88,7 +88,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata); + struct IDsSelectedData *data = static_cast<IDsSelectedData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (outliner_is_collection_tree_element(te)) { @@ -105,7 +105,7 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata); + struct IDsSelectedData *data = static_cast<IDsSelectedData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (outliner_is_collection_tree_element(te)) { @@ -184,7 +184,7 @@ struct CollectionNewData { static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) { - struct CollectionNewData *data = reinterpret_cast<CollectionNewData *>(customdata); + struct CollectionNewData *data = static_cast<CollectionNewData *>(customdata); Collection *collection = outliner_collection_from_tree_element(te); if (!collection) { @@ -286,7 +286,7 @@ struct CollectionEditData { static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata) { - CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata); + CollectionEditData *data = static_cast<CollectionEditData *>(customdata); Collection *collection = outliner_collection_from_tree_element(te); if (!collection) { @@ -339,7 +339,7 @@ void outliner_collection_delete( /* Effectively delete the collections. */ GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); /* Test in case collection got deleted as part of another one. */ @@ -444,12 +444,12 @@ struct CollectionObjectsSelectData { static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata) { - CollectionObjectsSelectData *data = reinterpret_cast<CollectionObjectsSelectData *>(customdata); + CollectionObjectsSelectData *data = static_cast<CollectionObjectsSelectData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); switch (tselem->type) { case TSE_LAYER_COLLECTION: - data->layer_collection = reinterpret_cast<LayerCollection *>(te->directdata); + data->layer_collection = static_cast<LayerCollection *>(te->directdata); return TRAVERSE_BREAK; case TSE_R_LAYER: case TSE_SCENE_COLLECTION_BASE: @@ -538,7 +538,7 @@ struct CollectionDuplicateData { static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata) { - CollectionDuplicateData *data = reinterpret_cast<CollectionDuplicateData *>(customdata); + CollectionDuplicateData *data = static_cast<CollectionDuplicateData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); switch (tselem->type) { @@ -701,7 +701,7 @@ static int collection_link_exec(bContext *C, wmOperator *op) /* Effectively link the collections. */ GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_collection_child_add(bmain, active_collection, collection); id_fake_user_clear(&collection->id); @@ -762,7 +762,7 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); while (BKE_collection_cycle_find(active_lc->collection, collection)) { @@ -772,7 +772,7 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) /* Effectively instance the collections. */ GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); Object *ob = ED_object_add_type( C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, nullptr, false, 0); @@ -814,14 +814,14 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot) static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata) { - CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata); + CollectionEditData *data = static_cast<CollectionEditData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) { return TRAVERSE_CONTINUE; } - LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *lc = static_cast<LayerCollection *>(te->directdata); if (lc->collection->flag & COLLECTION_IS_MASTER) { /* skip - showing warning/error message might be misleading @@ -862,7 +862,7 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>( + LayerCollection *lc = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (clear && (lc->flag & flag)) { @@ -934,7 +934,7 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>( + LayerCollection *lc = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_flag(lc, flag, !clear); } @@ -1068,7 +1068,7 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (extend) { @@ -1168,7 +1168,7 @@ static int collection_visibility_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside); } @@ -1319,7 +1319,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) &data); GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); Collection *collection = layer_collection->collection; if (!BKE_id_is_editable(bmain, &collection->id)) { @@ -1348,7 +1348,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) &data); GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = reinterpret_cast<Collection *>( + Collection *collection = static_cast<Collection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (!BKE_id_is_editable(bmain, &collection->id)) { continue; @@ -1451,7 +1451,7 @@ struct OutlinerHideEditData { static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata) { - OutlinerHideEditData *data = reinterpret_cast<OutlinerHideEditData *>(customdata); + OutlinerHideEditData *data = static_cast<OutlinerHideEditData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (tselem == nullptr) { @@ -1459,7 +1459,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void } if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *lc = static_cast<LayerCollection *>(te->directdata); if (lc->collection->flag & COLLECTION_IS_MASTER) { /* Skip - showing warning/error message might be misleading @@ -1501,7 +1501,7 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_visible(view_layer, layer_collection, false, false); } @@ -1509,7 +1509,7 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator bases_to_edit_iter; GSET_ITER (bases_to_edit_iter, data.bases_to_edit) { - Base *base = reinterpret_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter)); + Base *base = static_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter)); base->flag |= BASE_HIDDEN; } BLI_gset_free(data.bases_to_edit, nullptr); @@ -1542,8 +1542,7 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op)) ViewLayer *view_layer = CTX_data_view_layer(C); /* Unhide all the collections. */ - LayerCollection *lc_master = reinterpret_cast<LayerCollection *>( - view_layer->layer_collections.first); + LayerCollection *lc_master = static_cast<LayerCollection *>(view_layer->layer_collections.first); LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) { BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false); } diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc index 7435fa50a93..2fa512b4006 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.cc +++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc @@ -144,7 +144,7 @@ static TreeElement *outliner_drop_insert_find(bContext *C, return te_hovered; } *r_insert_type = TE_INSERT_BEFORE; - return reinterpret_cast<TreeElement *>(te_hovered->subtree.first); + return static_cast<TreeElement *>(te_hovered->subtree.first); } *r_insert_type = TE_INSERT_AFTER; return te_hovered; @@ -159,8 +159,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C, /* Mouse doesn't hover any item (ignoring x-axis), * so it's either above list bounds or below. */ - TreeElement *first = reinterpret_cast<TreeElement *>(space_outliner->tree.first); - TreeElement *last = reinterpret_cast<TreeElement *>(space_outliner->tree.last); + TreeElement *first = static_cast<TreeElement *>(space_outliner->tree.first); + TreeElement *last = static_cast<TreeElement *>(space_outliner->tree.last); if (view_mval[1] < last->ys) { *r_insert_type = TE_INSERT_AFTER; @@ -422,12 +422,12 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); parent_drop_set_parents(C, op->reports, - reinterpret_cast<wmDragID *>(drag->ids.first), + static_cast<wmDragID *>(drag->ids.first), par, PAR_OBJECT, event->modifier & KM_ALT); @@ -505,8 +505,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) { if (GS(drag_id->id->name) == ID_OB) { @@ -849,7 +849,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) ARegion *region = CTX_wm_region(C); bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); - StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); + StackDropData *drop_data = static_cast<StackDropData *>(drag->poin); if (!drop_data) { return false; } @@ -887,7 +887,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C), const int UNUSED(xy[2]), struct wmDropBox *UNUSED(drop)) { - StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); + StackDropData *drop_data = static_cast<StackDropData *>(drag->poin); switch (drop_data->drop_action) { case DATA_STACK_DROP_REORDER: return BLI_strdup(TIP_("Reorder")); @@ -965,14 +965,13 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) case TSE_MODIFIER: if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) { ED_object_gpencil_modifier_copy_to_object( - ob_dst, reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata)); + ob_dst, static_cast<GpencilModifierData *>(drop_data->drag_directdata)); } else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) { - ED_object_modifier_copy_to_object( - C, - ob_dst, - drop_data->ob_parent, - reinterpret_cast<ModifierData *>(drop_data->drag_directdata)); + ED_object_modifier_copy_to_object(C, + ob_dst, + drop_data->ob_parent, + static_cast<ModifierData *>(drop_data->drag_directdata)); } break; case TSE_CONSTRAINT: @@ -980,12 +979,12 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) ED_object_constraint_copy_for_pose( bmain, ob_dst, - reinterpret_cast<bPoseChannel *>(drop_data->drop_te->directdata), - reinterpret_cast<bConstraint *>(drop_data->drag_directdata)); + static_cast<bPoseChannel *>(drop_data->drop_te->directdata), + static_cast<bConstraint *>(drop_data->drag_directdata)); } else { ED_object_constraint_copy_for_object( - bmain, ob_dst, reinterpret_cast<bConstraint *>(drop_data->drag_directdata)); + bmain, ob_dst, static_cast<bConstraint *>(drop_data->drag_directdata)); } break; case TSE_GPENCIL_EFFECT: { @@ -993,8 +992,7 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) return; } - ED_object_shaderfx_copy(ob_dst, - reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata)); + ED_object_shaderfx_copy(ob_dst, static_cast<ShaderFxData *>(drop_data->drag_directdata)); break; } } @@ -1021,15 +1019,12 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa index = outliner_get_insert_index( drag_te, drop_te, insert_type, &ob->greasepencil_modifiers); ED_object_gpencil_modifier_move_to_index( - reports, - ob, - reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata), - index); + reports, ob, static_cast<GpencilModifierData *>(drop_data->drag_directdata), index); } else { index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers); ED_object_modifier_move_to_index( - reports, ob, reinterpret_cast<ModifierData *>(drop_data->drag_directdata), index); + reports, ob, static_cast<ModifierData *>(drop_data->drag_directdata), index); } break; case TSE_CONSTRAINT: @@ -1041,13 +1036,13 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints); } ED_object_constraint_move_to_index( - ob, reinterpret_cast<bConstraint *>(drop_data->drag_directdata), index); + ob, static_cast<bConstraint *>(drop_data->drag_directdata), index); break; case TSE_GPENCIL_EFFECT: index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx); ED_object_shaderfx_move_to_index( - reports, ob, reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata), index); + reports, ob, static_cast<ShaderFxData *>(drop_data->drag_directdata), index); } } @@ -1057,9 +1052,9 @@ static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *eve return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); - StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); + StackDropData *drop_data = static_cast<StackDropData *>(drag->poin); switch (drop_data->drop_action) { case DATA_STACK_DROP_LINK: @@ -1143,7 +1138,7 @@ static bool collection_drop_init(bContext *C, wmDrag *drag, const int xy[2], Col return false; } - wmDragID *drag_id = reinterpret_cast<wmDragID *>(drag->ids.first); + wmDragID *drag_id = static_cast<wmDragID *>(drag->ids.first); if (drag_id == nullptr) { return false; } @@ -1300,8 +1295,8 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE return OPERATOR_CANCELLED; } - ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); - wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); + ListBase *lb = static_cast<ListBase *>(event->customdata); + wmDrag *drag = static_cast<wmDrag *>(lb->first); CollectionDrop data; if (!collection_drop_init(C, drag, event->xy, &data)) { diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index 6bab0b938e8..1828846811a 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -277,8 +277,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C, Object *ob_parent = ob ? ob : base->object; - for (Object *ob_iter = reinterpret_cast<Object *>(bmain->objects.first); ob_iter; - ob_iter = reinterpret_cast<Object *>(ob_iter->id.next)) { + for (Object *ob_iter = static_cast<Object *>(bmain->objects.first); ob_iter; + ob_iter = static_cast<Object *>(ob_iter->id.next)) { if (BKE_object_is_child_recursive(ob_parent, ob_iter)) { if (ob) { RNA_id_pointer_create(&ob_iter->id, &ptr); @@ -312,8 +312,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C, */ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Object *ob = reinterpret_cast<Object *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + Object *ob = static_cast<Object *>(poin); + char *propname = static_cast<char *>(poin2); outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname); } @@ -322,8 +322,8 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void */ static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Base *base = reinterpret_cast<Base *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + Base *base = static_cast<Base *>(poin); + char *propname = static_cast<char *>(poin2); outliner_object_set_flag_recursive_fn(C, base, nullptr, propname); } @@ -488,7 +488,7 @@ void outliner_collection_isolate_flag(Scene *scene, const bool is_hide = strstr(propname, "hide_") != nullptr; LayerCollection *top_layer_collection = layer_collection ? - reinterpret_cast<LayerCollection *>( + static_cast<LayerCollection *>( view_layer->layer_collections.first) : nullptr; Collection *top_collection = collection ? scene->master_collection : nullptr; @@ -559,7 +559,7 @@ void outliner_collection_isolate_flag(Scene *scene, else { CollectionParent *parent; Collection *child = collection; - while ((parent = reinterpret_cast<CollectionParent *>(child->parents.first))) { + while ((parent = static_cast<CollectionParent *>(child->parents.first))) { if (parent->collection->flag & COLLECTION_IS_MASTER) { break; } @@ -638,8 +638,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + LayerCollection *layer_collection = static_cast<LayerCollection *>(poin); + char *propname = static_cast<char *>(poin2); outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname); } @@ -649,8 +649,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C, */ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + LayerCollection *layer_collection = static_cast<LayerCollection *>(poin); + char *propname = static_cast<char *>(poin2); outliner_collection_set_flag_recursive_fn( C, layer_collection, layer_collection->collection, propname); } @@ -661,8 +661,8 @@ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin */ static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Collection *collection = reinterpret_cast<Collection *>(poin); - char *propname = reinterpret_cast<char *>(poin2); + Collection *collection = static_cast<Collection *>(poin); + char *propname = static_cast<char *>(poin2); outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname); } @@ -672,7 +672,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); struct wmMsgBus *mbus = CTX_wm_message_bus(C); BLI_mempool *ts = space_outliner->treestore; - TreeStoreElem *tselem = reinterpret_cast<TreeStoreElem *>(tsep); + TreeStoreElem *tselem = static_cast<TreeStoreElem *>(tsep); if (ts && tselem) { TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem); @@ -737,7 +737,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) switch (tselem->type) { case TSE_DEFGROUP: { Object *ob = (Object *)tselem->id; - bDeformGroup *vg = reinterpret_cast<bDeformGroup *>(te->directdata); + bDeformGroup *vg = static_cast<bDeformGroup *>(te->directdata); BKE_object_defgroup_unique_name(vg, ob); WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name); break; @@ -752,7 +752,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) case TSE_EBONE: { bArmature *arm = (bArmature *)tselem->id; if (arm->edbo) { - EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + EditBone *ebone = static_cast<EditBone *>(te->directdata); char newname[sizeof(ebone->name)]; /* restore bone name */ @@ -770,7 +770,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) outliner_viewcontext_init(C, &tvc); bArmature *arm = (bArmature *)tselem->id; - Bone *bone = reinterpret_cast<Bone *>(te->directdata); + Bone *bone = static_cast<Bone *>(te->directdata); char newname[sizeof(bone->name)]; /* always make current object active */ @@ -790,7 +790,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) Object *ob = (Object *)tselem->id; bArmature *arm = (bArmature *)ob->data; - bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); char newname[sizeof(pchan->name)]; /* always make current pose-bone active */ @@ -801,15 +801,14 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) /* restore bone name */ BLI_strncpy(newname, pchan->name, sizeof(pchan->name)); BLI_strncpy(pchan->name, oldname, sizeof(pchan->name)); - ED_armature_bone_rename( - bmain, reinterpret_cast<bArmature *>(ob->data), oldname, newname); + ED_armature_bone_rename(bmain, static_cast<bArmature *>(ob->data), oldname, newname); WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); break; } case TSE_POSEGRP: { Object *ob = (Object *)tselem->id; /* id = object. */ - bActionGroup *grp = reinterpret_cast<bActionGroup *>(te->directdata); + bActionGroup *grp = static_cast<bActionGroup *>(te->directdata); BLI_uniquename(&ob->pose->agroups, grp, @@ -823,7 +822,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) } case TSE_GP_LAYER: { bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */ - bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata); + bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata); /* always make layer active */ BKE_gpencil_layer_active_set(gpd, gpl); @@ -839,7 +838,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) } case TSE_R_LAYER: { Scene *scene = (Scene *)tselem->id; - ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); /* Restore old name. */ char newname[sizeof(view_layer->name)]; @@ -991,7 +990,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene, { TreeStoreElem *tselem = TREESTORE(te); LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - reinterpret_cast<LayerCollection *>(te->directdata) : + static_cast<LayerCollection *>(te->directdata) : nullptr; Collection *collection = outliner_collection_from_tree_element(te); @@ -1105,7 +1104,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) { if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) { /* View layer render toggle. */ - ViewLayer *layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *layer = static_cast<ViewLayer *>(te->directdata); bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, @@ -1329,7 +1328,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, bPoseChannel *pchan = (bPoseChannel *)te->directdata; Bone *bone = pchan->bone; Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); @@ -1479,8 +1478,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) { LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - reinterpret_cast<LayerCollection *>( - te->directdata) : + static_cast<LayerCollection *>(te->directdata) : nullptr; Collection *collection = outliner_collection_from_tree_element(te); @@ -2499,7 +2497,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.drag_id = tselem->id; break; case TSE_CONSTRAINT: { - bConstraint *con = reinterpret_cast<bConstraint *>(te->directdata); + bConstraint *con = static_cast<bConstraint *>(te->directdata); data.drag_id = tselem->id; switch ((eBConstraint_Types)con->type) { case CONSTRAINT_TYPE_CAMERASOLVER: @@ -2616,9 +2614,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.drag_id = tselem->id; if (ob->type != OB_GPENCIL) { - ModifierData *md = reinterpret_cast<ModifierData *>( - BLI_findlink(&ob->modifiers, tselem->nr)); - const ModifierTypeInfo *modifier_type = reinterpret_cast<const ModifierTypeInfo *>( + ModifierData *md = static_cast<ModifierData *>(BLI_findlink(&ob->modifiers, tselem->nr)); + const ModifierTypeInfo *modifier_type = static_cast<const ModifierTypeInfo *>( BKE_modifier_get_info((ModifierType)md->type)); if (modifier_type != nullptr) { data.icon = modifier_type->icon; @@ -2629,7 +2626,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) } else { /* grease pencil modifiers */ - GpencilModifierData *md = reinterpret_cast<GpencilModifierData *>( + GpencilModifierData *md = static_cast<GpencilModifierData *>( BLI_findlink(&ob->greasepencil_modifiers, tselem->nr)); switch ((GpencilModifierType)md->type) { case eGpencilModifierType_Noise: @@ -2788,7 +2785,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) const PointerRNA &ptr = te_rna_struct->getPointerRNA(); if (RNA_struct_is_ID(ptr.type)) { - data.drag_id = reinterpret_cast<ID *>(ptr.data); + data.drag_id = static_cast<ID *>(ptr.data); data.icon = RNA_struct_ui_icon(ptr.type); } else { diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc index 32860bc2cff..f22db5d20fc 100644 --- a/source/blender/editors/space_outliner/outliner_edit.cc +++ b/source/blender/editors/space_outliner/outliner_edit.cc @@ -55,6 +55,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "GPU_material.h" @@ -597,9 +598,9 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); const short id_type = (short)RNA_enum_get(op->ptr, "id_type"); - ID *old_id = reinterpret_cast<ID *>( + ID *old_id = static_cast<ID *>( BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id"))); - ID *new_id = reinterpret_cast<ID *>( + ID *new_id = static_cast<ID *>( BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"))); /* check for invalid states */ @@ -693,9 +694,9 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C, int i = 0; short id_type = (short)RNA_enum_get(ptr, "id_type"); - ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first); + ID *id = static_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first); - for (; id; id = reinterpret_cast<ID *>(id->next)) { + for (; id; id = static_cast<ID *>(id->next)) { item_tmp.identifier = item_tmp.name = id->name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); @@ -1817,7 +1818,7 @@ static void tree_element_to_path(TreeElement *te, /* ptr->data not ptr->owner_id seems to be the one we want, * since ptr->data is sometimes the owner of this ID? */ if (RNA_struct_is_ID(ptr.type)) { - *id = reinterpret_cast<ID *>(ptr.data); + *id = static_cast<ID *>(ptr.data); /* clear path */ if (*path) { @@ -2052,8 +2053,7 @@ static KeyingSet *verify_active_keyingset(Scene *scene, short add) /* try to find one from scene */ if (scene->active_keyingset > 0) { - ks = reinterpret_cast<KeyingSet *>( - BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1)); + ks = static_cast<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1)); } /* Add if none found */ diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc index 877e0fc325c..31ae4aef7ff 100644 --- a/source/blender/editors/space_outliner/outliner_select.cc +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -220,7 +220,7 @@ static void tree_element_viewlayer_activate(bContext *C, TreeElement *te) return; } - ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); @@ -239,7 +239,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer, { Base *base; - for (base = reinterpret_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) { + for (base = static_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) { Object *ob = base->object; if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) { @@ -418,7 +418,7 @@ static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement scene->camera = ob; Main *bmain = CTX_data_main(C); - wmWindowManager *wm = reinterpret_cast<wmWindowManager *>(bmain->wm.first); + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); WM_windows_scene_data_sync(&wm->windows, scene); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); @@ -458,7 +458,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem) { bGPdata *gpd = (bGPdata *)tselem->id; - bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata); + bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata); /* We can only have a single "active" layer at a time * and there must always be an active layer... */ @@ -486,8 +486,8 @@ static void tree_element_posechannel_activate(bContext *C, bool recursive) { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); - bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + bArmature *arm = static_cast<bArmature *>(ob->data); + bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); if (!(pchan->bone->flag & BONE_HIDDEN_P)) { if (set != OL_SETSEL_EXTEND) { @@ -508,7 +508,7 @@ static void tree_element_posechannel_activate(bContext *C, } if (ob != ob_iter) { - DEG_id_tag_update(reinterpret_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); } } MEM_freeN(objects); @@ -541,14 +541,14 @@ static void tree_element_bone_activate(bContext *C, bool recursive) { bArmature *arm = (bArmature *)tselem->id; - Bone *bone = reinterpret_cast<Bone *>(te->directdata); + Bone *bone = static_cast<Bone *>(te->directdata); if (!(bone->flag & BONE_HIDDEN_P)) { Object *ob = OBACT(view_layer); if (ob) { if (set != OL_SETSEL_EXTEND) { /* single select forces all other bones to get unselected */ - for (Bone *bone_iter = reinterpret_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr; + for (Bone *bone_iter = static_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr; bone_iter = bone_iter->next) { bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); do_outliner_bone_select_recursive(arm, bone_iter, false); @@ -590,7 +590,7 @@ static void tree_element_ebone_activate(bContext *C, bool recursive) { bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + EditBone *ebone = static_cast<EditBone *>(te->directdata); if (set == OL_SETSEL_NORMAL) { if (!(ebone->flag & BONE_HIDDEN_A)) { @@ -703,7 +703,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED #if 0 select_single_seq(seq, 1); #endif - Sequence *p = reinterpret_cast<Sequence *>(ed->seqbasep->first); + Sequence *p = static_cast<Sequence *>(ed->seqbasep->first); while (p) { if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { p = p->next; @@ -722,7 +722,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED static void tree_element_master_collection_activate(const bContext *C) { ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + LayerCollection *layer_collection = static_cast<LayerCollection *>( view_layer->layer_collections.first); BKE_layer_collection_activate(view_layer, layer_collection); /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work @@ -733,7 +733,7 @@ static void tree_element_master_collection_activate(const bContext *C) static void tree_element_layer_collection_activate(bContext *C, TreeElement *te) { Scene *scene = CTX_data_scene(C); - LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(te->directdata); + LayerCollection *layer_collection = static_cast<LayerCollection *>(te->directdata); ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); BKE_layer_collection_activate(view_layer, layer_collection); /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work @@ -857,7 +857,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer, const TreeStoreElem *tselem) { const bArmature *arm = (const bArmature *)tselem->id; - const Bone *bone = reinterpret_cast<Bone *>(te->directdata); + const Bone *bone = static_cast<Bone *>(te->directdata); const Object *ob = OBACT(view_layer); if (ob && ob->data == arm) { if (bone->flag & BONE_SELECTED) { @@ -869,7 +869,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer, static eOLDrawState tree_element_ebone_state_get(const TreeElement *te) { - const EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + const EditBone *ebone = static_cast<EditBone *>(te->directdata); if (ebone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; } @@ -913,7 +913,7 @@ static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose, const TreeStoreElem *tselem) { const Object *ob = (const Object *)tselem->id; - const bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + const bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); if (ob == ob_pose && ob->pose) { if (pchan->bone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; @@ -929,7 +929,7 @@ static eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const Tr return OL_DRAWSEL_NONE; } - const ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + const ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); if (CTX_data_view_layer(C) == view_layer) { return OL_DRAWSEL_NORMAL; @@ -1229,7 +1229,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE /* Expand the selected constraint in the properties editor. */ if (tselem->type != TSE_CONSTRAINT_BASE) { - BKE_constraint_panel_expand(reinterpret_cast<bConstraint *>(te->directdata)); + BKE_constraint_panel_expand(static_cast<bConstraint *>(te->directdata)); } break; } @@ -1242,8 +1242,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE Object *ob = (Object *)tselem->id; if (ob->type == OB_GPENCIL) { - BKE_gpencil_modifier_panel_expand( - reinterpret_cast<GpencilModifierData *>(te->directdata)); + BKE_gpencil_modifier_panel_expand(static_cast<GpencilModifierData *>(te->directdata)); } else { ModifierData *md = (ModifierData *)te->directdata; @@ -1276,12 +1275,12 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE context = BCONTEXT_SHADERFX; if (tselem->type != TSE_GPENCIL_EFFECT_BASE) { - BKE_shaderfx_panel_expand(reinterpret_cast<ShaderFxData *>(te->directdata)); + BKE_shaderfx_panel_expand(static_cast<ShaderFxData *>(te->directdata)); } break; case TSE_BONE: { bArmature *arm = (bArmature *)tselem->id; - Bone *bone = reinterpret_cast<Bone *>(te->directdata); + Bone *bone = static_cast<Bone *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); context = BCONTEXT_BONE; @@ -1289,7 +1288,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_EBONE: { bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); + EditBone *ebone = static_cast<EditBone *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr); context = BCONTEXT_BONE; @@ -1297,8 +1296,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_POSE_CHANNEL: { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); - bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); + bArmature *arm = static_cast<bArmature *>(ob->data); + bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr); context = BCONTEXT_BONE; @@ -1306,7 +1305,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_POSE_BASE: { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); context = BCONTEXT_DATA; @@ -1314,7 +1313,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_R_LAYER_BASE: case TSE_R_LAYER: { - ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); + ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata); RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr); context = BCONTEXT_VIEW_LAYER; @@ -1323,7 +1322,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE case TSE_POSEGRP_BASE: case TSE_POSEGRP: { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); context = BCONTEXT_DATA; @@ -1823,7 +1822,7 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *space_o { while (te->subtree.last) { if (TSELEM_OPEN(TREESTORE(te), space_outliner)) { - te = reinterpret_cast<TreeElement *>(te->subtree.last); + te = static_cast<TreeElement *>(te->subtree.last); } else { break; @@ -1867,7 +1866,7 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr TreeStoreElem *tselem = TREESTORE(te); if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) { - te = reinterpret_cast<TreeElement *>(te->subtree.first); + te = static_cast<TreeElement *>(te->subtree.first); } else if (te->next) { te = te->next; @@ -1904,7 +1903,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner, /* Only walk down a level if the element is open and not toggling expand */ if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) { - te = reinterpret_cast<TreeElement *>(te->subtree.first); + te = static_cast<TreeElement *>(te->subtree.first); } else { outliner_item_openclose(space_outliner, te, true, toggle_all); @@ -1955,7 +1954,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner /* If no active element exists, use the first element in the tree */ if (!active_te) { - active_te = reinterpret_cast<TreeElement *>(space_outliner->tree.first); + active_te = static_cast<TreeElement *>(space_outliner->tree.first); *changed = true; } diff --git a/source/blender/editors/space_outliner/outliner_sync.cc b/source/blender/editors/space_outliner/outliner_sync.cc index 36bc7c31b91..772a5826f9f 100644 --- a/source/blender/editors/space_outliner/outliner_sync.cc +++ b/source/blender/editors/space_outliner/outliner_sync.cc @@ -77,8 +77,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); - for (bScreen *screen = reinterpret_cast<bScreen *>(bmain->screens.first); screen; - screen = reinterpret_cast<bScreen *>(screen->id.next)) { + for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen; + screen = static_cast<bScreen *>(screen->id.next)) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { if (sl->spacetype == SPACE_OUTLINER) { @@ -259,7 +259,7 @@ static void outliner_select_sync_to_pose_bone(TreeElement *te, GSet *selected_pbones) { Object *ob = (Object *)tselem->id; - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); bPoseChannel *pchan = (bPoseChannel *)te->directdata; short bone_flag = pchan->bone->flag; diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 87604818ee1..c408eca654c 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -856,7 +856,7 @@ static void id_override_library_create_hierarchy_pre_process_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); - OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; ID *id_root_reference = tselem->id; @@ -1160,7 +1160,7 @@ static void id_override_library_reset_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { @@ -1191,7 +1191,7 @@ static void id_override_library_resync_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce; if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { @@ -1637,7 +1637,7 @@ static void data_select_linked_fn(int event, const PointerRNA &ptr = te_rna_struct->getPointerRNA(); if (RNA_struct_is_ID(ptr.type)) { bContext *C = (bContext *)C_v; - ID *id = reinterpret_cast<ID *>(ptr.data); + ID *id = static_cast<ID *>(ptr.data); ED_object_select_linked_by_id(C, id); } @@ -1646,7 +1646,7 @@ static void data_select_linked_fn(int event, static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v) { - bContext *C = reinterpret_cast<bContext *>(C_v); + bContext *C = static_cast<bContext *>(C_v); Main *bmain = CTX_data_main(C); bConstraint *constraint = (bConstraint *)te->directdata; Object *ob = (Object *)outliner_search_back(te, ID_OB); @@ -1737,7 +1737,7 @@ static Base *outliner_batch_delete_hierarchy( } object = base->object; - for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base; + for (child_base = static_cast<Base *>(view_layer->object_bases.first); child_base; child_base = base_next) { base_next = child_base->next; for (parent = child_base->object->parent; parent && (parent != object); @@ -1960,7 +1960,7 @@ static void outliner_do_object_delete(bContext *C, static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void *customdata) { - ObjectEditData *data = reinterpret_cast<ObjectEditData *>(customdata); + ObjectEditData *data = static_cast<ObjectEditData *>(customdata); GSet *objects_to_delete = data->objects_set; TreeStoreElem *tselem = TREESTORE(te); @@ -2711,8 +2711,7 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op) get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); /* get action to use */ - act = reinterpret_cast<bAction *>( - BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"))); + act = static_cast<bAction *>(BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"))); if (act == nullptr) { BKE_report(op->reports, RPT_ERROR, "No valid action to add"); diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index aa739758ecb..49220762b65 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -90,7 +90,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) BLI_mempool_iter iter; BLI_mempool_iternew(ts, &iter); - while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { tselem->used = 0; } @@ -100,7 +100,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP; BLI_mempool_iternew(ts, &iter); - while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { if (tselem->id == nullptr) { unused++; } @@ -120,9 +120,9 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) BLI_mempool *new_ts = BLI_mempool_create( sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER); BLI_mempool_iternew(ts, &iter); - while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { if (tselem->id) { - tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts)); + tsenew = static_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts)); *tsenew = *tselem; } } @@ -151,7 +151,7 @@ static void check_persistent( sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); } if (space_outliner->runtime->treehash == nullptr) { - space_outliner->runtime->treehash = reinterpret_cast<GHash *>( + space_outliner->runtime->treehash = static_cast<GHash *>( BKE_outliner_treehash_create_from_treestore(space_outliner->treestore)); } @@ -166,7 +166,7 @@ static void check_persistent( } /* add 1 element to treestore */ - tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore)); + tselem = static_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore)); tselem->type = type; tselem->nr = type ? nr : 0; tselem->id = id; @@ -293,7 +293,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { - bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bArmature *arm = static_cast<bArmature *>(ob->data); TreeElement *tenla = outliner_add_element( space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0); tenla->name = IFACE_("Pose"); @@ -339,7 +339,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } } /* make hierarchy */ - TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first); + TreeElement *ten = static_cast<TreeElement *>(tenla->subtree.first); while (ten) { TreeElement *nten = ten->next, *par; tselem = TREESTORE(ten); @@ -694,15 +694,15 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, ebone->temp.p = ten; } /* make hierarchy */ - TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>( - ((EditBone *)arm->edbo->first)->temp.p) : - nullptr; + TreeElement *ten = arm->edbo->first ? + static_cast<TreeElement *>(((EditBone *)arm->edbo->first)->temp.p) : + nullptr; while (ten) { TreeElement *nten = ten->next, *par; EditBone *ebone = (EditBone *)ten->directdata; if (ebone->parent) { BLI_remlink(&te->subtree, ten); - par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p); + par = static_cast<TreeElement *>(ebone->parent->temp.p); BLI_addtail(&par->subtree, ten); ten->parent = par; } @@ -805,12 +805,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, short index, const bool expand) { - ID *id = reinterpret_cast<ID *>(idv); + ID *id = static_cast<ID *>(idv); if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { id = ((PointerRNA *)idv)->owner_id; if (!id) { - id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data); + id = static_cast<ID *>(((PointerRNA *)idv)->data); } } else if (type == TSE_GP_LAYER) { @@ -980,8 +980,8 @@ struct tTreeSort { /* alphabetical comparator, trying to put objects first */ static int treesort_alpha_ob(const void *v1, const void *v2) { - const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); - const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); + const tTreeSort *x1 = static_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = static_cast<const tTreeSort *>(v2); /* first put objects last (hierarchy) */ int comp = (x1->idcode == ID_OB); @@ -1019,8 +1019,8 @@ static int treesort_alpha_ob(const void *v1, const void *v2) /* Move children that are not in the collection to the end of the list. */ static int treesort_child_not_in_collection(const void *v1, const void *v2) { - const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); - const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); + const tTreeSort *x1 = static_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = static_cast<const tTreeSort *>(v2); /* Among objects first come the ones in the collection, followed by the ones not on it. * This way we can have the dashed lines in a separate style connecting the former. */ @@ -1033,8 +1033,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2) /* alphabetical comparator */ static int treesort_alpha(const void *v1, const void *v2) { - const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); - const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); + const tTreeSort *x1 = static_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = static_cast<const tTreeSort *>(v2); int comp = BLI_strcasecmp_natural(x1->name, x2->name); @@ -1091,7 +1091,7 @@ static int treesort_obtype_alpha(const void *v1, const void *v2) /* sort happens on each subtree individual */ static void outliner_sort(ListBase *lb) { - TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last); + TreeElement *last_te = static_cast<TreeElement *>(lb->last); if (last_te == nullptr) { return; } @@ -1103,7 +1103,7 @@ static void outliner_sort(ListBase *lb) int totelem = BLI_listbase_count(lb); if (totelem > 1) { - tTreeSort *tear = reinterpret_cast<tTreeSort *>( + tTreeSort *tear = static_cast<tTreeSort *>( MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array")); tTreeSort *tp = tear; int skip = 0; @@ -1159,7 +1159,7 @@ static void outliner_sort(ListBase *lb) static void outliner_collections_children_sort(ListBase *lb) { - TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last); + TreeElement *last_te = static_cast<TreeElement *>(lb->last); if (last_te == nullptr) { return; } @@ -1170,7 +1170,7 @@ static void outliner_collections_children_sort(ListBase *lb) int totelem = BLI_listbase_count(lb); if (totelem > 1) { - tTreeSort *tear = reinterpret_cast<tTreeSort *>( + tTreeSort *tear = static_cast<tTreeSort *>( MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array")); tTreeSort *tp = tear; @@ -1541,8 +1541,7 @@ static TreeElement *outliner_extract_children_from_subtree(TreeElement *element, if (outliner_element_is_collection_or_object(element)) { TreeElement *te_prev = nullptr; - for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te; - te = te_prev) { + for (TreeElement *te = static_cast<TreeElement *>(element->subtree.last); te; te = te_prev) { te_prev = te->prev; if (!outliner_element_is_collection_or_object(te)) { @@ -1569,7 +1568,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner, TreeElement *te, *te_next; TreeStoreElem *tselem; - for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) { + for (te = static_cast<TreeElement *>(lb->first); te; te = te_next) { te_next = te->next; if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { /* Don't free the tree, but extract the children from the parent and add to this tree. */ diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc index 0db612ce6db..d8c50cd04f9 100644 --- a/source/blender/editors/space_outliner/outliner_utils.cc +++ b/source/blender/editors/space_outliner/outliner_utils.cc @@ -98,7 +98,7 @@ static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement * float view_co_x, bool *r_is_merged_icon) { - TreeElement *child_te = reinterpret_cast<TreeElement *>(parent_te->subtree.first); + TreeElement *child_te = static_cast<TreeElement *>(parent_te->subtree.first); while (child_te) { const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend); @@ -282,8 +282,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner, TreeTraversalFunc func, void *customdata) { - for (TreeElement *te = reinterpret_cast<TreeElement *>(tree->first), *te_next; te; - te = te_next) { + for (TreeElement *te = static_cast<TreeElement *>(tree->first), *te_next; te; te = te_next) { TreeTraversalAction func_retval = TRAVERSE_CONTINUE; /* in case te is freed in callback */ TreeStoreElem *tselem = TREESTORE(te); diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc index 5bcd1edebc0..61bc3d35dfd 100644 --- a/source/blender/editors/space_outliner/space_outliner.cc +++ b/source/blender/editors/space_outliner/space_outliner.cc @@ -101,7 +101,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) ScrArea *area = params->area; ARegion *region = params->region; wmNotifier *wmn = params->notifier; - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); /* context changes */ switch (wmn->category) { @@ -264,7 +264,7 @@ static void outliner_main_region_message_subscribe(const wmRegionMessageSubscrib struct wmMsgBus *mbus = params->message_bus; ScrArea *area = params->area; ARegion *region = params->region; - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); wmMsgSubscribeValue msg_sub_value_region_tag_redraw{}; msg_sub_value_region_tag_redraw.owner = region; @@ -361,7 +361,7 @@ static void outliner_free(SpaceLink *sl) /* spacetype; init callback */ static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area) { - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); if (space_outliner->runtime == nullptr) { space_outliner->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_Runtime"); @@ -437,7 +437,7 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRe static void outliner_deactivate(struct ScrArea *area) { /* Remove hover highlights */ - SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); + SpaceOutliner *space_outliner = static_cast<SpaceOutliner *>(area->spacedata.first); outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY, false); ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); } diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc index 349d36e2fe6..e590b0c97d1 100644 --- a/source/blender/editors/space_outliner/tree/common.cc +++ b/source/blender/editors/space_outliner/tree/common.cc @@ -38,7 +38,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb) { /* build hierarchy */ /* XXX also, set extents here... */ - TreeElement *te = reinterpret_cast<TreeElement *>(lb->first); + TreeElement *te = static_cast<TreeElement *>(lb->first); while (te) { TreeElement *ten = te->next; TreeStoreElem *tselem = TREESTORE(te); diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 94d55b70e3c..7808c4a3c0f 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -54,7 +54,7 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i return TreeElementID::createFromID(legacy_te, *static_cast<ID *>(idv)); case TSE_ANIM_DATA: return std::make_unique<TreeElementAnimData>(legacy_te, - *reinterpret_cast<IdAdtTemplate *>(idv)->adt); + *static_cast<IdAdtTemplate *>(idv)->adt); case TSE_DRIVER_BASE: return std::make_unique<TreeElementDriverBase>(legacy_te, *static_cast<AnimData *>(idv)); case TSE_NLA: @@ -77,22 +77,20 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const i return std::make_unique<TreeElementOverridesProperty>( legacy_te, *static_cast<TreeElementOverridesData *>(idv)); case TSE_RNA_STRUCT: - return std::make_unique<TreeElementRNAStruct>(legacy_te, - *reinterpret_cast<PointerRNA *>(idv)); + return std::make_unique<TreeElementRNAStruct>(legacy_te, *static_cast<PointerRNA *>(idv)); case TSE_RNA_PROPERTY: return std::make_unique<TreeElementRNAProperty>( - legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index); + legacy_te, *static_cast<PointerRNA *>(idv), legacy_te.index); case TSE_RNA_ARRAY_ELEM: return std::make_unique<TreeElementRNAArrayElement>( - legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index); + legacy_te, *static_cast<PointerRNA *>(idv), legacy_te.index); case TSE_SEQUENCE: - return std::make_unique<TreeElementSequence>(legacy_te, *reinterpret_cast<Sequence *>(idv)); + return std::make_unique<TreeElementSequence>(legacy_te, *static_cast<Sequence *>(idv)); case TSE_SEQ_STRIP: - return std::make_unique<TreeElementSequenceStrip>(legacy_te, - *reinterpret_cast<Strip *>(idv)); + return std::make_unique<TreeElementSequenceStrip>(legacy_te, *static_cast<Strip *>(idv)); case TSE_SEQUENCE_DUP: - return std::make_unique<TreeElementSequenceStripDuplicate>( - legacy_te, *reinterpret_cast<Sequence *>(idv)); + return std::make_unique<TreeElementSequenceStripDuplicate>(legacy_te, + *static_cast<Sequence *>(idv)); default: break; } diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc index 914104f1f06..6dd5ec84041 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_rna.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc @@ -117,7 +117,7 @@ void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const for (int index = 0; index < tot; index++) { PointerRNA propptr; RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr); - if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) { + if (!(RNA_property_flag(static_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) { outliner_add_element( &space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index); } @@ -146,7 +146,7 @@ TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te, PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type); RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr); - PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data); + PropertyRNA *prop = static_cast<PropertyRNA *>(propptr.data); legacy_te_.name = RNA_property_ui_name(prop); rna_prop_ = prop; @@ -232,8 +232,7 @@ TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te, char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index); - legacy_te_.name = reinterpret_cast<char *>( - MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName")); + legacy_te_.name = static_cast<char *>(MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName")); if (c) { sprintf((char *)legacy_te_.name, " %c", c); } diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index ea35a8c0fa7..1b4acda9bcf 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -30,6 +30,7 @@ #include "UI_view2d.h" #include "RNA_access.h" +#include "RNA_path.h" #include "text_format.h" #include "text_intern.h" /* own include */ diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 479214ee2d3..6808f06bdd3 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -498,7 +498,8 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, const bool is_edited = (base->object->mode == OB_MODE_EDIT); const bool is_selectable = (base->flag & BASE_SELECTABLE); /* Get attributes of state. */ - const bool is_in_object_mode = (base_act == NULL) || (base_act->object->mode == OB_MODE_OBJECT); + const bool is_in_object_mode = (base_act == nullptr) || + (base_act->object->mode == OB_MODE_OBJECT); if (is_in_object_mode) { /* Handle target selection options that make sense for object mode. */ diff --git a/source/blender/editors/undo/CMakeLists.txt b/source/blender/editors/undo/CMakeLists.txt index 284b725cdf0..271d05e9c04 100644 --- a/source/blender/editors/undo/CMakeLists.txt +++ b/source/blender/editors/undo/CMakeLists.txt @@ -11,6 +11,7 @@ set(INC ../../windowmanager ../../../../intern/clog ../../../../intern/guardedalloc + ../../bmesh ) set(SRC diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c index 9a31fd6469d..2afc60a4b5c 100644 --- a/source/blender/editors/uvedit/uvedit_islands.c +++ b/source/blender/editors/uvedit/uvedit_islands.c @@ -309,23 +309,8 @@ static float uv_nearest_grid_tile_distance(const int udim_grid[2], /* -------------------------------------------------------------------- */ /** \name Calculate UV Islands - * - * \note Currently this is a private API/type, it could be made public. * \{ */ -struct FaceIsland { - struct FaceIsland *next, *prev; - BMFace **faces; - int faces_len; - rctf bounds_rect; - /** - * \note While this is duplicate information, - * it allows islands from multiple meshes to be stored in the same list. - */ - uint cd_loop_uv_offset; - float aspect_y; -}; - struct SharedUVLoopData { uint cd_loop_uv_offset; bool use_seams; @@ -347,14 +332,14 @@ static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, v /** * Calculate islands and add them to \a island_list returning the number of items added. */ -static int bm_mesh_calc_uv_islands(const Scene *scene, - BMesh *bm, - ListBase *island_list, - const bool only_selected_faces, - const bool only_selected_uvs, - const bool use_seams, - const float aspect_y, - const uint cd_loop_uv_offset) +int bm_mesh_calc_uv_islands(const Scene *scene, + BMesh *bm, + ListBase *island_list, + const bool only_selected_faces, + const bool only_selected_uvs, + const bool use_seams, + const float aspect_y, + const uint cd_loop_uv_offset) { int island_added = 0; BM_mesh_elem_table_ensure(bm, BM_FACE); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index d59dcb4f4ed..b1ed00e2c57 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -81,6 +81,7 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, typedef enum { UV_SSIM_AREA_UV = 1000, UV_SSIM_AREA_3D, + UV_SSIM_FACE, UV_SSIM_LENGTH_UV, UV_SSIM_LENGTH_3D, UV_SSIM_SIDES, @@ -4638,6 +4639,33 @@ static float get_uv_face_needle(const eUVSelectSimilar type, return result; } +static float get_uv_island_needle(const eUVSelectSimilar type, + const struct FaceIsland *island, + const float ob_m3[3][3], + const int cd_loop_uv_offset) + +{ + float result = 0.0f; + switch (type) { + case UV_SSIM_AREA_UV: + for (int i = 0; i < island->faces_len; i++) { + result += BM_face_calc_area_uv(island->faces[i], cd_loop_uv_offset); + } + break; + case UV_SSIM_AREA_3D: + for (int i = 0; i < island->faces_len; i++) { + result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3); + } + break; + case UV_SSIM_FACE: + return island->faces_len; + default: + BLI_assert_unreachable(); + return false; + } + return result; +} + static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -4969,6 +4997,136 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool uv_island_selected(const Scene *scene, struct FaceIsland *island) +{ + BLI_assert(island && island->faces_len); + return uvedit_face_select_test(scene, island->faces[0], island->cd_loop_uv_offset); +} + +static int uv_select_similar_island_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__); + int island_list_len = 0; + + const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + + float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */ + island_list_len += bm_mesh_calc_uv_islands(scene, + em->bm, + &island_list_ptr[ob_index], + face_selected, + false, + false, + aspect_y, + cd_loop_uv_offset); + } + + struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len, + __func__); + + int tree_index = 0; + KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + + float ob_m3[3][3]; + copy_m3_m4(ob_m3, obedit->obmat); + + int index; + LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { + island_array[index] = island; + if (!uv_island_selected(scene, island)) { + continue; + } + float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); + if (tree_1d) { + BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); + } + } + } + + if (tree_1d != NULL) { + BLI_kdtree_1d_deduplicate(tree_1d); + BLI_kdtree_1d_balance(tree_1d); + } + + int tot_island_index = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + float ob_m3[3][3]; + copy_m3_m4(ob_m3, obedit->obmat); + + bool changed = false; + int index; + LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { + island_array[tot_island_index++] = island; /* To deallocate later. */ + if (uv_island_selected(scene, island)) { + continue; + } + float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); + bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); + if (!select) { + continue; + } + bool do_history = false; + for (int j = 0; j < island->faces_len; j++) { + uvedit_face_select_set( + scene, em, island->faces[j], select, do_history, island->cd_loop_uv_offset); + } + changed = true; + } + + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + + BLI_assert(tot_island_index == island_list_len); + for (int i = 0; i < island_list_len; i++) { + MEM_SAFE_FREE(island_array[i]->faces); + MEM_SAFE_FREE(island_array[i]); + } + + MEM_SAFE_FREE(island_array); + MEM_SAFE_FREE(island_list_ptr); + MEM_SAFE_FREE(objects); + BLI_kdtree_1d_free(tree_1d); + + return OPERATOR_FINISHED; +} + /* Select similar UV faces/edges/verts based on current selection. */ static int uv_select_similar_exec(bContext *C, wmOperator *op) { @@ -4990,7 +5148,7 @@ static int uv_select_similar_exec(bContext *C, wmOperator *op) return uv_select_similar_face_exec(C, op); } if (selectmode & UV_SELECT_ISLAND) { - // return uv_select_similar_island_exec(C, op); + return uv_select_similar_island_exec(C, op); } return uv_select_similar_vert_exec(C, op); @@ -5011,6 +5169,12 @@ static EnumPropertyItem prop_face_similar_types[] = { {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""}, {0}}; +static EnumPropertyItem prop_island_similar_types[] = { + {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""}, + {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""}, + {UV_SSIM_FACE, "FACE", 0, "Amount of Faces in Island", ""}, + {0}}; + static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, {SIM_CMP_LT, "LESS", 0, "Less", ""}, @@ -5030,6 +5194,9 @@ static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C, if (selectmode & UV_SELECT_FACE) { return prop_face_similar_types; } + if (selectmode & UV_SELECT_ISLAND) { + return prop_island_similar_types; + } } return prop_vert_similar_types; diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.c index 38924c718c3..7e9c879106a 100644 --- a/source/blender/geometry/intern/uv_parametrizer.c +++ b/source/blender/geometry/intern/uv_parametrizer.c @@ -51,7 +51,6 @@ typedef struct PVert { union PVertUnion { PHashKey key; /* Construct. */ int id; /* ABF/LSCM matrix index. */ - float distortion; /* Area smoothing. */ HeapNode *heaplink; /* Edge collapsing. */ } u; @@ -153,14 +152,9 @@ typedef struct PChart { } pack; } u; - uchar flag; - ParamHandle *handle; + bool has_pins; } PChart; -enum PChartFlag { - PCHART_HAS_PINS = 1, -}; - enum PHandleState { PHANDLE_STATE_ALLOCATED, PHANDLE_STATE_CONSTRUCTED, @@ -225,8 +219,10 @@ static PHash *phash_new(PHashLink **list, int sizehint) static void phash_delete(PHash *ph) { - MEM_freeN(ph->buckets); - MEM_freeN(ph); + if (ph) { + MEM_SAFE_FREE(ph->buckets); + } + MEM_SAFE_FREE(ph); } static int phash_size(PHash *ph) @@ -670,9 +666,9 @@ static PVert *p_vert_lookup(ParamHandle *handle, PHashKey key, const float co[3] return p_vert_add(handle, key, co, e); } -static PVert *p_vert_copy(PChart *chart, PVert *v) +static PVert *p_vert_copy(ParamHandle *handle, PVert *v) { - PVert *nv = (PVert *)BLI_memarena_alloc(chart->handle->arena, sizeof(*nv)); + PVert *nv = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*nv)); copy_v3_v3(nv->co, v->co); nv->uv[0] = v->uv[0]; @@ -727,20 +723,6 @@ static int p_face_exists(ParamHandle *handle, const ParamKey *pvkeys, int i1, in return false; } -static PChart *p_chart_new(ParamHandle *handle) -{ - PChart *chart = (PChart *)MEM_callocN(sizeof(*chart), "PChart"); - chart->handle = handle; - - return chart; -} - -static void p_chart_delete(PChart *chart) -{ - /* the actual links are free by memarena */ - MEM_freeN(chart); -} - static bool p_edge_implicit_seam(PEdge *e, PEdge *ep) { float *uv1, *uv2, *uvp1, *uvp2; @@ -898,14 +880,14 @@ static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs) return ncharts; } -static void p_split_vert(PChart *chart, PEdge *e) +static void p_split_vert(ParamHandle *handle, PChart *chart, PEdge *e) { PEdge *we, *lastwe = NULL; PVert *v = e->vert; bool copy = true; if (e->flag & PEDGE_PIN) { - chart->flag |= PCHART_HAS_PINS; + chart->has_pins = true; } if (e->flag & PEDGE_VERTEX_SPLIT) { @@ -938,7 +920,7 @@ static void p_split_vert(PChart *chart, PEdge *e) if (copy) { /* not found, copying */ v->flag |= PVERT_SPLIT; - v = p_vert_copy(chart, v); + v = p_vert_copy(handle, v); v->flag |= PVERT_SPLIT; v->nextlink = chart->verts; @@ -957,12 +939,11 @@ static void p_split_vert(PChart *chart, PEdge *e) static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts) { - PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"), *nchart; + PChart **charts = MEM_mallocN(sizeof(*charts) * ncharts, "PCharts"); PFace *f, *nextf; - int i; - for (i = 0; i < ncharts; i++) { - charts[i] = p_chart_new(handle); + for (int i = 0; i < ncharts; i++) { + charts[i] = (PChart *)MEM_callocN(sizeof(*chart), "PChart"); } f = chart->faces; @@ -970,7 +951,7 @@ static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts) PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; nextf = f->nextlink; - nchart = charts[f->u.chart]; + PChart *nchart = charts[f->u.chart]; f->nextlink = nchart->faces; nchart->faces = f; @@ -984,9 +965,9 @@ static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts) nchart->nfaces++; nchart->nedges += 3; - p_split_vert(nchart, e1); - p_split_vert(nchart, e2); - p_split_vert(nchart, e3); + p_split_vert(handle, nchart, e1); + p_split_vert(handle, nchart, e2); + p_split_vert(handle, nchart, e3); f = nextf; } @@ -1086,9 +1067,9 @@ static PFace *p_face_add_construct(ParamHandle *handle, return f; } -static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3) +static PFace *p_face_add_fill(ParamHandle *handle, PChart *chart, PVert *v1, PVert *v2, PVert *v3) { - PFace *f = p_face_add(chart->handle); + PFace *f = p_face_add(handle); PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; e1->vert = v1; @@ -1202,7 +1183,7 @@ static float p_edge_boundary_angle(PEdge *e) return angle; } -static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) +static void p_chart_fill_boundary(ParamHandle *handle, PChart *chart, PEdge *be, int nedges) { PEdge *e, *e1, *e2; @@ -1243,7 +1224,7 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) e->flag |= PEDGE_FILLED; e1->flag |= PEDGE_FILLED; - f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert); + f = p_face_add_fill(handle, chart, e->vert, e1->vert, e2->vert); f->flag |= PFACE_FILLED; ne = f->edge->next->next; @@ -1279,7 +1260,7 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges) BLI_heap_free(heap, NULL); } -static void p_chart_fill_boundaries(PChart *chart, PEdge *outer) +static void p_chart_fill_boundaries(ParamHandle *handle, PChart *chart, PEdge *outer) { PEdge *e, *be; /* *enext - as yet unused */ int nedges; @@ -1300,7 +1281,7 @@ static void p_chart_fill_boundaries(PChart *chart, PEdge *outer) } while (be != e); if (e != outer) { - p_chart_fill_boundary(chart, e, nedges); + p_chart_fill_boundary(handle, chart, e, nedges); } } } @@ -3709,8 +3690,8 @@ static void p_chart_rotate_fit_aabb(PChart *chart) ParamHandle *GEO_uv_parametrizer_construct_begin(void) { - ParamHandle *handle = MEM_callocN(sizeof(*handle), "ParamHandle"); - handle->construction_chart = p_chart_new(handle); + ParamHandle *handle = (ParamHandle *)MEM_callocN(sizeof(*handle), "ParamHandle"); + handle->construction_chart = (PChart *)MEM_callocN(sizeof(PChart), "PChart"); handle->state = PHANDLE_STATE_ALLOCATED; handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena"); handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena"); @@ -3733,12 +3714,10 @@ void GEO_uv_parametrizer_aspect_ratio(ParamHandle *phandle, float aspx, float as void GEO_uv_parametrizer_delete(ParamHandle *phandle) { - int i; - param_assert(ELEM(phandle->state, PHANDLE_STATE_ALLOCATED, PHANDLE_STATE_CONSTRUCTED)); - for (i = 0; i < phandle->ncharts; i++) { - p_chart_delete(phandle->charts[i]); + for (int i = 0; i < phandle->ncharts; i++) { + MEM_SAFE_FREE(phandle->charts[i]); } MEM_SAFE_FREE(phandle->charts); @@ -3748,13 +3727,11 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle) phandle->pin_hash = NULL; } - if (phandle->construction_chart) { - p_chart_delete(phandle->construction_chart); + MEM_SAFE_FREE(phandle->construction_chart); - phash_delete(phandle->hash_verts); - phash_delete(phandle->hash_edges); - phash_delete(phandle->hash_faces); - } + phash_delete(phandle->hash_verts); + phash_delete(phandle->hash_edges); + phash_delete(phandle->hash_faces); BLI_memarena_free(phandle->arena); BLI_memarena_free(phandle->polyfill_arena); @@ -3957,8 +3934,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, phandle->ncharts = p_connect_pairs(phandle, topology_from_uvs); phandle->charts = p_split_charts(phandle, chart, phandle->ncharts); - p_chart_delete(phandle->construction_chart); - phandle->construction_chart = NULL; + MEM_SAFE_FREE(phandle->construction_chart); phash_delete(phandle->hash_verts); phash_delete(phandle->hash_edges); @@ -3972,7 +3948,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, p_chart_boundaries(chart, &outer); if (!topology_from_uvs && chart->nboundaries == 0) { - p_chart_delete(chart); + MEM_SAFE_FREE(chart); if (count_fail != NULL) { *count_fail += 1; } @@ -3983,7 +3959,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle, j++; if (fill && (chart->nboundaries > 1)) { - p_chart_fill_boundaries(chart, outer); + p_chart_fill_boundaries(phandle, chart, outer); } for (v = chart->verts; v; v = v->nextlink) { @@ -4025,7 +4001,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in if (chart->u.lscm.context) { const bool result = p_chart_lscm_solve(phandle, chart); - if (result && !(chart->flag & PCHART_HAS_PINS)) { + if (result && !chart->has_pins) { p_chart_rotate_minimum_area(chart); } else if (result && chart->u.lscm.single_pin) { @@ -4033,7 +4009,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in p_chart_lscm_transform_single_pin(chart); } - if (!result || !(chart->flag & PCHART_HAS_PINS)) { + if (!result || !chart->has_pins) { p_chart_lscm_end(chart); } @@ -4133,7 +4109,7 @@ static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pi for (i = 0; i < phandle->ncharts; i++) { chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { continue; } @@ -4174,7 +4150,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle, for (i = 0; i < handle->ncharts; i++) { chart = handle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { unpacked++; continue; } @@ -4190,7 +4166,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle, box->w = chart->u.pack.size[0] + trans[0]; box->h = chart->u.pack.size[1] + trans[1]; - box->index = i; /* warning this index skips PCHART_HAS_PINS boxes */ + box->index = i; /* Warning this index skips chart->has_pins boxes. */ if (margin > 0.0f) { area += (double)sqrtf(box->w * box->h); @@ -4207,7 +4183,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle, for (i = 0; i < handle->ncharts; i++) { chart = handle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { unpacked++; continue; } @@ -4264,7 +4240,7 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle, for (i = 0; i < phandle->ncharts; i++) { chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { continue; } @@ -4367,7 +4343,7 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle, for (i = 0; i < phandle->ncharts; i++) { chart = phandle->charts[i]; - if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { + if (ignore_pinned && chart->has_pins) { continue; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c index 41015c429fe..aa9c654aa7e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c @@ -270,7 +270,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, } static void segment_list_item(struct uiList *UNUSED(ui_list), - struct bContext *UNUSED(C), + const struct bContext *UNUSED(C), struct uiLayout *layout, struct PointerRNA *UNUSED(idataptr), struct PointerRNA *itemptr, diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5e97909a2b8..2de0f4e470a 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -456,6 +456,7 @@ set(SRC_SHADER_CREATE_INFOS ../draw/engines/basic/shaders/infos/basic_depth_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh + ../draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh ../draw/engines/gpencil/shaders/infos/gpencil_info.hh ../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 3ca465fa57a..12a7cf49f9d 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -121,6 +121,7 @@ typedef struct GPUCodegenOutput { char *surface; char *volume; char *thickness; + char *composite; char *material_functions; GPUShaderCreateInfo *create_info; @@ -178,6 +179,8 @@ void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link); void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash); +void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link); + /** * Wrap a part of the material graph into a function. You need then need to call the function by * using something like #GPU_differentiate_float_function. @@ -218,6 +221,7 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene, void *thunk); void GPU_material_compile(GPUMaterial *mat); +void GPU_material_free_single(GPUMaterial *material); void GPU_material_free(struct ListBase *gpumaterial); void GPU_material_acquire(GPUMaterial *mat); @@ -319,6 +323,16 @@ struct GHash *GPU_uniform_attr_list_hash_new(const char *info); void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, GPUUniformAttrList *src); void GPU_uniform_attr_list_free(GPUUniformAttrList *set); +/* A callback passed to GPU_material_from_callbacks to construct the material graph by adding and + * linking the necessary GPU material nodes. */ +typedef void (*ConstructGPUMaterialFn)(void *thunk, GPUMaterial *material); + +/* Construct a GPU material from a set of callbacks. See the callback types for more information. + * The given thunk will be passed as the first parameter of each callback. */ +GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb, + GPUCodegenCallbackFn generate_code_function_cb, + void *thunk); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 3460d33fe68..c154f1adc8b 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -177,7 +177,9 @@ void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, fl void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]); void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]); void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]); +void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2]); void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]); +void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3]); void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]); void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]); diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 82441c3c89c..4a45a3e63ed 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -280,6 +280,7 @@ class GPUCodegen { void node_serialize(std::stringstream &eval_ss, const GPUNode *node); char *graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link); + char *graph_serialize(eGPUNodeTag tree_tag); static char *extract_c_str(std::stringstream &stream) { @@ -500,6 +501,19 @@ char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link return eval_c_str; } +char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag) +{ + std::stringstream eval_ss; + LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) { + if (node->tag & tree_tag) { + node_serialize(eval_ss, node); + } + } + char *eval_c_str = extract_c_str(eval_ss); + BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size()); + return eval_c_str; +} + void GPUCodegen::generate_uniform_buffer() { /* Extract uniform inputs. */ @@ -539,6 +553,9 @@ void GPUCodegen::generate_graphs() output.volume = graph_serialize(GPU_NODE_TAG_VOLUME, graph.outlink_volume); output.displacement = graph_serialize(GPU_NODE_TAG_DISPLACEMENT, graph.outlink_displacement); output.thickness = graph_serialize(GPU_NODE_TAG_THICKNESS, graph.outlink_thickness); + if (!BLI_listbase_is_empty(&graph.outlink_compositor)) { + output.composite = graph_serialize(GPU_NODE_TAG_COMPOSITOR); + } if (!BLI_listbase_is_empty(&graph.material_functions)) { std::stringstream eval_ss; @@ -569,9 +586,10 @@ GPUPass *GPU_generate_pass(GPUMaterial *material, GPUCodegenCallbackFn finalize_source_cb, void *thunk) { - /* Prune the unused nodes and extract attributes before compiling so the - * generated VBOs are ready to accept the future shader. */ gpu_node_graph_prune_unused(graph); + + /* Extract attributes before compiling so the generated VBOs are ready to accept the future + * shader. */ gpu_node_graph_finalize_uniform_attrs(graph); GPUCodegen codegen(material, graph); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 4d3ea3e0c99..a4842ef0e43 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -141,7 +141,7 @@ static void gpu_material_ramp_texture_build(GPUMaterial *mat) mat->coba_builder = NULL; } -static void gpu_material_free_single(GPUMaterial *material) +void GPU_material_free_single(GPUMaterial *material) { bool do_free = atomic_sub_and_fetch_uint32(&material->refcount, 1) == 0; if (!do_free) { @@ -173,7 +173,7 @@ void GPU_material_free(ListBase *gpumaterial) LISTBASE_FOREACH (LinkData *, link, gpumaterial) { GPUMaterial *material = link->data; DRW_deferred_shader_remove(material); - gpu_material_free_single(material); + GPU_material_free_single(material); } BLI_freelistN(gpumaterial); } @@ -538,6 +538,13 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, BLI_addtail(&material->graph.outlink_aovs, aov_link); } +void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link) +{ + GPUNodeGraphOutputLink *compositor_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__); + compositor_link->outlink = link; + BLI_addtail(&material->graph.outlink_compositor, compositor_link); +} + char *GPU_material_split_sub_function(GPUMaterial *material, eGPUType return_type, GPUNodeLink **link) @@ -721,7 +728,7 @@ void GPU_material_acquire(GPUMaterial *mat) void GPU_material_release(GPUMaterial *mat) { - gpu_material_free_single(mat); + GPU_material_free_single(mat); } void GPU_material_compile(GPUMaterial *mat) @@ -772,3 +779,42 @@ void GPU_materials_free(Main *bmain) // BKE_world_defaults_free_gpu(); BKE_material_defaults_free_gpu(); } + +GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb, + GPUCodegenCallbackFn generate_code_function_cb, + void *thunk) +{ + /* Allocate a new material and its material graph, and initialize its reference count. */ + GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); + material->graph.used_libraries = BLI_gset_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); + material->refcount = 1; + + /* Construct the material graph by adding and linking the necessary GPU material nodes. */ + construct_function_cb(thunk, material); + + /* Create and initialize the texture storing color bands used by Ramp and Curve nodes. */ + gpu_material_ramp_texture_build(material); + + /* Lookup an existing pass in the cache or generate a new one. */ + material->pass = GPU_generate_pass(material, &material->graph, generate_code_function_cb, thunk); + + /* The pass already exists in the pass cache but its shader already failed to compile. */ + if (material->pass == NULL) { + material->status = GPU_MAT_FAILED; + gpu_node_graph_free(&material->graph); + return material; + } + + /* The pass already exists in the pass cache and its shader is already compiled. */ + GPUShader *shader = GPU_pass_shader_get(material->pass); + if (shader != NULL) { + material->status = GPU_MAT_SUCCESS; + gpu_node_graph_free_nodes(&material->graph); + return material; + } + + /* The material was created successfully but still needs to be compiled. */ + material->status = GPU_MAT_CREATED; + return material; +} diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 684070dbdc0..c7b2fde492f 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -75,9 +75,26 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType if (STR_ELEM(name, "set_value", "set_rgb", "set_rgba") && (input->type == type)) { input = MEM_dupallocN(outnode->inputs.first); + + switch (input->source) { + case GPU_SOURCE_ATTR: + input->attr->users++; + break; + case GPU_SOURCE_UNIFORM_ATTR: + input->uniform_attr->users++; + break; + case GPU_SOURCE_TEX: + case GPU_SOURCE_TEX_TILED_MAPPING: + input->texture->users++; + break; + default: + break; + } + if (input->link) { input->link->users++; } + BLI_addtail(&node->inputs, input); return; } @@ -179,35 +196,21 @@ static GPUNodeLink *gpu_uniformbuffer_link(GPUMaterial *mat, BLI_assert(socket != NULL); BLI_assert(socket->in_out == in_out); - if ((socket->flag & SOCK_HIDE_VALUE) == 0) { - GPUNodeLink *link; - switch (socket->type) { - case SOCK_FLOAT: { - bNodeSocketValueFloat *socket_data = socket->default_value; - link = GPU_uniform(&socket_data->value); - break; - } - case SOCK_VECTOR: { - bNodeSocketValueVector *socket_data = socket->default_value; - link = GPU_uniform(socket_data->value); - break; - } - case SOCK_RGBA: { - bNodeSocketValueRGBA *socket_data = socket->default_value; - link = GPU_uniform(socket_data->value); - break; - } - default: - return NULL; - break; - } + if (socket->flag & SOCK_HIDE_VALUE) { + return NULL; + } - if (in_out == SOCK_IN) { - GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); - } - return link; + if (!ELEM(socket->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA)) { + return NULL; + } + + GPUNodeLink *link = GPU_uniform(stack->vec); + + if (in_out == SOCK_IN) { + GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); } - return NULL; + + return link; } static void gpu_node_input_socket( @@ -803,6 +806,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph) { BLI_freelistN(&graph->outlink_aovs); BLI_freelistN(&graph->material_functions); + BLI_freelistN(&graph->outlink_compositor); gpu_node_graph_free_nodes(graph); BLI_freelistN(&graph->textures); @@ -855,6 +859,9 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph) LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, funclink, &graph->material_functions) { gpu_nodes_tag(funclink->outlink, GPU_NODE_TAG_FUNCTION); } + LISTBASE_FOREACH (GPUNodeGraphOutputLink *, compositor_link, &graph->outlink_compositor) { + gpu_nodes_tag(compositor_link->outlink, GPU_NODE_TAG_COMPOSITOR); + } for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) { next = node->next; diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index ae472d5b7aa..08ff8bbef58 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -59,6 +59,7 @@ typedef enum { GPU_NODE_TAG_THICKNESS = (1 << 3), GPU_NODE_TAG_AOV = (1 << 4), GPU_NODE_TAG_FUNCTION = (1 << 5), + GPU_NODE_TAG_COMPOSITOR = (1 << 6), } eGPUNodeTag; ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION) @@ -158,6 +159,8 @@ typedef struct GPUNodeGraph { ListBase outlink_aovs; /* List of GPUNodeGraphFunctionLink */ ListBase material_functions; + /* List of GPUNodeGraphOutputLink */ + ListBase outlink_compositor; /* Requested attributes and textures. */ ListBase attributes; diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index fe9aacb95f9..8a630d9e3ca 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -7,6 +7,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_math_matrix.h" #include "BLI_string_utils.h" #include "GPU_capabilities.h" @@ -382,6 +383,8 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) sources.append(resources.c_str()); sources.append(layout.c_str()); sources.extend(code); + sources.extend(info.dependencies_generated); + sources.append(info.compute_source_generated.c_str()); shader->compute_shader_from_glsl(sources); } @@ -702,12 +705,25 @@ void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4] GPU_shader_uniform_vector(sh, loc, 4, 1, data); } +void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2]) +{ + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector_int(sh, loc, 2, 1, data); +} + void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]) { const int loc = GPU_shader_get_uniform(sh, name); GPU_shader_uniform_vector(sh, loc, 16, 1, (const float *)data); } +void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3]) +{ + float matrix[4][4]; + copy_m4_m3(matrix, data); + GPU_shader_uniform_mat4(sh, name, matrix); +} + void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]) { const int loc = GPU_shader_get_uniform(sh, name); diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index 8e05412d0ee..fb8efbb209a 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -298,6 +298,7 @@ struct ShaderCreateInfo { /** Manually set generated code. */ std::string vertex_source_generated = ""; std::string fragment_source_generated = ""; + std::string compute_source_generated = ""; std::string geometry_source_generated = ""; std::string typedef_source_generated = ""; /** Manually set generated dependencies. */ @@ -818,6 +819,7 @@ struct ShaderCreateInfo { TEST_EQUAL(*this, b, builtins_); TEST_EQUAL(*this, b, vertex_source_generated); TEST_EQUAL(*this, b, fragment_source_generated); + TEST_EQUAL(*this, b, compute_source_generated); TEST_EQUAL(*this, b, typedef_source_generated); TEST_VECTOR_EQUAL(*this, b, vertex_inputs_); TEST_EQUAL(*this, b, geometry_layout_); diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc index d91e15243f3..aff7df9ac33 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency.cc +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -593,7 +593,8 @@ struct GPUSource { bool is_from_material_library() const { return (filename.startswith("gpu_shader_material_") || - filename.startswith("gpu_shader_common_")) && + filename.startswith("gpu_shader_common_") || + filename.startswith("gpu_shader_compositor_")) && filename.endswith(".glsl"); } }; diff --git a/source/blender/io/collada/BCAnimationCurve.cpp b/source/blender/io/collada/BCAnimationCurve.cpp index 04a7a81c0a6..fe90dc5d5fa 100644 --- a/source/blender/io/collada/BCAnimationCurve.cpp +++ b/source/blender/io/collada/BCAnimationCurve.cpp @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2008 Blender Foundation. All rights reserved. */ +#include "RNA_path.h" + #include "BCAnimationCurve.h" BCAnimationCurve::BCAnimationCurve() diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index a32fd90594d..8594603867f 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -13,6 +13,7 @@ #include "obj_import_file_reader.hh" #include "obj_import_string_utils.hh" +#include <algorithm> #include <charconv> namespace blender::io::obj { @@ -394,6 +395,23 @@ static bool parse_keyword(const char *&p, const char *end, StringRef keyword) return true; } +/* Special case: if there were no faces/edges in any geometries, + * treat all the vertices as a point cloud. */ +static void use_all_vertices_if_no_faces(Geometry *geom, + const Vector<std::unique_ptr<Geometry>> &all_geometries, + const GlobalVertices &global_vertices) +{ + if (!global_vertices.vertices.is_empty() && geom && geom->geom_type_ == GEOM_MESH) { + if (std::all_of( + all_geometries.begin(), all_geometries.end(), [](const std::unique_ptr<Geometry> &g) { + return g->get_vertex_count() == 0; + })) { + geom->track_vertex_index(0); + geom->track_vertex_index(global_vertices.vertices.size() - 1); + } + } +} + void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, GlobalVertices &r_global_vertices) { @@ -571,6 +589,7 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, buffer_offset = left_size; } + use_all_vertices_if_no_faces(curr_geom, r_all_geometries, r_global_vertices); add_default_mtl_library(); } diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc index 60e419728f3..f7685ba0b7b 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc @@ -65,7 +65,7 @@ static bool load_texture_image_at_path(Main *bmain, bNode *r_node, const std::string &path) { - Image *tex_image = BKE_image_load(bmain, path.c_str()); + Image *tex_image = BKE_image_load_exists(bmain, path.c_str()); if (!tex_image) { fprintf(stderr, "Cannot load image file: '%s'\n", path.c_str()); return false; diff --git a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc index 9a457167fca..7e282b164b0 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc @@ -41,12 +41,14 @@ void fixup_line_continuations(char *p, char *end) while (true) { /* Find next backslash, if any. */ char *backslash = std::find(p, end, '\\'); - if (backslash == end) + if (backslash == end) { break; + } /* Skip over possible whitespace right after it. */ p = backslash + 1; - while (p < end && is_whitespace(*p) && *p != '\n') + while (p < end && is_whitespace(*p) && *p != '\n') { ++p; + } /* If then we have a newline, turn both backslash * and the newline into regular spaces. */ if (p < end && *p == '\n') { diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index c59269f5a7d..ecf1243fa86 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -47,7 +47,8 @@ class obj_importer_test : public BlendfileLoadingBaseTest { void import_and_check(const char *path, const Expectation *expect, size_t expect_count, - int expect_mat_count) + int expect_mat_count, + int expect_image_count = 0) { if (!blendfile_load("io_tests/blend_geometry/all_quads.blend")) { ADD_FAILURE(); @@ -132,12 +133,12 @@ class obj_importer_test : public BlendfileLoadingBaseTest { DEG_OBJECT_ITER_END; EXPECT_EQ(object_index, expect_count); - /* Count number of materials. */ - int mat_count = 0; - LISTBASE_FOREACH (ID *, id, &bfile->main->materials) { - ++mat_count; - } + /* Check number of materials & textures. */ + const int mat_count = BLI_listbase_count(&bfile->main->materials); EXPECT_EQ(mat_count, expect_mat_count); + + const int ima_count = BLI_listbase_count(&bfile->main->images); + EXPECT_EQ(ima_count, expect_image_count); } }; @@ -306,7 +307,45 @@ TEST_F(obj_importer_test, import_materials) {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)}, }; - import_and_check("materials.obj", expect, std::size(expect), 4); + import_and_check("materials.obj", expect, std::size(expect), 4, 1); +} + +TEST_F(obj_importer_test, import_cubes_with_textures_rel) +{ + Expectation expect[] = { + {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, + {"OBCube4Tex", + OB_MESH, + 8, + 12, + 6, + 24, + float3(1, 1, -1), + float3(-1, -1, 1), + float3(0, 1, 0), + float2(0.9935f, 0.0020f)}, + {"OBCubeTiledTex", + OB_MESH, + 8, + 12, + 6, + 24, + float3(4, 1, -1), + float3(2, -1, 1), + float3(0, 1, 0), + float2(0.9935f, 0.0020f)}, + {"OBCubeTiledTexFromAnotherFolder", + OB_MESH, + 8, + 12, + 6, + 24, + float3(7, 1, -1), + float3(5, -1, 1), + float3(0, 1, 0), + float2(0.9935f, 0.0020f)}, + }; + import_and_check("cubes_with_textures_rel.obj", expect, std::size(expect), 3, 4); } TEST_F(obj_importer_test, import_faces_invalid_or_with_holes) @@ -664,4 +703,14 @@ TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb) import_and_check("cubes_vertex_colors_mrgb.obj", expect, std::size(expect), 0); } +TEST_F(obj_importer_test, import_vertices) +{ + Expectation expect[] = { + {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, + /* Loose vertices without faces or edges. */ + {"OBCube.001", OB_MESH, 8, 0, 0, 0, float3(1, 1, -1), float3(-1, 1, 1)}, + }; + import_and_check("vertices.obj", expect, std::size(expect), 0); +} + } // namespace blender::io::obj diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h index d49d0906aa7..29795519719 100644 --- a/source/blender/makesdna/DNA_asset_types.h +++ b/source/blender/makesdna/DNA_asset_types.h @@ -96,7 +96,7 @@ typedef enum eAssetLibraryType { } eAssetLibraryType; /** - * Information to identify a asset library. May be either one of the predefined types (current + * Information to identify an asset library. May be either one of the predefined types (current * 'Main', builtin library, project library), or a custom type as defined in the Preferences. * * If the type is set to #ASSET_LIBRARY_CUSTOM, `custom_library_index` must be set to identify the diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 0af50b2bd4f..345fa141514 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -37,7 +37,7 @@ typedef enum eViewLayerEEVEEPassType { EEVEE_RENDER_PASS_CRYPTOMATTE = (1 << 16), EEVEE_RENDER_PASS_VECTOR = (1 << 17), } eViewLayerEEVEEPassType; -#define EEVEE_RENDER_PASS_MAX_BIT 17 +#define EEVEE_RENDER_PASS_MAX_BIT 18 /* #ViewLayerAOV.type */ typedef enum eViewLayerAOVType { diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 2a4234bde6a..4090c45a753 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -55,7 +55,6 @@ enum { /* ME_HIDE = (1 << 4), */ ME_EDGERENDER = (1 << 5), ME_LOOSEEDGE = (1 << 7), - ME_EDGE_TMP_TAG = (1 << 8), ME_SHARP = (1 << 9), /* only reason this flag remains a 'short' */ }; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 005228bea72..de9fa60aa5d 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -475,247 +475,6 @@ bool RNA_property_copy( bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index); bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop); -/* Path - * - * Experimental method to refer to structs and properties with a string, - * using a syntax like: scenes[0].objects["Cube"].data.verts[7].co - * - * This provides a way to refer to RNA data while being detached from any - * particular pointers, which is useful in a number of applications, like - * UI code or Actions, though efficiency is a concern. */ - -char *RNA_path_append( - const char *path, const PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey); -#if 0 /* UNUSED. */ -char *RNA_path_back(const char *path); -#endif - -/** - * Search for the start of the 'rna array index' part of the given `rna_path`. - * - * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first - * character in `rna_path` that is part of the array index for the given property. Return NULL if - * none can be found, e.g. because the property is not an RNA array. - * - * \param array_prop: if not NULL, the #PropertyRNA assumed to be the last one from the RNA path. - * Only used to ensure it is a valid array property. - */ -const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop); - -/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */ - -/** - * Resolve the given RNA Path to find the pointer and/or property - * indicated by fully resolving the path. - * - * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers, - * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr, - * and a NULL \a r_prop... - * - * \note Assumes all pointers provided are valid - * \return True if path can be resolved to a valid "pointer + property" OR "pointer only" - */ -bool RNA_path_resolve(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop); - -/** - * Resolve the given RNA Path to find the pointer and/or property + array index - * indicated by fully resolving the path. - * - * \note Assumes all pointers provided are valid. - * \return True if path can be resolved to a valid "pointer + property" OR "pointer only" - */ -bool RNA_path_resolve_full(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index); -/** - * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data. - * - * \note While it's correct to ignore the value of #PointerRNA.data - * most callers need to know if the resulting pointer was found and not null. - */ -bool RNA_path_resolve_full_maybe_null(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index); - -/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */ - -/** - * Resolve the given RNA Path to find both the pointer AND property - * indicated by fully resolving the path. - * - * This is a convenience method to avoid logic errors and ugly syntax. - * \note Assumes all pointers provided are valid - * \return True only if both a valid pointer and property are found after resolving the path - */ -bool RNA_path_resolve_property(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop); - -/** - * Resolve the given RNA Path to find the pointer AND property (as well as the array index) - * indicated by fully resolving the path. - * - * This is a convenience method to avoid logic errors and ugly syntax. - * \note Assumes all pointers provided are valid - * \return True only if both a valid pointer and property are found after resolving the path - */ -bool RNA_path_resolve_property_full(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index); - -/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist, - * and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */ - -/** - * Resolve the given RNA Path to find both the pointer AND property - * indicated by fully resolving the path, and get the value of the Pointer property - * (or item of the collection). - * - * This is a convenience method to avoid logic errors and ugly syntax, - * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call. - * \note Assumes all pointers provided are valid. - * \param r_item_ptr: The final Pointer or Collection item value. - * You must check for its validity before use! - * \return True only if both a valid pointer and property are found after resolving the path - */ -bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - PointerRNA *r_item_ptr); - -/** - * Resolve the given RNA Path to find both the pointer AND property (as well as the array index) - * indicated by fully resolving the path, - * and get the value of the Pointer property (or item of the collection). - * - * This is a convenience method to avoid logic errors and ugly syntax, - * it combines both \a RNA_path_resolve_full and - * \a RNA_path_resolve_property_full in a single call. - * \note Assumes all pointers provided are valid. - * \param r_item_ptr: The final Pointer or Collection item value. - * You must check for its validity before use! - * \return True only if both a valid pointer and property are found after resolving the path - */ -bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index, - PointerRNA *r_item_ptr); - -typedef struct PropertyElemRNA PropertyElemRNA; -struct PropertyElemRNA { - PropertyElemRNA *next, *prev; - PointerRNA ptr; - PropertyRNA *prop; - int index; -}; -/** - * Resolve the given RNA Path into a linked list of #PropertyElemRNA's. - * - * To be used when complex operations over path are needed, like e.g. get relative paths, - * to avoid too much string operations. - * - * \return True if there was no error while resolving the path - * \note Assumes all pointers provided are valid - */ -bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements); - -/** - * Find the path from the structure referenced by the pointer to the runtime RNA-defined - * #IDProperty object. - * - * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties). - * - * \param ptr: Reference to the object owning the custom property storage. - * \param needle: Custom property object to find. - * \return Relative path or NULL. - */ -char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle); - -/** - * Find the actual ID pointer and path from it to the given ID. - * - * \param id: ID reference to search the global owner for. - * \param[out] r_path: Path from the real ID to the initial ID. - * \return The ID pointer, or NULL in case of failure. - */ -struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path); - -char *RNA_path_from_ID_to_struct(const PointerRNA *ptr); - -char *RNA_path_from_real_ID_to_struct(struct Main *bmain, - const PointerRNA *ptr, - struct ID **r_real); - -char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop); -/** - * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc. - * \param index: The *flattened* index to use when \a `index_dim > 0`, - * this is expanded when used with multi-dimensional arrays. - */ -char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr, - PropertyRNA *prop, - int index_dim, - int index); - -char *RNA_path_from_real_ID_to_property_index(struct Main *bmain, - const PointerRNA *ptr, - PropertyRNA *prop, - int index_dim, - int index, - struct ID **r_real_id); - -/** - * \return the path to given ptr/prop from the closest ancestor of given type, - * if any (else return NULL). - */ -char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, - PropertyRNA *prop, - const struct StructRNA *type); - -/** - * Get the ID as a python representation, eg: - * bpy.data.foo["bar"] - */ -char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id); -/** - * Get the ID.struct as a python representation, eg: - * bpy.data.foo["bar"].some_struct - */ -char *RNA_path_full_struct_py(struct Main *bmain, const PointerRNA *ptr); -/** - * Get the ID.struct.property as a python representation, eg: - * bpy.data.foo["bar"].some_struct.some_prop[10] - */ -char *RNA_path_full_property_py_ex( - struct Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback); -char *RNA_path_full_property_py(struct Main *bmain, - const PointerRNA *ptr, - PropertyRNA *prop, - int index); -/** - * Get the struct.property as a python representation, eg: - * some_struct.some_prop[10] - */ -char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index); -/** - * Get the struct.property as a python representation, eg: - * some_prop[10] - */ -char *RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index); - /* Quick name based property access * * These are just an easier way to access property values without having to diff --git a/source/blender/makesrna/RNA_path.h b/source/blender/makesrna/RNA_path.h new file mode 100644 index 00000000000..7ab8c6fa313 --- /dev/null +++ b/source/blender/makesrna/RNA_path.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup RNA + * + * RNA paths are a way to refer to pointers and properties with a string, + * using a syntax like: scenes[0].objects["Cube"].data.verts[7].co + * + * This provides a way to refer to RNA data while being detached from any + * particular pointers, which is useful in a number of applications, like + * UI code or Actions, though efficiency is a concern. + */ + +#include "RNA_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ListBase; +struct IDProperty; + +char *RNA_path_append( + const char *path, const PointerRNA *ptr, PropertyRNA *prop, int intkey, const char *strkey); +#if 0 /* UNUSED. */ +char *RNA_path_back(const char *path); +#endif + +/** + * Search for the start of the 'rna array index' part of the given `rna_path`. + * + * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first + * character in `rna_path` that is part of the array index for the given property. Return NULL if + * none can be found, e.g. because the property is not an RNA array. + * + * \param array_prop: if not NULL, the #PropertyRNA assumed to be the last one from the RNA path. + * Only used to ensure it is a valid array property. + */ +const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop); + +/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */ + +/** + * Resolve the given RNA Path to find the pointer and/or property + * indicated by fully resolving the path. + * + * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers, + * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr, + * and a NULL \a r_prop... + * + * \note Assumes all pointers provided are valid + * \return True if path can be resolved to a valid "pointer + property" OR "pointer only" + */ +bool RNA_path_resolve(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop); + +/** + * Resolve the given RNA Path to find the pointer and/or property + array index + * indicated by fully resolving the path. + * + * \note Assumes all pointers provided are valid. + * \return True if path can be resolved to a valid "pointer + property" OR "pointer only" + */ +bool RNA_path_resolve_full(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index); +/** + * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data. + * + * \note While it's correct to ignore the value of #PointerRNA.data + * most callers need to know if the resulting pointer was found and not null. + */ +bool RNA_path_resolve_full_maybe_null(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index); + +/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */ + +/** + * Resolve the given RNA Path to find both the pointer AND property + * indicated by fully resolving the path. + * + * This is a convenience method to avoid logic errors and ugly syntax. + * \note Assumes all pointers provided are valid + * \return True only if both a valid pointer and property are found after resolving the path + */ +bool RNA_path_resolve_property(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop); + +/** + * Resolve the given RNA Path to find the pointer AND property (as well as the array index) + * indicated by fully resolving the path. + * + * This is a convenience method to avoid logic errors and ugly syntax. + * \note Assumes all pointers provided are valid + * \return True only if both a valid pointer and property are found after resolving the path + */ +bool RNA_path_resolve_property_full(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index); + +/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist, + * and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */ + +/** + * Resolve the given RNA Path to find both the pointer AND property + * indicated by fully resolving the path, and get the value of the Pointer property + * (or item of the collection). + * + * This is a convenience method to avoid logic errors and ugly syntax, + * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call. + * \note Assumes all pointers provided are valid. + * \param r_item_ptr: The final Pointer or Collection item value. + * You must check for its validity before use! + * \return True only if both a valid pointer and property are found after resolving the path + */ +bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + PointerRNA *r_item_ptr); + +/** + * Resolve the given RNA Path to find both the pointer AND property (as well as the array index) + * indicated by fully resolving the path, + * and get the value of the Pointer property (or item of the collection). + * + * This is a convenience method to avoid logic errors and ugly syntax, + * it combines both \a RNA_path_resolve_full and + * \a RNA_path_resolve_property_full in a single call. + * \note Assumes all pointers provided are valid. + * \param r_item_ptr: The final Pointer or Collection item value. + * You must check for its validity before use! + * \return True only if both a valid pointer and property are found after resolving the path + */ +bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index, + PointerRNA *r_item_ptr); + +typedef struct PropertyElemRNA PropertyElemRNA; +struct PropertyElemRNA { + PropertyElemRNA *next, *prev; + PointerRNA ptr; + PropertyRNA *prop; + int index; +}; +/** + * Resolve the given RNA Path into a linked list of #PropertyElemRNA's. + * + * To be used when complex operations over path are needed, like e.g. get relative paths, + * to avoid too much string operations. + * + * \return True if there was no error while resolving the path + * \note Assumes all pointers provided are valid + */ +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements); + +/** + * Find the path from the structure referenced by the pointer to the runtime RNA-defined + * #IDProperty object. + * + * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties). + * + * \param ptr: Reference to the object owning the custom property storage. + * \param needle: Custom property object to find. + * \return Relative path or NULL. + */ +char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle); + +/** + * Find the actual ID pointer and path from it to the given ID. + * + * \param id: ID reference to search the global owner for. + * \param[out] r_path: Path from the real ID to the initial ID. + * \return The ID pointer, or NULL in case of failure. + */ +struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path); + +char *RNA_path_from_ID_to_struct(const PointerRNA *ptr); + +char *RNA_path_from_real_ID_to_struct(struct Main *bmain, + const PointerRNA *ptr, + struct ID **r_real); + +char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop); +/** + * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc. + * \param index: The *flattened* index to use when \a `index_dim > 0`, + * this is expanded when used with multi-dimensional arrays. + */ +char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr, + PropertyRNA *prop, + int index_dim, + int index); + +char *RNA_path_from_real_ID_to_property_index(struct Main *bmain, + const PointerRNA *ptr, + PropertyRNA *prop, + int index_dim, + int index, + struct ID **r_real_id); + +/** + * \return the path to given ptr/prop from the closest ancestor of given type, + * if any (else return NULL). + */ +char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, + PropertyRNA *prop, + const struct StructRNA *type); + +/** + * Get the ID as a python representation, eg: + * bpy.data.foo["bar"] + */ +char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id); +/** + * Get the ID.struct as a python representation, eg: + * bpy.data.foo["bar"].some_struct + */ +char *RNA_path_full_struct_py(struct Main *bmain, const PointerRNA *ptr); +/** + * Get the ID.struct.property as a python representation, eg: + * bpy.data.foo["bar"].some_struct.some_prop[10] + */ +char *RNA_path_full_property_py_ex( + struct Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback); +char *RNA_path_full_property_py(struct Main *bmain, + const PointerRNA *ptr, + PropertyRNA *prop, + int index); +/** + * Get the struct.property as a python representation, eg: + * some_struct.some_prop[10] + */ +char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index); +/** + * Get the struct.property as a python representation, eg: + * some_prop[10] + */ +char *RNA_path_property_py(const PointerRNA *ptr, PropertyRNA *prop, int index); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index aaadd36341f..8124804de2b 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -159,6 +159,7 @@ set(SRC_RNA_INC ../RNA_documentation.h ../RNA_enum_items.h ../RNA_enum_types.h + ../RNA_path.h ../RNA_types.h ) @@ -416,6 +417,7 @@ add_custom_command( set(SRC rna_access.c rna_access_compare_override.c + rna_path.cc ${GENSRC} ${SRC_RNA_INC} diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index cf4182243b9..04707c01d6b 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -46,6 +46,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "WM_api.h" #include "WM_message.h" @@ -738,7 +739,7 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier) } /* Find the property which uses the given nested struct */ -static PropertyRNA *RNA_struct_find_nested(PointerRNA *ptr, StructRNA *srna) +PropertyRNA *rna_struct_find_nested(PointerRNA *ptr, StructRNA *srna) { PropertyRNA *prop = NULL; @@ -1422,7 +1423,7 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop) return cprop->item_type; } } - /* ignore other types, RNA_struct_find_nested calls with unchecked props */ + /* ignore other types, rna_struct_find_nested calls with unchecked props */ return &RNA_UnknownType; } @@ -4821,1337 +4822,6 @@ PointerRNA rna_array_lookup_int( return rna_pointer_inherit_refine(ptr, type, ((char *)data) + index * itemsize); } -/* RNA Path - Experiment */ - -/** - * Extract the first token from `path`. - * - * \param path: Extract the token from path, step the pointer to the beginning of the next token - * \return The nil terminated token. - */ -static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen) -{ - int len = 0; - - /* Get data until `.` or `[`. */ - const char *p = *path; - while (*p && !ELEM(*p, '.', '[')) { - len++; - p++; - } - - /* Empty, return. */ - if (UNLIKELY(len == 0)) { - return NULL; - } - - /* Try to use fixed buffer if possible. */ - char *buf = (len + 1 < fixedlen) ? fixedbuf : MEM_mallocN(sizeof(char) * (len + 1), __func__); - memcpy(buf, *path, sizeof(char) * len); - buf[len] = '\0'; - - if (*p == '.') { - p++; - } - *path = p; - - return buf; -} - -/** - * Extract the first token in brackets from `path` (with quoted text support). - * - * - `[0]` -> `0` - * - `["Some\"Quote"]` -> `Some"Quote` - * - * \param path: Extract the token from path, step the pointer to the beginning of the next token - * (past quoted text and brackets). - * \return The nil terminated token. - */ -static char *rna_path_token_in_brackets(const char **path, - char *fixedbuf, - int fixedlen, - bool *r_quoted) -{ - int len = 0; - bool quoted = false; - - BLI_assert(r_quoted != NULL); - - /* Get data between `[]`, check escaping quotes and back-slashes with #BLI_str_unescape. */ - if (UNLIKELY(**path != '[')) { - return NULL; - } - - (*path)++; - const char *p = *path; - - /* 2 kinds of look-ups now, quoted or unquoted. */ - if (*p == '"') { - /* Find the matching quote. */ - (*path)++; - p = *path; - const char *p_end = BLI_str_escape_find_quote(p); - if (p_end == NULL) { - /* No Matching quote. */ - return NULL; - } - /* Exclude the last quote from the length. */ - len += (p_end - p); - - /* Skip the last quoted char to get the `]`. */ - p_end += 1; - p = p_end; - quoted = true; - } - else { - /* Find the matching bracket. */ - while (*p && (*p != ']')) { - len++; - p++; - } - } - - if (UNLIKELY(*p != ']')) { - return NULL; - } - - /* Empty, return. */ - if (UNLIKELY(len == 0)) { - return NULL; - } - - /* Try to use fixed buffer if possible. */ - char *buf = (len + 1 < fixedlen) ? fixedbuf : MEM_mallocN(sizeof(char) * (len + 1), __func__); - - /* Copy string, taking into account escaped ']' */ - if (quoted) { - BLI_str_unescape(buf, *path, len); - /* +1 to step over the last quote. */ - BLI_assert((*path)[len] == '"'); - p = (*path) + len + 1; - } - else { - memcpy(buf, *path, sizeof(char) * len); - buf[len] = '\0'; - } - /* Set path to start of next token. */ - if (*p == ']') { - p++; - } - if (*p == '.') { - p++; - } - *path = p; - - *r_quoted = quoted; - - return buf; -} - -/** - * \return true when the key in the path is correctly parsed and found in the collection - * or when the path is empty. - */ -static bool rna_path_parse_collection_key(const char **path, - PointerRNA *ptr, - PropertyRNA *prop, - PointerRNA *r_nextptr) -{ - char fixedbuf[256]; - int intkey; - - *r_nextptr = *ptr; - - /* end of path, ok */ - if (!(**path)) { - return true; - } - - bool found = false; - if (**path == '[') { - bool quoted; - char *token; - - /* resolve the lookup with [] brackets */ - token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), "ed); - - if (!token) { - return false; - } - - /* check for "" to see if it is a string */ - if (quoted) { - if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) { - found = true; - } - else { - r_nextptr->data = NULL; - } - } - else { - /* otherwise do int lookup */ - intkey = atoi(token); - if (intkey == 0 && (token[0] != '0' || token[1] != '\0')) { - return false; /* we can be sure the fixedbuf was used in this case */ - } - if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) { - found = true; - } - else { - r_nextptr->data = NULL; - } - } - - if (token != fixedbuf) { - MEM_freeN(token); - } - } - else { - if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) { - found = true; - } - else { - /* ensure we quit on invalid values */ - r_nextptr->data = NULL; - } - } - - return found; -} - -static bool rna_path_parse_array_index(const char **path, - PointerRNA *ptr, - PropertyRNA *prop, - int *r_index) -{ - char fixedbuf[256]; - int index_arr[RNA_MAX_ARRAY_DIMENSION] = {0}; - int len[RNA_MAX_ARRAY_DIMENSION]; - const int dim = RNA_property_array_dimension(ptr, prop, len); - int i; - - *r_index = -1; - - /* end of path, ok */ - if (!(**path)) { - return true; - } - - for (i = 0; i < dim; i++) { - int temp_index = -1; - char *token; - - /* multi index resolve */ - if (**path == '[') { - bool quoted; - token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), "ed); - - if (token == NULL) { - /* invalid syntax blah[] */ - return false; - } - /* check for "" to see if it is a string */ - if (quoted) { - temp_index = RNA_property_array_item_index(prop, *token); - } - else { - /* otherwise do int lookup */ - temp_index = atoi(token); - - if (temp_index == 0 && (token[0] != '0' || token[1] != '\0')) { - if (token != fixedbuf) { - MEM_freeN(token); - } - - return false; - } - } - } - else if (dim == 1) { - /* location.x || scale.X, single dimension arrays only */ - token = rna_path_token(path, fixedbuf, sizeof(fixedbuf)); - if (token == NULL) { - /* invalid syntax blah. */ - return false; - } - temp_index = RNA_property_array_item_index(prop, *token); - } - else { - /* just to avoid uninitialized pointer use */ - token = fixedbuf; - } - - if (token != fixedbuf) { - MEM_freeN(token); - } - - /* out of range */ - if (temp_index < 0 || temp_index >= len[i]) { - return false; - } - - index_arr[i] = temp_index; - /* end multi index resolve */ - } - - /* arrays always contain numbers so further values are not valid */ - if (**path) { - return false; - } - - /* flatten index over all dimensions */ - { - int totdim = 1; - int flat_index = 0; - - for (i = dim - 1; i >= 0; i--) { - flat_index += index_arr[i] * totdim; - totdim *= len[i]; - } - - *r_index = flat_index; - } - return true; -} - -/** - * Generic rna path parser. - * - * \note All parameters besides \a ptr and \a path are optional. - * - * \param ptr: The root of given RNA path. - * \param path: The RNA path. - * \param r_ptr: The final RNA data holding the last property in \a path. - * \param r_prop: The final property of \a r_ptr, from \a path. - * \param r_index: The final index in the \a r_prop, if defined by \a path. - * \param r_item_ptr: Only valid for Pointer and Collection, return the actual value of the - * pointer, or of the collection item. - * Mutually exclusive with \a eval_pointer option. - * \param r_elements: A list of \a PropertyElemRNA items(pairs of \a PointerRNA, \a PropertyRNA - * that represent the whole given \a path). - * \param eval_pointer: If \a true, and \a path leads to a Pointer property, or an item in a - * Collection property, \a r_ptr will be set to the value of that property, - * and \a r_prop will be NULL. - * Mutually exclusive with \a r_item_ptr. - * - * \return \a true on success, \a false if the path is somehow invalid. - */ -static bool rna_path_parse(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index, - PointerRNA *r_item_ptr, - ListBase *r_elements, - const bool eval_pointer) -{ - BLI_assert(r_item_ptr == NULL || !eval_pointer); - PropertyRNA *prop; - PointerRNA curptr, nextptr; - PropertyElemRNA *prop_elem = NULL; - int index = -1; - char fixedbuf[256]; - int type; - const bool do_item_ptr = r_item_ptr != NULL && !eval_pointer; - - if (do_item_ptr) { - RNA_POINTER_INVALIDATE(&nextptr); - } - - prop = NULL; - curptr = *ptr; - - if (path == NULL || *path == '\0') { - return false; - } - - while (*path) { - if (do_item_ptr) { - RNA_POINTER_INVALIDATE(&nextptr); - } - - const bool use_id_prop = (*path == '['); - /* custom property lookup ? - * C.object["someprop"] - */ - - if (!curptr.data) { - return false; - } - - /* look up property name in current struct */ - bool quoted = false; - char *token = use_id_prop ? - rna_path_token_in_brackets(&path, fixedbuf, sizeof(fixedbuf), "ed) : - rna_path_token(&path, fixedbuf, sizeof(fixedbuf)); - if (!token) { - return false; - } - - prop = NULL; - if (use_id_prop) { /* look up property name in current struct */ - IDProperty *group = RNA_struct_idprops(&curptr, 0); - if (group && quoted) { - prop = (PropertyRNA *)IDP_GetPropertyFromGroup(group, token); - } - } - else { - prop = RNA_struct_find_property(&curptr, token); - } - - if (token != fixedbuf) { - MEM_freeN(token); - } - - if (!prop) { - return false; - } - - if (r_elements) { - prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); - prop_elem->ptr = curptr; - prop_elem->prop = prop; - prop_elem->index = -1; /* index will be added later, if needed. */ - BLI_addtail(r_elements, prop_elem); - } - - type = RNA_property_type(prop); - - /* now look up the value of this property if it is a pointer or - * collection, otherwise return the property rna so that the - * caller can read the value of the property itself */ - switch (type) { - case PROP_POINTER: { - /* resolve pointer if further path elements follow - * or explicitly requested - */ - if (do_item_ptr || eval_pointer || *path != '\0') { - nextptr = RNA_property_pointer_get(&curptr, prop); - } - - if (eval_pointer || *path != '\0') { - curptr = nextptr; - prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - index = -1; - } - break; - } - case PROP_COLLECTION: { - /* Resolve pointer if further path elements follow. - * Note that if path is empty, rna_path_parse_collection_key will do nothing anyway, - * so do_item_ptr is of no use in that case. - */ - if (*path) { - if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr)) { - return false; - } - - if (eval_pointer || *path != '\0') { - curptr = nextptr; - prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - index = -1; - } - } - break; - } - default: - if (r_index || prop_elem) { - if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) { - return false; - } - - if (prop_elem) { - prop_elem->index = index; - } - } - break; - } - } - - if (r_ptr) { - *r_ptr = curptr; - } - if (r_prop) { - *r_prop = prop; - } - if (r_index) { - *r_index = index; - } - if (r_item_ptr && do_item_ptr) { - *r_item_ptr = nextptr; - } - - if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || - prop_elem->index != index)) { - prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); - prop_elem->ptr = curptr; - prop_elem->prop = prop; - prop_elem->index = index; - BLI_addtail(r_elements, prop_elem); - } - - return true; -} - -bool RNA_path_resolve(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) { - return false; - } - - return r_ptr->data != NULL; -} - -bool RNA_path_resolve_full( - const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true)) { - return false; - } - - return r_ptr->data != NULL; -} - -bool RNA_path_resolve_full_maybe_null( - const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) -{ - return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true); -} - -bool RNA_path_resolve_property(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} - -bool RNA_path_resolve_property_full( - const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} - -bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - PointerRNA *r_item_ptr) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, r_item_ptr, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} - -bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr, - const char *path, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index, - PointerRNA *r_item_ptr) -{ - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, r_item_ptr, NULL, false)) { - return false; - } - - return r_ptr->data != NULL && *r_prop != NULL; -} -bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements) -{ - return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false); -} - -char *RNA_path_append(const char *path, - const PointerRNA *UNUSED(ptr), - PropertyRNA *prop, - int intkey, - const char *strkey) -{ - DynStr *dynstr; - char *result; - - dynstr = BLI_dynstr_new(); - - /* add .identifier */ - if (path) { - BLI_dynstr_append(dynstr, path); - if (*path) { - BLI_dynstr_append(dynstr, "."); - } - } - - BLI_dynstr_append(dynstr, RNA_property_identifier(prop)); - - if (RNA_property_type(prop) == PROP_COLLECTION) { - /* add ["strkey"] or [intkey] */ - BLI_dynstr_append(dynstr, "["); - - if (strkey) { - const int strkey_esc_max_size = (strlen(strkey) * 2) + 1; - char *strkey_esc = BLI_array_alloca(strkey_esc, strkey_esc_max_size); - BLI_str_escape(strkey_esc, strkey, strkey_esc_max_size); - BLI_dynstr_append(dynstr, "\""); - BLI_dynstr_append(dynstr, strkey_esc); - BLI_dynstr_append(dynstr, "\""); - } - else { - char appendstr[128]; - BLI_snprintf(appendstr, sizeof(appendstr), "%d", intkey); - BLI_dynstr_append(dynstr, appendstr); - } - - BLI_dynstr_append(dynstr, "]"); - } - - result = BLI_dynstr_get_cstring(dynstr); - BLI_dynstr_free(dynstr); - - return result; -} - -/* Having both path append & back seems like it could be useful, - * this function isn't used at the moment. */ -static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path) -{ - char fixedbuf[256]; - const char *previous, *current; - char *result; - int i; - - if (!path) { - return NULL; - } - - previous = NULL; - current = path; - - /* parse token by token until the end, then we back up to the previous - * position and strip of the next token to get the path one step back */ - while (*current) { - char *token; - - token = rna_path_token(¤t, fixedbuf, sizeof(fixedbuf)); - - if (!token) { - return NULL; - } - if (token != fixedbuf) { - MEM_freeN(token); - } - - /* in case of collection we also need to strip off [] */ - bool quoted; - token = rna_path_token_in_brackets(¤t, fixedbuf, sizeof(fixedbuf), "ed); - if (token && token != fixedbuf) { - MEM_freeN(token); - } - - if (!*current) { - break; - } - - previous = current; - } - - if (!previous) { - return NULL; - } - - /* copy and strip off last token */ - i = previous - path; - result = BLI_strdup(path); - - if (i > 0 && result[i - 1] == '.') { - i--; - } - result[i] = 0; - - return result; -} - -const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop) -{ - if (array_prop != NULL) { - if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { - BLI_assert(array_prop->arraydimension == 0); - return NULL; - } - if (array_prop->arraydimension == 0) { - return NULL; - } - } - - /* Valid 'array part' of a rna path can only have '[', ']' and digit characters. - * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */ - off_t rna_path_len = (off_t)strlen(rna_path); - if (rna_path[rna_path_len] != ']') { - return NULL; - } - const char *last_valid_index_token_start = NULL; - for (rna_path_len--; rna_path_len >= 0; rna_path_len--) { - switch (rna_path[rna_path_len]) { - case '[': - if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') { - return &rna_path[rna_path_len]; - } - last_valid_index_token_start = &rna_path[rna_path_len]; - rna_path_len--; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - default: - return last_valid_index_token_start; - } - } - return last_valid_index_token_start; -} - -/* generic path search func - * if its needed this could also reference the IDProperty direct */ -typedef struct IDP_Chain { - struct IDP_Chain *up; /* parent member, reverse and set to child for path conversion. */ - - const char *name; - int index; - -} IDP_Chain; - -static char *rna_idp_path_create(IDP_Chain *child_link) -{ - DynStr *dynstr = BLI_dynstr_new(); - char *path; - bool is_first = true; - - int tot = 0; - IDP_Chain *link = child_link; - - /* reverse the list */ - IDP_Chain *link_prev; - link_prev = NULL; - while (link) { - IDP_Chain *link_next = link->up; - link->up = link_prev; - link_prev = link; - link = link_next; - tot++; - } - - for (link = link_prev; link; link = link->up) { - /* pass */ - if (link->index >= 0) { - BLI_dynstr_appendf(dynstr, is_first ? "%s[%d]" : ".%s[%d]", link->name, link->index); - } - else { - BLI_dynstr_appendf(dynstr, is_first ? "%s" : ".%s", link->name); - } - - is_first = false; - } - - path = BLI_dynstr_get_cstring(dynstr); - BLI_dynstr_free(dynstr); - - if (*path == '\0') { - MEM_freeN(path); - path = NULL; - } - - return path; -} - -static char *rna_idp_path(PointerRNA *ptr, - IDProperty *haystack, - IDProperty *needle, - IDP_Chain *parent_link) -{ - char *path = NULL; - IDP_Chain link; - - IDProperty *iter; - int i; - - BLI_assert(haystack->type == IDP_GROUP); - - link.up = parent_link; - /* Always set both name and index, else a stale value might get used. */ - link.name = NULL; - link.index = -1; - - for (i = 0, iter = haystack->data.group.first; iter; iter = iter->next, i++) { - if (needle == iter) { /* found! */ - link.name = iter->name; - link.index = -1; - path = rna_idp_path_create(&link); - break; - } - - /* Early out in case the IDProperty type cannot contain RNA properties. */ - if (!ELEM(iter->type, IDP_GROUP, IDP_IDPARRAY)) { - continue; - } - - /* Ensure this is RNA. */ - /* NOTE: `iter` might be a fully user-defined IDProperty (a.k.a. custom data), which name - * collides with an actual fully static RNA property of the same struct (which would then not - * be flagged with `PROP_IDPROPERTY`). - * - * That case must be ignored here, we only want to deal with runtime RNA properties stored in - * IDProps. - * - * See T84091. */ - PropertyRNA *prop = RNA_struct_find_property(ptr, iter->name); - if (prop == NULL || (prop->flag & PROP_IDPROPERTY) == 0) { - continue; - } - - if (iter->type == IDP_GROUP) { - if (prop->type == PROP_POINTER) { - PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop); - if (RNA_pointer_is_null(&child_ptr)) { - /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a NULL - * value is perfectly valid. Just means it won't match the searched needle. */ - continue; - } - - link.name = iter->name; - link.index = -1; - if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) { - break; - } - } - } - else if (iter->type == IDP_IDPARRAY) { - if (prop->type == PROP_COLLECTION) { - IDProperty *array = IDP_IDPArray(iter); - if (needle >= array && needle < (iter->len + array)) { /* found! */ - link.name = iter->name; - link.index = (int)(needle - array); - path = rna_idp_path_create(&link); - break; - } - int j; - link.name = iter->name; - for (j = 0; j < iter->len; j++, array++) { - PointerRNA child_ptr; - if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) { - if (RNA_pointer_is_null(&child_ptr)) { - /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case - * a NULL value is perfectly valid. Just means it won't match the searched needle. */ - continue; - } - link.index = j; - if ((path = rna_idp_path(&child_ptr, array, needle, &link))) { - break; - } - } - } - if (path) { - break; - } - } - } - } - - return path; -} - -char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle) -{ - IDProperty *haystack = RNA_struct_idprops(ptr, false); - - if (haystack) { /* can fail when called on bones */ - return rna_idp_path(ptr, haystack, needle, NULL); - } - return NULL; -} - -static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr) -{ - PointerRNA id_ptr; - - BLI_assert(ptr->owner_id != NULL); - - /* TODO: Support Bones/PoseBones. no pointers stored to the bones from here, only the ID. - * See example in T25746. - * Unless this is added only way to find this is to also search - * all bones and pose bones of an armature or object. - */ - RNA_id_pointer_create(ptr->owner_id, &id_ptr); - - return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data); -} - -ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path) -{ - if (r_path) { - *r_path = ""; - } - - if ((id == NULL) || (id->flag & LIB_EMBEDDED_DATA) == 0) { - return id; - } - - const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); - if (r_path) { - switch (GS(id->name)) { - case ID_NT: - *r_path = "node_tree"; - break; - case ID_GR: - *r_path = "collection"; - break; - default: - BLI_assert_msg(0, "Missing handling of embedded id type."); - } - } - - if (id_type->owner_get == NULL) { - BLI_assert_msg(0, "Missing handling of embedded id type."); - return id; - } - return id_type->owner_get(bmain, id); -} - -static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id) -{ - if (r_real_id != NULL) { - *r_real_id = NULL; - } - - const char *prefix; - ID *real_id = RNA_find_real_ID_and_path(bmain, id, &prefix); - - if (r_real_id != NULL) { - *r_real_id = real_id; - } - - if (path != NULL) { - char *new_path = NULL; - - if (real_id) { - if (prefix[0]) { - new_path = BLI_sprintfN("%s%s%s", prefix, path[0] == '[' ? "" : ".", path); - } - else { - return path; - } - } - - MEM_freeN(path); - return new_path; - } - return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL; -} - -char *RNA_path_from_ID_to_struct(const PointerRNA *ptr) -{ - char *ptrpath = NULL; - - if (!ptr->owner_id || !ptr->data) { - return NULL; - } - - if (!RNA_struct_is_ID(ptr->type)) { - if (ptr->type->path) { - /* if type has a path to some ID, use it */ - ptrpath = ptr->type->path((PointerRNA *)ptr); - } - else if (ptr->type->nested && RNA_struct_is_ID(ptr->type->nested)) { - PointerRNA parentptr; - PropertyRNA *userprop; - - /* find the property in the struct we're nested in that references this struct, and - * use its identifier as the first part of the path used... - */ - RNA_id_pointer_create(ptr->owner_id, &parentptr); - userprop = RNA_struct_find_nested(&parentptr, ptr->type); - - if (userprop) { - ptrpath = BLI_strdup(RNA_property_identifier(userprop)); - } - else { - return NULL; /* can't do anything about this case yet... */ - } - } - else if (RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) { - /* special case, easier to deal with here than in ptr->type->path() */ - return rna_path_from_ID_to_idpgroup(ptr); - } - else { - return NULL; - } - } - - return ptrpath; -} - -char *RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, struct ID **r_real) -{ - char *path = RNA_path_from_ID_to_struct(ptr); - - /* NULL path is valid in that case, when given struct is an ID one... */ - return rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real); -} - -static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY_LENGTH], - const int totdims, - const int index_dim, - int index, - int r_index_multi[RNA_MAX_ARRAY_LENGTH]) -{ - int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1]; - int i = totdims - 1; - dimsize_step[i + 1] = 1; - dimsize_step[i] = dimsize[i]; - while (--i != -1) { - dimsize_step[i] = dimsize[i] * dimsize_step[i + 1]; - } - while (++i != index_dim) { - int index_round = index / dimsize_step[i + 1]; - r_index_multi[i] = index_round; - index -= (index_round * dimsize_step[i + 1]); - } - BLI_assert(index == 0); -} - -static void rna_path_array_multi_string_from_flat_index(const PointerRNA *ptr, - PropertyRNA *prop, - int index_dim, - int index, - char *index_str, - int index_str_len) -{ - int dimsize[RNA_MAX_ARRAY_LENGTH]; - int totdims = RNA_property_array_dimension(ptr, prop, dimsize); - int index_multi[RNA_MAX_ARRAY_LENGTH]; - - rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi); - - for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) { - offset += BLI_snprintf_rlen( - &index_str[offset], index_str_len - offset, "[%d]", index_multi[i]); - } -} - -char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr, - PropertyRNA *prop, - int index_dim, - int index) -{ - const bool is_rna = (prop->magic == RNA_MAGIC); - const char *propname; - char *ptrpath, *path; - - if (!ptr->owner_id || !ptr->data) { - return NULL; - } - - /* path from ID to the struct holding this property */ - ptrpath = RNA_path_from_ID_to_struct(ptr); - - propname = RNA_property_identifier(prop); - - /* support indexing w/ multi-dimensional arrays */ - char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1]; - if (index_dim == 0) { - index_str[0] = '\0'; - } - else { - rna_path_array_multi_string_from_flat_index( - ptr, prop, index_dim, index, index_str, sizeof(index_str)); - } - - if (ptrpath) { - if (is_rna) { - path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str); - } - MEM_freeN(ptrpath); - } - else if (RNA_struct_is_ID(ptr->type)) { - if (is_rna) { - path = BLI_sprintfN("%s%s", propname, index_str); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str); - } - } - else { - path = NULL; - } - - return path; -} - -char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop) -{ - return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1); -} - -char *RNA_path_from_real_ID_to_property_index(Main *bmain, - const PointerRNA *ptr, - PropertyRNA *prop, - int index_dim, - int index, - ID **r_real_id) -{ - char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index); - - /* NULL path is always an error here, in that case do not return the 'fake ID from real ID' part - * of the path either. */ - return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL; -} - -char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, - PropertyRNA *prop, - const StructRNA *type) -{ - /* Try to recursively find an "type"'d ancestor, - * to handle situations where path from ID is not enough. */ - PointerRNA idptr; - ListBase path_elems = {NULL}; - char *path = NULL; - char *full_path = RNA_path_from_ID_to_property(ptr, prop); - - if (full_path == NULL) { - return NULL; - } - - RNA_id_pointer_create(ptr->owner_id, &idptr); - - if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) { - PropertyElemRNA *prop_elem; - - for (prop_elem = path_elems.last; prop_elem; prop_elem = prop_elem->prev) { - if (RNA_struct_is_a(prop_elem->ptr.type, type)) { - char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr); - if (ref_path) { - path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */ - MEM_freeN(ref_path); - } - break; - } - } - - BLI_freelistN(&path_elems); - } - - MEM_freeN(full_path); - return path; -} - -char *RNA_path_full_ID_py(Main *bmain, ID *id) -{ - const char *path; - ID *id_real = RNA_find_real_ID_and_path(bmain, id, &path); - - if (id_real) { - id = id_real; - } - else { - path = ""; - } - - char lib_filepath_esc[(sizeof(id->lib->filepath) * 2) + 4]; - if (ID_IS_LINKED(id)) { - int ofs = 0; - memcpy(lib_filepath_esc, ", \"", 3); - ofs += 3; - ofs += BLI_str_escape(lib_filepath_esc + ofs, id->lib->filepath, sizeof(lib_filepath_esc)); - memcpy(lib_filepath_esc + ofs, "\"", 2); - } - else { - lib_filepath_esc[0] = '\0'; - } - - char id_esc[(sizeof(id->name) - 2) * 2]; - BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc)); - - return BLI_sprintfN("bpy.data.%s[\"%s\"%s]%s%s", - BKE_idtype_idcode_to_name_plural(GS(id->name)), - id_esc, - lib_filepath_esc, - path[0] ? "." : "", - path); -} - -char *RNA_path_full_struct_py(Main *bmain, const PointerRNA *ptr) -{ - char *id_path; - char *data_path; - - char *ret; - - if (!ptr->owner_id) { - return NULL; - } - - /* never fails */ - id_path = RNA_path_full_ID_py(bmain, ptr->owner_id); - - data_path = RNA_path_from_ID_to_struct(ptr); - - /* XXX data_path may be NULL (see T36788), - * do we want to get the 'bpy.data.foo["bar"].(null)' stuff? */ - ret = BLI_sprintfN("%s.%s", id_path, data_path); - - if (data_path) { - MEM_freeN(data_path); - } - MEM_freeN(id_path); - - return ret; -} - -char *RNA_path_full_property_py_ex( - Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback) -{ - char *id_path; - const char *data_delim; - const char *data_path; - bool data_path_free; - - char *ret; - - if (!ptr->owner_id) { - return NULL; - } - - /* never fails */ - id_path = RNA_path_full_ID_py(bmain, ptr->owner_id); - - data_path = RNA_path_from_ID_to_property(ptr, prop); - if (data_path) { - data_delim = (data_path[0] == '[') ? "" : "."; - data_path_free = true; - } - else { - if (use_fallback) { - /* Fuzzy fallback. Be explicit in our ignorance. */ - data_path = RNA_property_identifier(prop); - data_delim = " ... "; - } - else { - data_delim = "."; - } - data_path_free = false; - } - - if ((index == -1) || (RNA_property_array_check(prop) == false)) { - ret = BLI_sprintfN("%s%s%s", id_path, data_delim, data_path); - } - else { - ret = BLI_sprintfN("%s%s%s[%d]", id_path, data_delim, data_path, index); - } - MEM_freeN(id_path); - if (data_path_free) { - MEM_freeN((void *)data_path); - } - - return ret; -} - -char *RNA_path_full_property_py(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index) -{ - return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false); -} - -char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) -{ - char *data_path; - - char *ret; - - if (!ptr->owner_id) { - return NULL; - } - - data_path = RNA_path_from_ID_to_property(ptr, prop); - - if (data_path == NULL) { - /* This may not be an ID at all, check for simple when pointer owns property. - * TODO: more complex nested case. */ - if (!RNA_struct_is_ID(ptr->type)) { - const char *prop_identifier = RNA_property_identifier(prop); - if (RNA_struct_find_property(ptr, prop_identifier) == prop) { - data_path = BLI_strdup(prop_identifier); - } - } - } - - if ((index == -1) || (RNA_property_array_check(prop) == false)) { - ret = BLI_strdup(data_path); - } - else { - ret = BLI_sprintfN("%s[%d]", data_path, index); - } - - if (data_path) { - MEM_freeN(data_path); - } - - return ret; -} - -char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index) -{ - const bool is_rna = (prop->magic == RNA_MAGIC); - const char *propname = RNA_property_identifier(prop); - char *ret; - - if ((index == -1) || (RNA_property_array_check(prop) == false)) { - if (is_rna) { - ret = BLI_strdup(propname); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - ret = BLI_sprintfN("[\"%s\"]", propname_esc); - } - } - else { - if (is_rna) { - ret = BLI_sprintfN("%s[%d]", propname, index); - } - else { - char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); - ret = BLI_sprintfN("[\"%s\"][%d]", propname_esc, index); - } - } - - return ret; -} - /* Quick name based property access */ bool RNA_boolean_get(PointerRNA *ptr, const char *name) diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 17c00923efa..d1df54df3cd 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -38,6 +38,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "rna_access_internal.h" diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h index a7dd35af670..384ff417fc9 100644 --- a/source/blender/makesrna/intern/rna_access_internal.h +++ b/source/blender/makesrna/intern/rna_access_internal.h @@ -10,6 +10,10 @@ #include "rna_internal_types.h" +#ifdef __cplusplus +extern "C" { +#endif + struct IDProperty; struct PropertyRNAOrID; @@ -26,3 +30,9 @@ void rna_property_rna_or_id_get(PropertyRNA *prop, void rna_idproperty_touch(struct IDProperty *idprop); struct IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name); + +PropertyRNA *rna_struct_find_nested(PointerRNA *ptr, StructRNA *srna); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 92cdcc6d781..2a85da42483 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -23,6 +23,7 @@ #ifdef RNA_RUNTIME # include "RNA_access.h" +# include "RNA_path.h" # include "DNA_image_types.h" # include "DNA_material_types.h" diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 833060e40f8..370455302b6 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -14,6 +14,10 @@ #include "UI_resources.h" +#ifdef __cplusplus +extern "C" { +#endif + #define RNA_MAGIC ((int)~0) struct AssetLibraryReference; @@ -691,3 +695,7 @@ void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values); : -FLT_MAX, double \ : -DBL_MAX) #endif + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/makesrna/intern/rna_path.cc b/source/blender/makesrna/intern/rna_path.cc new file mode 100644 index 00000000000..fe1f4c0101f --- /dev/null +++ b/source/blender/makesrna/intern/rna_path.cc @@ -0,0 +1,1360 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup RNA + */ + +#include <cstdlib> +#include <stdlib.h> +#include <string.h> + +#include "BLI_alloca.h" +#include "BLI_dynstr.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_idprop.h" +#include "BKE_idtype.h" + +#include "DNA_ID.h" /* For ID properties. */ + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_path.h" +#include "RNA_prototypes.h" + +#include "rna_access_internal.h" +#include "rna_internal.h" + +/** + * Extract the first token from `path`. + * + * \param path: Extract the token from path, step the pointer to the beginning of the next token + * \return The nil terminated token. + */ +static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen) +{ + int len = 0; + + /* Get data until `.` or `[`. */ + const char *p = *path; + while (*p && !ELEM(*p, '.', '[')) { + len++; + p++; + } + + /* Empty, return. */ + if (UNLIKELY(len == 0)) { + return NULL; + } + + /* Try to use fixed buffer if possible. */ + char *buf = (len + 1 < fixedlen) ? fixedbuf : + (char *)MEM_mallocN(sizeof(char) * (len + 1), __func__); + memcpy(buf, *path, sizeof(char) * len); + buf[len] = '\0'; + + if (*p == '.') { + p++; + } + *path = p; + + return buf; +} + +/** + * Extract the first token in brackets from `path` (with quoted text support). + * + * - `[0]` -> `0` + * - `["Some\"Quote"]` -> `Some"Quote` + * + * \param path: Extract the token from path, step the pointer to the beginning of the next token + * (past quoted text and brackets). + * \return The nil terminated token. + */ +static char *rna_path_token_in_brackets(const char **path, + char *fixedbuf, + int fixedlen, + bool *r_quoted) +{ + int len = 0; + bool quoted = false; + + BLI_assert(r_quoted != NULL); + + /* Get data between `[]`, check escaping quotes and back-slashes with #BLI_str_unescape. */ + if (UNLIKELY(**path != '[')) { + return NULL; + } + + (*path)++; + const char *p = *path; + + /* 2 kinds of look-ups now, quoted or unquoted. */ + if (*p == '"') { + /* Find the matching quote. */ + (*path)++; + p = *path; + const char *p_end = BLI_str_escape_find_quote(p); + if (p_end == NULL) { + /* No Matching quote. */ + return NULL; + } + /* Exclude the last quote from the length. */ + len += (p_end - p); + + /* Skip the last quoted char to get the `]`. */ + p_end += 1; + p = p_end; + quoted = true; + } + else { + /* Find the matching bracket. */ + while (*p && (*p != ']')) { + len++; + p++; + } + } + + if (UNLIKELY(*p != ']')) { + return NULL; + } + + /* Empty, return. */ + if (UNLIKELY(len == 0)) { + return NULL; + } + + /* Try to use fixed buffer if possible. */ + char *buf = (len + 1 < fixedlen) ? fixedbuf : + (char *)MEM_mallocN(sizeof(char) * (len + 1), __func__); + + /* Copy string, taking into account escaped ']' */ + if (quoted) { + BLI_str_unescape(buf, *path, len); + /* +1 to step over the last quote. */ + BLI_assert((*path)[len] == '"'); + p = (*path) + len + 1; + } + else { + memcpy(buf, *path, sizeof(char) * len); + buf[len] = '\0'; + } + /* Set path to start of next token. */ + if (*p == ']') { + p++; + } + if (*p == '.') { + p++; + } + *path = p; + + *r_quoted = quoted; + + return buf; +} + +/** + * \return true when the key in the path is correctly parsed and found in the collection + * or when the path is empty. + */ +static bool rna_path_parse_collection_key(const char **path, + PointerRNA *ptr, + PropertyRNA *prop, + PointerRNA *r_nextptr) +{ + char fixedbuf[256]; + int intkey; + + *r_nextptr = *ptr; + + /* end of path, ok */ + if (!(**path)) { + return true; + } + + bool found = false; + if (**path == '[') { + bool quoted; + char *token; + + /* resolve the lookup with [] brackets */ + token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), "ed); + + if (!token) { + return false; + } + + /* check for "" to see if it is a string */ + if (quoted) { + if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) { + found = true; + } + else { + r_nextptr->data = NULL; + } + } + else { + /* otherwise do int lookup */ + intkey = atoi(token); + if (intkey == 0 && (token[0] != '0' || token[1] != '\0')) { + return false; /* we can be sure the fixedbuf was used in this case */ + } + if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) { + found = true; + } + else { + r_nextptr->data = NULL; + } + } + + if (token != fixedbuf) { + MEM_freeN(token); + } + } + else { + if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) { + found = true; + } + else { + /* ensure we quit on invalid values */ + r_nextptr->data = NULL; + } + } + + return found; +} + +static bool rna_path_parse_array_index(const char **path, + PointerRNA *ptr, + PropertyRNA *prop, + int *r_index) +{ + char fixedbuf[256]; + int index_arr[RNA_MAX_ARRAY_DIMENSION] = {0}; + int len[RNA_MAX_ARRAY_DIMENSION]; + const int dim = RNA_property_array_dimension(ptr, prop, len); + int i; + + *r_index = -1; + + /* end of path, ok */ + if (!(**path)) { + return true; + } + + for (i = 0; i < dim; i++) { + int temp_index = -1; + char *token; + + /* multi index resolve */ + if (**path == '[') { + bool quoted; + token = rna_path_token_in_brackets(path, fixedbuf, sizeof(fixedbuf), "ed); + + if (token == NULL) { + /* invalid syntax blah[] */ + return false; + } + /* check for "" to see if it is a string */ + if (quoted) { + temp_index = RNA_property_array_item_index(prop, *token); + } + else { + /* otherwise do int lookup */ + temp_index = atoi(token); + + if (temp_index == 0 && (token[0] != '0' || token[1] != '\0')) { + if (token != fixedbuf) { + MEM_freeN(token); + } + + return false; + } + } + } + else if (dim == 1) { + /* location.x || scale.X, single dimension arrays only */ + token = rna_path_token(path, fixedbuf, sizeof(fixedbuf)); + if (token == NULL) { + /* invalid syntax blah. */ + return false; + } + temp_index = RNA_property_array_item_index(prop, *token); + } + else { + /* just to avoid uninitialized pointer use */ + token = fixedbuf; + } + + if (token != fixedbuf) { + MEM_freeN(token); + } + + /* out of range */ + if (temp_index < 0 || temp_index >= len[i]) { + return false; + } + + index_arr[i] = temp_index; + /* end multi index resolve */ + } + + /* arrays always contain numbers so further values are not valid */ + if (**path) { + return false; + } + + /* flatten index over all dimensions */ + { + int totdim = 1; + int flat_index = 0; + + for (i = dim - 1; i >= 0; i--) { + flat_index += index_arr[i] * totdim; + totdim *= len[i]; + } + + *r_index = flat_index; + } + return true; +} + +/** + * Generic rna path parser. + * + * \note All parameters besides \a ptr and \a path are optional. + * + * \param ptr: The root of given RNA path. + * \param path: The RNA path. + * \param r_ptr: The final RNA data holding the last property in \a path. + * \param r_prop: The final property of \a r_ptr, from \a path. + * \param r_index: The final index in the \a r_prop, if defined by \a path. + * \param r_item_ptr: Only valid for Pointer and Collection, return the actual value of the + * pointer, or of the collection item. + * Mutually exclusive with \a eval_pointer option. + * \param r_elements: A list of \a PropertyElemRNA items(pairs of \a PointerRNA, \a PropertyRNA + * that represent the whole given \a path). + * \param eval_pointer: If \a true, and \a path leads to a Pointer property, or an item in a + * Collection property, \a r_ptr will be set to the value of that property, + * and \a r_prop will be NULL. + * Mutually exclusive with \a r_item_ptr. + * + * \return \a true on success, \a false if the path is somehow invalid. + */ +static bool rna_path_parse(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index, + PointerRNA *r_item_ptr, + ListBase *r_elements, + const bool eval_pointer) +{ + BLI_assert(r_item_ptr == NULL || !eval_pointer); + PropertyRNA *prop; + PointerRNA curptr, nextptr; + PropertyElemRNA *prop_elem = NULL; + int index = -1; + char fixedbuf[256]; + int type; + const bool do_item_ptr = r_item_ptr != NULL && !eval_pointer; + + if (do_item_ptr) { + RNA_POINTER_INVALIDATE(&nextptr); + } + + prop = NULL; + curptr = *ptr; + + if (path == NULL || *path == '\0') { + return false; + } + + while (*path) { + if (do_item_ptr) { + RNA_POINTER_INVALIDATE(&nextptr); + } + + const bool use_id_prop = (*path == '['); + /* custom property lookup ? + * C.object["someprop"] + */ + + if (!curptr.data) { + return false; + } + + /* look up property name in current struct */ + bool quoted = false; + char *token = use_id_prop ? + rna_path_token_in_brackets(&path, fixedbuf, sizeof(fixedbuf), "ed) : + rna_path_token(&path, fixedbuf, sizeof(fixedbuf)); + if (!token) { + return false; + } + + prop = NULL; + if (use_id_prop) { /* look up property name in current struct */ + IDProperty *group = RNA_struct_idprops(&curptr, 0); + if (group && quoted) { + prop = (PropertyRNA *)IDP_GetPropertyFromGroup(group, token); + } + } + else { + prop = RNA_struct_find_property(&curptr, token); + } + + if (token != fixedbuf) { + MEM_freeN(token); + } + + if (!prop) { + return false; + } + + if (r_elements) { + prop_elem = MEM_cnew<PropertyElemRNA>(__func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = -1; /* index will be added later, if needed. */ + BLI_addtail(r_elements, prop_elem); + } + + type = RNA_property_type(prop); + + /* now look up the value of this property if it is a pointer or + * collection, otherwise return the property rna so that the + * caller can read the value of the property itself */ + switch (type) { + case PROP_POINTER: { + /* resolve pointer if further path elements follow + * or explicitly requested + */ + if (do_item_ptr || eval_pointer || *path != '\0') { + nextptr = RNA_property_pointer_get(&curptr, prop); + } + + if (eval_pointer || *path != '\0') { + curptr = nextptr; + prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ + index = -1; + } + break; + } + case PROP_COLLECTION: { + /* Resolve pointer if further path elements follow. + * Note that if path is empty, rna_path_parse_collection_key will do nothing anyway, + * so do_item_ptr is of no use in that case. + */ + if (*path) { + if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr)) { + return false; + } + + if (eval_pointer || *path != '\0') { + curptr = nextptr; + prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ + index = -1; + } + } + break; + } + default: + if (r_index || prop_elem) { + if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) { + return false; + } + + if (prop_elem) { + prop_elem->index = index; + } + } + break; + } + } + + if (r_ptr) { + *r_ptr = curptr; + } + if (r_prop) { + *r_prop = prop; + } + if (r_index) { + *r_index = index; + } + if (r_item_ptr && do_item_ptr) { + *r_item_ptr = nextptr; + } + + if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || + prop_elem->index != index)) { + prop_elem = MEM_cnew<PropertyElemRNA>(__func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = index; + BLI_addtail(r_elements, prop_elem); + } + + return true; +} + +bool RNA_path_resolve(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop) +{ + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) { + return false; + } + + return r_ptr->data != NULL; +} + +bool RNA_path_resolve_full( + const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) +{ + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true)) { + return false; + } + + return r_ptr->data != NULL; +} + +bool RNA_path_resolve_full_maybe_null( + const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) +{ + return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true); +} + +bool RNA_path_resolve_property(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop) +{ + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, false)) { + return false; + } + + return r_ptr->data != NULL && *r_prop != NULL; +} + +bool RNA_path_resolve_property_full( + const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) +{ + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false)) { + return false; + } + + return r_ptr->data != NULL && *r_prop != NULL; +} + +bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + PointerRNA *r_item_ptr) +{ + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, r_item_ptr, NULL, false)) { + return false; + } + + return r_ptr->data != NULL && *r_prop != NULL; +} + +bool RNA_path_resolve_property_and_item_pointer_full(const PointerRNA *ptr, + const char *path, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index, + PointerRNA *r_item_ptr) +{ + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, r_item_ptr, NULL, false)) { + return false; + } + + return r_ptr->data != NULL && *r_prop != NULL; +} +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements) +{ + return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false); +} + +char *RNA_path_append(const char *path, + const PointerRNA *UNUSED(ptr), + PropertyRNA *prop, + int intkey, + const char *strkey) +{ + DynStr *dynstr; + char *result; + + dynstr = BLI_dynstr_new(); + + /* add .identifier */ + if (path) { + BLI_dynstr_append(dynstr, path); + if (*path) { + BLI_dynstr_append(dynstr, "."); + } + } + + BLI_dynstr_append(dynstr, RNA_property_identifier(prop)); + + if (RNA_property_type(prop) == PROP_COLLECTION) { + /* add ["strkey"] or [intkey] */ + BLI_dynstr_append(dynstr, "["); + + if (strkey) { + const int strkey_esc_max_size = (strlen(strkey) * 2) + 1; + char *strkey_esc = static_cast<char *>(BLI_array_alloca(strkey_esc, strkey_esc_max_size)); + BLI_str_escape(strkey_esc, strkey, strkey_esc_max_size); + BLI_dynstr_append(dynstr, "\""); + BLI_dynstr_append(dynstr, strkey_esc); + BLI_dynstr_append(dynstr, "\""); + } + else { + char appendstr[128]; + BLI_snprintf(appendstr, sizeof(appendstr), "%d", intkey); + BLI_dynstr_append(dynstr, appendstr); + } + + BLI_dynstr_append(dynstr, "]"); + } + + result = BLI_dynstr_get_cstring(dynstr); + BLI_dynstr_free(dynstr); + + return result; +} + +/* Having both path append & back seems like it could be useful, + * this function isn't used at the moment. */ +static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path) +{ + char fixedbuf[256]; + const char *previous, *current; + char *result; + int i; + + if (!path) { + return NULL; + } + + previous = NULL; + current = path; + + /* parse token by token until the end, then we back up to the previous + * position and strip of the next token to get the path one step back */ + while (*current) { + char *token; + + token = rna_path_token(¤t, fixedbuf, sizeof(fixedbuf)); + + if (!token) { + return NULL; + } + if (token != fixedbuf) { + MEM_freeN(token); + } + + /* in case of collection we also need to strip off [] */ + bool quoted; + token = rna_path_token_in_brackets(¤t, fixedbuf, sizeof(fixedbuf), "ed); + if (token && token != fixedbuf) { + MEM_freeN(token); + } + + if (!*current) { + break; + } + + previous = current; + } + + if (!previous) { + return NULL; + } + + /* copy and strip off last token */ + i = previous - path; + result = BLI_strdup(path); + + if (i > 0 && result[i - 1] == '.') { + i--; + } + result[i] = 0; + + return result; +} + +const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop) +{ + if (array_prop != NULL) { + if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + BLI_assert(array_prop->arraydimension == 0); + return NULL; + } + if (array_prop->arraydimension == 0) { + return NULL; + } + } + + /* Valid 'array part' of a rna path can only have '[', ']' and digit characters. + * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */ + int64_t rna_path_len = (int64_t)strlen(rna_path); + if (rna_path[rna_path_len] != ']') { + return NULL; + } + const char *last_valid_index_token_start = NULL; + for (rna_path_len--; rna_path_len >= 0; rna_path_len--) { + switch (rna_path[rna_path_len]) { + case '[': + if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') { + return &rna_path[rna_path_len]; + } + last_valid_index_token_start = &rna_path[rna_path_len]; + rna_path_len--; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + return last_valid_index_token_start; + } + } + return last_valid_index_token_start; +} + +/* generic path search func + * if its needed this could also reference the IDProperty direct */ +typedef struct IDP_Chain { + struct IDP_Chain *up; /* parent member, reverse and set to child for path conversion. */ + + const char *name; + int index; + +} IDP_Chain; + +static char *rna_idp_path_create(IDP_Chain *child_link) +{ + DynStr *dynstr = BLI_dynstr_new(); + char *path; + bool is_first = true; + + int tot = 0; + IDP_Chain *link = child_link; + + /* reverse the list */ + IDP_Chain *link_prev; + link_prev = NULL; + while (link) { + IDP_Chain *link_next = link->up; + link->up = link_prev; + link_prev = link; + link = link_next; + tot++; + } + + for (link = link_prev; link; link = link->up) { + /* pass */ + if (link->index >= 0) { + BLI_dynstr_appendf(dynstr, is_first ? "%s[%d]" : ".%s[%d]", link->name, link->index); + } + else { + BLI_dynstr_appendf(dynstr, is_first ? "%s" : ".%s", link->name); + } + + is_first = false; + } + + path = BLI_dynstr_get_cstring(dynstr); + BLI_dynstr_free(dynstr); + + if (*path == '\0') { + MEM_freeN(path); + path = NULL; + } + + return path; +} + +static char *rna_idp_path(PointerRNA *ptr, + IDProperty *haystack, + IDProperty *needle, + IDP_Chain *parent_link) +{ + char *path = NULL; + IDP_Chain link; + + IDProperty *iter; + int i; + + BLI_assert(haystack->type == IDP_GROUP); + + link.up = parent_link; + /* Always set both name and index, else a stale value might get used. */ + link.name = NULL; + link.index = -1; + + for (i = 0, iter = static_cast<IDProperty *>(haystack->data.group.first); iter; + iter = iter->next, i++) { + if (needle == iter) { /* found! */ + link.name = iter->name; + link.index = -1; + path = rna_idp_path_create(&link); + break; + } + + /* Early out in case the IDProperty type cannot contain RNA properties. */ + if (!ELEM(iter->type, IDP_GROUP, IDP_IDPARRAY)) { + continue; + } + + /* Ensure this is RNA. */ + /* NOTE: `iter` might be a fully user-defined IDProperty (a.k.a. custom data), which name + * collides with an actual fully static RNA property of the same struct (which would then not + * be flagged with `PROP_IDPROPERTY`). + * + * That case must be ignored here, we only want to deal with runtime RNA properties stored in + * IDProps. + * + * See T84091. */ + PropertyRNA *prop = RNA_struct_find_property(ptr, iter->name); + if (prop == NULL || (prop->flag & PROP_IDPROPERTY) == 0) { + continue; + } + + if (iter->type == IDP_GROUP) { + if (prop->type == PROP_POINTER) { + PointerRNA child_ptr = RNA_property_pointer_get(ptr, prop); + if (RNA_pointer_is_null(&child_ptr)) { + /* Pointer ID prop might be a 'leaf' in the IDProp group hierarchy, in which case a NULL + * value is perfectly valid. Just means it won't match the searched needle. */ + continue; + } + + link.name = iter->name; + link.index = -1; + if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) { + break; + } + } + } + else if (iter->type == IDP_IDPARRAY) { + if (prop->type == PROP_COLLECTION) { + IDProperty *array = IDP_IDPArray(iter); + if (needle >= array && needle < (iter->len + array)) { /* found! */ + link.name = iter->name; + link.index = (int)(needle - array); + path = rna_idp_path_create(&link); + break; + } + int j; + link.name = iter->name; + for (j = 0; j < iter->len; j++, array++) { + PointerRNA child_ptr; + if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) { + if (RNA_pointer_is_null(&child_ptr)) { + /* Array item ID prop might be a 'leaf' in the IDProp group hierarchy, in which case + * a NULL value is perfectly valid. Just means it won't match the searched needle. */ + continue; + } + link.index = j; + if ((path = rna_idp_path(&child_ptr, array, needle, &link))) { + break; + } + } + } + if (path) { + break; + } + } + } + } + + return path; +} + +char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle) +{ + IDProperty *haystack = RNA_struct_idprops(ptr, false); + + if (haystack) { /* can fail when called on bones */ + return rna_idp_path(ptr, haystack, needle, NULL); + } + return NULL; +} + +static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr) +{ + PointerRNA id_ptr; + + BLI_assert(ptr->owner_id != NULL); + + /* TODO: Support Bones/PoseBones. no pointers stored to the bones from here, only the ID. + * See example in T25746. + * Unless this is added only way to find this is to also search + * all bones and pose bones of an armature or object. + */ + RNA_id_pointer_create(ptr->owner_id, &id_ptr); + + return RNA_path_from_struct_to_idproperty(&id_ptr, static_cast<IDProperty *>(ptr->data)); +} + +ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path) +{ + if (r_path) { + *r_path = ""; + } + + if ((id == NULL) || (id->flag & LIB_EMBEDDED_DATA) == 0) { + return id; + } + + const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); + if (r_path) { + switch (GS(id->name)) { + case ID_NT: + *r_path = "node_tree"; + break; + case ID_GR: + *r_path = "collection"; + break; + default: + BLI_assert_msg(0, "Missing handling of embedded id type."); + } + } + + if (id_type->owner_get == NULL) { + BLI_assert_msg(0, "Missing handling of embedded id type."); + return id; + } + return id_type->owner_get(bmain, id); +} + +static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_real_id) +{ + if (r_real_id != NULL) { + *r_real_id = NULL; + } + + const char *prefix; + ID *real_id = RNA_find_real_ID_and_path(bmain, id, &prefix); + + if (r_real_id != NULL) { + *r_real_id = real_id; + } + + if (path != NULL) { + char *new_path = NULL; + + if (real_id) { + if (prefix[0]) { + new_path = BLI_sprintfN("%s%s%s", prefix, path[0] == '[' ? "" : ".", path); + } + else { + return path; + } + } + + MEM_freeN(path); + return new_path; + } + return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL; +} + +char *RNA_path_from_ID_to_struct(const PointerRNA *ptr) +{ + char *ptrpath = NULL; + + if (!ptr->owner_id || !ptr->data) { + return NULL; + } + + if (!RNA_struct_is_ID(ptr->type)) { + if (ptr->type->path) { + /* if type has a path to some ID, use it */ + ptrpath = ptr->type->path((PointerRNA *)ptr); + } + else if (ptr->type->nested && RNA_struct_is_ID(ptr->type->nested)) { + PointerRNA parentptr; + PropertyRNA *userprop; + + /* find the property in the struct we're nested in that references this struct, and + * use its identifier as the first part of the path used... + */ + RNA_id_pointer_create(ptr->owner_id, &parentptr); + userprop = rna_struct_find_nested(&parentptr, ptr->type); + + if (userprop) { + ptrpath = BLI_strdup(RNA_property_identifier(userprop)); + } + else { + return NULL; /* can't do anything about this case yet... */ + } + } + else if (RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) { + /* special case, easier to deal with here than in ptr->type->path() */ + return rna_path_from_ID_to_idpgroup(ptr); + } + else { + return NULL; + } + } + + return ptrpath; +} + +char *RNA_path_from_real_ID_to_struct(Main *bmain, const PointerRNA *ptr, struct ID **r_real) +{ + char *path = RNA_path_from_ID_to_struct(ptr); + + /* NULL path is valid in that case, when given struct is an ID one... */ + return rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real); +} + +static void rna_path_array_multi_from_flat_index(const int dimsize[RNA_MAX_ARRAY_LENGTH], + const int totdims, + const int index_dim, + int index, + int r_index_multi[RNA_MAX_ARRAY_LENGTH]) +{ + int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1]; + int i = totdims - 1; + dimsize_step[i + 1] = 1; + dimsize_step[i] = dimsize[i]; + while (--i != -1) { + dimsize_step[i] = dimsize[i] * dimsize_step[i + 1]; + } + while (++i != index_dim) { + int index_round = index / dimsize_step[i + 1]; + r_index_multi[i] = index_round; + index -= (index_round * dimsize_step[i + 1]); + } + BLI_assert(index == 0); +} + +static void rna_path_array_multi_string_from_flat_index(const PointerRNA *ptr, + PropertyRNA *prop, + int index_dim, + int index, + char *index_str, + int index_str_len) +{ + int dimsize[RNA_MAX_ARRAY_LENGTH]; + int totdims = RNA_property_array_dimension(ptr, prop, dimsize); + int index_multi[RNA_MAX_ARRAY_LENGTH]; + + rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi); + + for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) { + offset += BLI_snprintf_rlen( + &index_str[offset], index_str_len - offset, "[%d]", index_multi[i]); + } +} + +char *RNA_path_from_ID_to_property_index(const PointerRNA *ptr, + PropertyRNA *prop, + int index_dim, + int index) +{ + const bool is_rna = (prop->magic == RNA_MAGIC); + const char *propname; + char *ptrpath, *path; + + if (!ptr->owner_id || !ptr->data) { + return NULL; + } + + /* path from ID to the struct holding this property */ + ptrpath = RNA_path_from_ID_to_struct(ptr); + + propname = RNA_property_identifier(prop); + + /* support indexing w/ multi-dimensional arrays */ + char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1]; + if (index_dim == 0) { + index_str[0] = '\0'; + } + else { + rna_path_array_multi_string_from_flat_index( + ptr, prop, index_dim, index, index_str, sizeof(index_str)); + } + + if (ptrpath) { + if (is_rna) { + path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str); + } + else { + char propname_esc[MAX_IDPROP_NAME * 2]; + BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); + path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str); + } + MEM_freeN(ptrpath); + } + else if (RNA_struct_is_ID(ptr->type)) { + if (is_rna) { + path = BLI_sprintfN("%s%s", propname, index_str); + } + else { + char propname_esc[MAX_IDPROP_NAME * 2]; + BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); + path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str); + } + } + else { + path = NULL; + } + + return path; +} + +char *RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop) +{ + return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1); +} + +char *RNA_path_from_real_ID_to_property_index(Main *bmain, + const PointerRNA *ptr, + PropertyRNA *prop, + int index_dim, + int index, + ID **r_real_id) +{ + char *path = RNA_path_from_ID_to_property_index(ptr, prop, index_dim, index); + + /* NULL path is always an error here, in that case do not return the 'fake ID from real ID' part + * of the path either. */ + return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL; +} + +char *RNA_path_resolve_from_type_to_property(const PointerRNA *ptr, + PropertyRNA *prop, + const StructRNA *type) +{ + /* Try to recursively find an "type"'d ancestor, + * to handle situations where path from ID is not enough. */ + PointerRNA idptr; + ListBase path_elems = {NULL}; + char *path = NULL; + char *full_path = RNA_path_from_ID_to_property(ptr, prop); + + if (full_path == NULL) { + return NULL; + } + + RNA_id_pointer_create(ptr->owner_id, &idptr); + + if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) { + LISTBASE_FOREACH_BACKWARD (PropertyElemRNA *, prop_elem, &path_elems) { + if (RNA_struct_is_a(prop_elem->ptr.type, type)) { + char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr); + if (ref_path) { + path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */ + MEM_freeN(ref_path); + } + break; + } + } + + BLI_freelistN(&path_elems); + } + + MEM_freeN(full_path); + return path; +} + +char *RNA_path_full_ID_py(Main *bmain, ID *id) +{ + const char *path; + ID *id_real = RNA_find_real_ID_and_path(bmain, id, &path); + + if (id_real) { + id = id_real; + } + else { + path = ""; + } + + char lib_filepath_esc[(sizeof(id->lib->filepath) * 2) + 4]; + if (ID_IS_LINKED(id)) { + int ofs = 0; + memcpy(lib_filepath_esc, ", \"", 3); + ofs += 3; + ofs += BLI_str_escape(lib_filepath_esc + ofs, id->lib->filepath, sizeof(lib_filepath_esc)); + memcpy(lib_filepath_esc + ofs, "\"", 2); + } + else { + lib_filepath_esc[0] = '\0'; + } + + char id_esc[(sizeof(id->name) - 2) * 2]; + BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc)); + + return BLI_sprintfN("bpy.data.%s[\"%s\"%s]%s%s", + BKE_idtype_idcode_to_name_plural(GS(id->name)), + id_esc, + lib_filepath_esc, + path[0] ? "." : "", + path); +} + +char *RNA_path_full_struct_py(Main *bmain, const PointerRNA *ptr) +{ + char *id_path; + char *data_path; + + char *ret; + + if (!ptr->owner_id) { + return NULL; + } + + /* never fails */ + id_path = RNA_path_full_ID_py(bmain, ptr->owner_id); + + data_path = RNA_path_from_ID_to_struct(ptr); + + /* XXX data_path may be NULL (see T36788), + * do we want to get the 'bpy.data.foo["bar"].(null)' stuff? */ + ret = BLI_sprintfN("%s.%s", id_path, data_path); + + if (data_path) { + MEM_freeN(data_path); + } + MEM_freeN(id_path); + + return ret; +} + +char *RNA_path_full_property_py_ex( + Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback) +{ + char *id_path; + const char *data_delim; + const char *data_path; + bool data_path_free; + + char *ret; + + if (!ptr->owner_id) { + return NULL; + } + + /* never fails */ + id_path = RNA_path_full_ID_py(bmain, ptr->owner_id); + + data_path = RNA_path_from_ID_to_property(ptr, prop); + if (data_path) { + data_delim = (data_path[0] == '[') ? "" : "."; + data_path_free = true; + } + else { + if (use_fallback) { + /* Fuzzy fallback. Be explicit in our ignorance. */ + data_path = RNA_property_identifier(prop); + data_delim = " ... "; + } + else { + data_delim = "."; + } + data_path_free = false; + } + + if ((index == -1) || (RNA_property_array_check(prop) == false)) { + ret = BLI_sprintfN("%s%s%s", id_path, data_delim, data_path); + } + else { + ret = BLI_sprintfN("%s%s%s[%d]", id_path, data_delim, data_path, index); + } + MEM_freeN(id_path); + if (data_path_free) { + MEM_freeN((void *)data_path); + } + + return ret; +} + +char *RNA_path_full_property_py(Main *bmain, const PointerRNA *ptr, PropertyRNA *prop, int index) +{ + return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false); +} + +char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) +{ + char *data_path; + + char *ret; + + if (!ptr->owner_id) { + return NULL; + } + + data_path = RNA_path_from_ID_to_property(ptr, prop); + + if (data_path == NULL) { + /* This may not be an ID at all, check for simple when pointer owns property. + * TODO: more complex nested case. */ + if (!RNA_struct_is_ID(ptr->type)) { + const char *prop_identifier = RNA_property_identifier(prop); + if (RNA_struct_find_property(ptr, prop_identifier) == prop) { + data_path = BLI_strdup(prop_identifier); + } + } + } + + if ((index == -1) || (RNA_property_array_check(prop) == false)) { + ret = BLI_strdup(data_path); + } + else { + ret = BLI_sprintfN("%s[%d]", data_path, index); + } + + if (data_path) { + MEM_freeN(data_path); + } + + return ret; +} + +char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index) +{ + const bool is_rna = (prop->magic == RNA_MAGIC); + const char *propname = RNA_property_identifier(prop); + char *ret; + + if ((index == -1) || (RNA_property_array_check(prop) == false)) { + if (is_rna) { + ret = BLI_strdup(propname); + } + else { + char propname_esc[MAX_IDPROP_NAME * 2]; + BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); + ret = BLI_sprintfN("[\"%s\"]", propname_esc); + } + } + else { + if (is_rna) { + ret = BLI_sprintfN("%s[%d]", propname, index); + } + else { + char propname_esc[MAX_IDPROP_NAME * 2]; + BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); + ret = BLI_sprintfN("[\"%s\"][%d]", propname_esc, index); + } + } + + return ret; +} diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index dabb89bcd5e..adb959944b5 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -473,7 +473,7 @@ static int rna_UIList_list_id_length(PointerRNA *ptr) } static void uilist_draw_item(uiList *ui_list, - bContext *C, + const bContext *C, uiLayout *layout, PointerRNA *dataptr, PointerRNA *itemptr, @@ -507,7 +507,7 @@ static void uilist_draw_item(uiList *ui_list, RNA_parameter_list_free(&list); } -static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout) +static void uilist_draw_filter(uiList *ui_list, const bContext *C, uiLayout *layout) { extern FunctionRNA rna_UIList_draw_filter_func; @@ -527,7 +527,7 @@ static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout) } static void uilist_filter_items(uiList *ui_list, - bContext *C, + const bContext *C, PointerRNA *dataptr, const char *propname) { diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 223e4b757b7..72978d6410a 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -40,7 +40,7 @@ #include "BKE_geometry_fields.hh" #include "BKE_geometry_set_instances.hh" #include "BKE_global.h" -#include "BKE_idprop.h" +#include "BKE_idprop.hh" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" @@ -416,15 +416,16 @@ static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int soc return field_interface.inputs[socket_index] != InputSocketFieldType::None; } -static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) +static std::unique_ptr<IDProperty, blender::bke::idprop::IDPropertyDeleter> +id_property_create_from_socket(const bNodeSocket &socket) { + using namespace blender; switch (socket.type) { case SOCK_FLOAT: { - bNodeSocketValueFloat *value = (bNodeSocketValueFloat *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.f = value->value; - IDProperty *property = IDP_New(IDP_FLOAT, &idprop, socket.identifier); - IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property); + const bNodeSocketValueFloat *value = static_cast<const bNodeSocketValueFloat *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, value->value); + IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = value->subtype; ui_data->min = ui_data->soft_min = (double)value->min; ui_data->max = ui_data->soft_max = (double)value->max; @@ -432,11 +433,10 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_INT: { - bNodeSocketValueInt *value = (bNodeSocketValueInt *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.i = value->value; - IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier); - IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property); + const bNodeSocketValueInt *value = static_cast<const bNodeSocketValueInt *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, value->value); + IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = value->subtype; ui_data->min = ui_data->soft_min = value->min; ui_data->max = ui_data->soft_max = value->max; @@ -444,13 +444,11 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_VECTOR: { - bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.array.len = 3; - idprop.array.type = IDP_FLOAT; - IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier); - copy_v3_v3((float *)IDP_Array(property), value->value); - IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property); + const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>( + socket.default_value); + auto property = bke::idprop::create( + socket.identifier, Span<float>{value->value[0], value->value[1], value->value[2]}); + IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = value->subtype; ui_data->min = ui_data->soft_min = (double)value->min; ui_data->max = ui_data->soft_max = (double)value->max; @@ -462,13 +460,12 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_RGBA: { - bNodeSocketValueRGBA *value = (bNodeSocketValueRGBA *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.array.len = 4; - idprop.array.type = IDP_FLOAT; - IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier); - copy_v4_v4((float *)IDP_Array(property), value->value); - IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property); + const bNodeSocketValueRGBA *value = static_cast<const bNodeSocketValueRGBA *>( + socket.default_value); + auto property = bke::idprop::create( + socket.identifier, + Span<float>{value->value[0], value->value[1], value->value[2], value->value[3]}); + IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get()); ui_data->base.rna_subtype = PROP_COLOR; ui_data->default_array = (double *)MEM_mallocN(sizeof(double[4]), __func__); ui_data->default_array_len = 4; @@ -482,53 +479,48 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) return property; } case SOCK_BOOLEAN: { - bNodeSocketValueBoolean *value = (bNodeSocketValueBoolean *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.i = value->value != 0; - IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier); - IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property); + const bNodeSocketValueBoolean *value = static_cast<const bNodeSocketValueBoolean *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, int(value->value)); + IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get()); ui_data->min = ui_data->soft_min = 0; ui_data->max = ui_data->soft_max = 1; ui_data->default_value = value->value != 0; return property; } case SOCK_STRING: { - bNodeSocketValueString *value = (bNodeSocketValueString *)socket.default_value; - IDProperty *property = IDP_NewString( - value->value, socket.identifier, BLI_strnlen(value->value, sizeof(value->value)) + 1); - IDPropertyUIDataString *ui_data = (IDPropertyUIDataString *)IDP_ui_data_ensure(property); + const bNodeSocketValueString *value = static_cast<const bNodeSocketValueString *>( + socket.default_value); + auto property = bke::idprop::create(socket.identifier, value->value); + IDPropertyUIDataString *ui_data = (IDPropertyUIDataString *)IDP_ui_data_ensure( + property.get()); ui_data->default_value = BLI_strdup(value->value); return property; } case SOCK_OBJECT: { - bNodeSocketValueObject *value = (bNodeSocketValueObject *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueObject *value = static_cast<const bNodeSocketValueObject *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_COLLECTION: { - bNodeSocketValueCollection *value = (bNodeSocketValueCollection *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueCollection *value = static_cast<const bNodeSocketValueCollection *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_TEXTURE: { - bNodeSocketValueTexture *value = (bNodeSocketValueTexture *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueTexture *value = static_cast<const bNodeSocketValueTexture *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_IMAGE: { - bNodeSocketValueImage *value = (bNodeSocketValueImage *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueImage *value = static_cast<const bNodeSocketValueImage *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } case SOCK_MATERIAL: { - bNodeSocketValueMaterial *value = (bNodeSocketValueMaterial *)socket.default_value; - IDPropertyTemplate idprop = {0}; - idprop.id = (ID *)value->value; - return IDP_New(IDP_ID, &idprop, socket.identifier); + const bNodeSocketValueMaterial *value = static_cast<const bNodeSocketValueMaterial *>( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value)); } } return nullptr; @@ -658,7 +650,7 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) int socket_index; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) { - IDProperty *new_prop = id_property_create_from_socket(*socket); + IDProperty *new_prop = id_property_create_from_socket(*socket).release(); if (new_prop == nullptr) { /* Out of the set of supported input sockets, only * geometry sockets aren't added to the modifier. */ diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index e43d2b4ad85..5cf4e21ea68 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -1863,6 +1863,7 @@ bool NodeParamsProvider::lazy_require_input(StringRef identifier) void NodeParamsProvider::set_input_unused(StringRef identifier) { + BLI_assert(node_supports_laziness(this->dnode)); const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 80af23054e4..4b744cd8350 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -53,7 +53,13 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) * \param poly_nors: Precalculated face normals. * \param r_vert_nors: Return vert normals. */ -static void mesh_calc_hq_normal(Mesh *mesh, const float (*poly_nors)[3], float (*r_vert_nors)[3]) +static void mesh_calc_hq_normal(Mesh *mesh, + const float (*poly_nors)[3], + float (*r_vert_nors)[3], +#ifdef USE_NONMANIFOLD_WORKAROUND + BLI_bitmap *edge_tmp_tag +#endif +) { int i, verts_num, edges_num, polys_num; MPoly *mpoly, *mp; @@ -103,7 +109,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, const float (*poly_nors)[3], float ( /* 3+ faces using an edge, we can't handle this usefully */ edge_ref->p1 = edge_ref->p2 = -1; #ifdef USE_NONMANIFOLD_WORKAROUND - medge[ml->e].flag |= ME_EDGE_TMP_TAG; + BLI_BITMAP_ENABLE(edge_tmp_tag, ml->e); #endif } /* --- done --- */ @@ -319,9 +325,20 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex BLI_assert(newEdges == 0); } +#ifdef USE_NONMANIFOLD_WORKAROUND + BLI_bitmap *edge_tmp_tag = BLI_BITMAP_NEW(mesh->totedge, __func__); +#endif + if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { vert_nors = MEM_calloc_arrayN(verts_num, sizeof(float[3]), "mod_solid_vno_hq"); - mesh_calc_hq_normal(mesh, poly_nors, vert_nors); + mesh_calc_hq_normal(mesh, + poly_nors, + vert_nors +#ifdef USE_NONMANIFOLD_WORKAROUND + , + edge_tmp_tag +#endif + ); } result = BKE_mesh_new_nomain_from_template(mesh, @@ -740,8 +757,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex #ifdef USE_NONMANIFOLD_WORKAROUND /* skip 3+ face user edges */ if ((check_non_manifold == false) || - LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) && - ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) { + LIKELY(!BLI_BITMAP_TEST(edge_tmp_tag, ml[i_curr].e) && + !BLI_BITMAP_TEST(edge_tmp_tag, ml[i_next].e))) { vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle; } @@ -949,6 +966,10 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex MEM_freeN(vert_angles); } +#ifdef USE_NONMANIFOLD_WORKAROUND + MEM_SAFE_FREE(edge_tmp_tag); +#endif + if (vert_nors) { MEM_freeN(vert_nors); } diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index 32b5d98a556..6efe6f231f5 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -183,6 +183,7 @@ void register_node_tree_type_cmp() tt->type = NTREE_COMPOSIT; strcpy(tt->idname, "CompositorNodeTree"); + strcpy(tt->group_idname, "CompositorNodeGroup"); strcpy(tt->ui_name, N_("Compositor")); tt->ui_icon = ICON_NODE_COMPOSITING; strcpy(tt->ui_description, N_("Compositing nodes")); diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index 38e914b9a9f..e3998322741 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -109,6 +109,7 @@ void register_node_tree_type_geo() MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type")); tt->type = NTREE_GEOMETRY; strcpy(tt->idname, "GeometryNodeTree"); + strcpy(tt->group_idname, "GeometryNodeGroup"); strcpy(tt->ui_name, N_("Geometry Node Editor")); tt->ui_icon = ICON_GEOMETRY_NODES; strcpy(tt->ui_description, N_("Geometry nodes")); diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index 43dbf5060bd..02ac54f4b2b 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -166,6 +166,7 @@ void register_node_tree_type_sh() tt->type = NTREE_SHADER; strcpy(tt->idname, "ShaderNodeTree"); + strcpy(tt->group_idname, "ShaderNodeGroup"); strcpy(tt->ui_name, N_("Shader Editor")); tt->ui_icon = ICON_NODE_MATERIAL; strcpy(tt->ui_description, N_("Shader nodes")); diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt index 5bed54ebfd7..2ccdf4c0bc9 100644 --- a/source/blender/nodes/texture/CMakeLists.txt +++ b/source/blender/nodes/texture/CMakeLists.txt @@ -15,6 +15,7 @@ set(INC ../../render ../../windowmanager ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 03dc61af9a2..ac105b5bcb9 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -140,6 +140,7 @@ void register_node_tree_type_tex(void) tt->type = NTREE_TEXTURE; strcpy(tt->idname, "TextureNodeTree"); + strcpy(tt->group_idname, "TextureNodeGroup"); strcpy(tt->ui_name, N_("Texture Node Editor")); tt->ui_icon = ICON_NODE_TEXTURE; /* Defined in `drawnode.c`. */ strcpy(tt->ui_description, N_("Texture nodes")); diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index 656024ae22c..b877e3ceb98 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -55,6 +55,34 @@ static PyObject *pygpu_platform_version_get(PyObject *UNUSED(self)) return PyUnicode_FromString(GPU_platform_version()); } +PyDoc_STRVAR( + pygpu_platform_device_type_get_doc, + ".. function:: device_type_get()\n" + "\n" + " Get GPU device type.\n" + "\n" + " :return: Device type ('APPLE', 'NVIDIA', 'AMD', 'INTEL', 'SOFTWARE', 'UNKNOWN').\n" + " :rtype: str\n"); +static PyObject *pygpu_platform_device_type_get(PyObject *UNUSED(self)) +{ + if (GPU_type_matches(GPU_DEVICE_APPLE, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("APPLE"); + } + if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("NVIDIA"); + } + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("AMD"); + } + if (GPU_type_matches(GPU_DEVICE_INTEL | GPU_DEVICE_INTEL_UHD, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("INTEL"); + } + if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_ANY, GPU_DRIVER_ANY)) { + return PyUnicode_FromString("SOFTWARE"); + } + return PyUnicode_FromString("UNKNOWN"); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -74,6 +102,10 @@ static struct PyMethodDef pygpu_platform__tp_methods[] = { (PyCFunction)pygpu_platform_version_get, METH_NOARGS, pygpu_platform_version_get_doc}, + {"device_type_get", + (PyCFunction)pygpu_platform_device_type_get, + METH_NOARGS, + pygpu_platform_device_type_get_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index 101b9f8e4c6..e3f789aa58d 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -31,16 +31,16 @@ #define PYDOC_BUILTIN_SHADER_DESCRIPTION \ "``2D_FLAT_COLOR``\n" \ - " :Attributes: vec3 pos, vec4 color\n" \ + " :Attributes: vec2 pos, vec4 color\n" \ " :Uniforms: none\n" \ "``2D_IMAGE``\n" \ - " :Attributes: vec3 pos, vec2 texCoord\n" \ + " :Attributes: vec2 pos, vec2 texCoord\n" \ " :Uniforms: sampler2D image\n" \ "``2D_SMOOTH_COLOR``\n" \ - " :Attributes: vec3 pos, vec4 color\n" \ + " :Attributes: vec2 pos, vec4 color\n" \ " :Uniforms: none\n" \ "``2D_UNIFORM_COLOR``\n" \ - " :Attributes: vec3 pos\n" \ + " :Attributes: vec2 pos\n" \ " :Uniforms: vec4 color\n" \ "``3D_FLAT_COLOR``\n" \ " :Attributes: vec3 pos, vec4 color\n" \ diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 14be9ceda94..d9c004fb6fa 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -15,6 +15,7 @@ #include <float.h> /* FLT_MIN/MAX */ #include <stddef.h> +#include "RNA_path.h" #include "RNA_types.h" #include "BLI_bitmap.h" diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index f25e9d0bbbc..d4a164d9482 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -32,6 +32,7 @@ #include "RNA_access.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "WM_api.h" diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index a184f727b9e..53a969d7fea 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -836,7 +836,7 @@ static bool seq_read_lib_cb(Sequence *seq, void *user_data) BlendLibReader *reader = data->reader; Scene *sce = data->scene; - IDP_BlendReadLib(reader, seq->prop); + IDP_BlendReadLib(reader, sce->id.lib, seq->prop); if (seq->ipo) { /* XXX: deprecated - old animation system. */ diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 7a36020cea5..6cbd21d0abe 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/memutil + ../bmesh # for writefile.c: dna_type_offsets.h ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 5e7fe4678f6..d90259c0cde 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -5174,7 +5174,7 @@ static bool wm_event_is_ignorable_key_press(const wmWindow *win, const wmEvent & return false; } - const wmEvent &last_event = *reinterpret_cast<const wmEvent *>(win->event_queue.last); + const wmEvent &last_event = *static_cast<const wmEvent *>(win->event_queue.last); return wm_event_is_same_key_press(last_event, event); } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 315e4c994ad..1dc2307ba14 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -81,6 +81,7 @@ #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "UI_interface.h" diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c index be153195cee..5c745c32d2c 100644 --- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c @@ -20,6 +20,7 @@ #include "message_bus/intern/wm_message_bus_intern.h" #include "RNA_access.h" +#include "RNA_path.h" /* -------------------------------------------------------------------- */ /** \name Internal Utilities diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 278cd4362c3..11f48a72908 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1216,10 +1216,8 @@ unset(LIB) setup_platform_linker_flags(blender) setup_platform_linker_libs(blender) -if(APPLE) - set_target_properties(blender PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/osx_locals.map) -elseif(UNIX) - set_target_properties(blender PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/blender.map) +if(DEFINED PLATFORM_SYMBOLS_MAP) + set_target_properties(blender PROPERTIES LINK_DEPENDS ${PLATFORM_SYMBOLS_MAP}) endif() # ----------------------------------------------------------------------------- diff --git a/source/creator/blender.map b/source/creator/blender.map deleted file mode 100644 index 500892a20f3..00000000000 --- a/source/creator/blender.map +++ /dev/null @@ -1,173 +0,0 @@ - -/* on Linux we exclude LLVM symbols, they conflict with Mesa llvmpipe - * we also keep boost's symbols local, since some python modules could - * be using boost as well (mainly that's for lux render) - */ - -{ -global: - *; - *_boost*; -local: - __once_proxy; - _ZSt11__once_call; - _ZSt15__once_callable; - al*; - *Alembic*; - av*; - blosc*; - *boost*; - *ceres*; - *cineon*; - *clang*; - *COLLADA*; - cu*; - *default_error_condition*; - *dpx*; - *embree*; - ff_*; - fftw*; - FLAC*; - FT_*; - *GeneratedSaxParser*; - *google*; - gsm*; - Gsm*; - html*; - id3tag*; - *Iex*; - *Ilm*; - *Imath*; - *Imf*; - jack_*; - jpeg_*; - jsimd**; - lame_*; - *llvm*; - *LLVM*; - *MathML*; - *mkldnn*; - nvrtc*; - oc_*; - ogg*; - *oidn*; - *OpenColorIO*; - *OpenImageIO*; - *OpenSubdiv*; - *openvdb*; - opj_*; - opus_*; - *OSL*; - *pathYy*; - png_*; - *SDL*; - *squish*; - *tbb*; - *textFileFormatYy*; - *TIFF*; - *tinyformat*; - *usdBlender*; - vorbis*; - vp8*; - vp9*; - vpx*; - x264_*; - xml*; - xvid*; - *YAML*; - - /* LLVM symbols not in the LLVM namespace that can conflict with LLVM usage - * in OpenGL and OpenCL drivers. - * - * These are found by doing a Blender build with and without OSL, and - * comparing the output of nm -gD ./bin/blender to find symbols. */ - AlwaysSpillBase; - AsmMacroMaxNestingDepth; - AttributorRun; - CheckBFIUnknownBlockQueries; - *cloneBitwiseIVUser*; - *computeHostNumHardwareThread*; - *computeHostNumPhysicalCores*; - decodeInstruction; - DisableBasicAA; - DisablePreInliner; - DisableWholeProgramVisibility; - EnableCHR; - EnableConstraintElimination; - EnableGVNHoist; - EnableGVNSink; - EnableHotColdSplit; - EnableIPRA; - EnableIROutliner; - EnableKnowledgeRetention; - EnableLoopFlatten; - EnableMatrix; - EnableOrderFileInstrumentation; - EnablePGSO; - EnableUnrollAndJam; - EnableVPlanNativePath; - EnableVPlanPredication; - ExtraVectorizerPasses; - FlattenedProfileUsed; - ForcePGSO; - ForceStackAlign; - ForceSummaryEdgesCold; - FSEC; - *getExtendedOperandRecurrence*; - *getWideRecurrence*; - InlinerFunctionImportStats; - *IROutlinerLegacyPass*; - __jit_debug_descriptor; - __jit_debug_register_code; - _Jv_RegisterClasses; - *LiveDebugValues*; - *LoopInterchangeLegacyPass*; - MachineRegionInfoPassID; - MaxDevirtIterations; - MaxRegistersForGCPointers; - MemOPOptMemcmpBcmp; - MemOPSizeLarge; - MemOPSizeRange; - MISchedPostRA; - ModuleSummaryDotFile; - __morestack; - Name; - NumNamedVarArgParams; - PGOViewCounts; - PGSOColdCodeOnly; - PGSOColdCodeOnlyForInstrPGO; - PGSOColdCodeOnlyForPartialSamplePGO; - PGSOColdCodeOnlyForSamplePGO; - PgsoCutoffInstrProf; - PgsoCutoffSampleProf; - PGSOLargeWorkingSetSizeOnly; - PreInlineThreshold; - PrintBlockFreqFuncName; - PrintBranchProbFuncName; - ProfileLikelyProb; - RunNewGVN; - RunPartialInlining; - RunSLPVectorization; - ScalePartialSampleProfileWorkingSetSize; - *ScopedAliasMetadataDeepCloner*; - ShouldPreserveAllAttributes; - SkipFunctionNames; - StartAfterOptName; - StartBeforeOptName; - StaticLikelyProb; - StopAfterOptName; - StopBeforeOptName; - UseContextLessSummary; - UseDbgAddr; - UseLEB128Directives; - UseRegistersForDeoptValues; - UseRegistersForGCPointersInLandingPad; - ViewBlockFreqFuncName; - ViewBlockLayoutWithBFI; - ViewHotFreqPercent; - WholeProgramVisibility; - *widenLoopCompare*; - *widenWithVariant*; - WriteRelBFToSummary; - X86CompilationCallback*; -}; diff --git a/source/creator/osx_locals.map b/source/creator/symbols_apple.map index 5619f151bd2..5619f151bd2 100644 --- a/source/creator/osx_locals.map +++ b/source/creator/symbols_apple.map diff --git a/source/creator/symbols_unix.map b/source/creator/symbols_unix.map new file mode 100644 index 00000000000..673c402022d --- /dev/null +++ b/source/creator/symbols_unix.map @@ -0,0 +1,44 @@ +/* Hide all symbols except a few required ones. + * + * Otherwise LLVM symbols conflict with Mesa llvm pipe, boost symbols conflict + * with Luxrender, etc. */ +{ +global: + /* Essential symbols for the program to start and exit. */ + _bss_start; + __end; + _fini; + _init; + /* Needed for Python modules to work. */ + Py*; + _Py*; + /* Needed for sanitizers. Based on: + * llvm/compiler-rt/lib/sanitizer_common/scripts/gen_dynamic_list.py. */ + __asan*; + __lsan*; + __tsan*; + __ubsan*; + __sanitizer*; + __Znw*; + __Zna*; + __Zdl*; + __Zda*; + aligned_alloc; + aligned_free; + calloc*; + free; + mallinfo; + malloc*; + mallopt; + memalign; + memcpy; + posix_memalign; + pthread_*; + pvalloc; + realloc*; + realpath; + sched_*; + valloc; +local: + *; +}; diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py index 68895291044..34c15872a11 100644 --- a/tests/python/eevee_render_tests.py +++ b/tests/python/eevee_render_tests.py @@ -3,6 +3,7 @@ import argparse import os +import pathlib import shlex import shutil import subprocess @@ -98,6 +99,26 @@ if inside_blender: print(e) sys.exit(1) +def get_gpu_device_type(blender): + command = [ + blender, + "-noaudio", + "--background" + "--factory-startup", + "--python", + str(pathlib.Path(__file__).parent / "gpu_info.py") + ] + try: + completed_process = subprocess.run(command, stdout=subprocess.PIPE) + for line in completed_process.stdout.read_text(): + if line.startswith("GPU_DEVICE_TYPE:"): + vendor = line.split(':')[1] + return vendor + except BaseException as e: + return None + return None + + def get_arguments(filepath, output_filepath): return [ @@ -134,10 +155,16 @@ def main(): idiff = args.idiff[0] output_dir = args.outdir[0] + gpu_device_type = get_gpu_device_type(blender) + reference_override_dir = None + if gpu_device_type == "AMD": + reference_override_dir = "eevee_renders/amd" + from modules import render_report report = render_report.Report("Eevee", output_dir, idiff) report.set_pixelated(True) report.set_reference_dir("eevee_renders") + report.set_reference_override_dir(reference_override_dir) report.set_compare_engine('cycles', 'CPU') test_dir_name = Path(test_dir).name diff --git a/tests/python/gpu_info.py b/tests/python/gpu_info.py new file mode 100644 index 00000000000..1df23d68000 --- /dev/null +++ b/tests/python/gpu_info.py @@ -0,0 +1,24 @@ +""" + Prints GPU backend information to the console and exits. + + Use this script as `blender --background --python gpu_info.py`. +""" +import bpy +import gpu +import sys + +# Render with workbench to initialize the GPU backend otherwise it would fail when running in +# background mode as the GPU backend won't be initialized. +scene = bpy.context.scene +scene.render.resolution_x = 1 +scene.render.resolution_y = 1 +scene.render.engine = "BLENDER_WORKBENCH" +bpy.ops.render.render(animation=False, write_still=False) + + +print('GPU_VENDOR:' + gpu.platform.vendor_get()) +print('GPU_RENDERER:' + gpu.platform.renderer_get()) +print('GPU_VERSION:' + gpu.platform.version_get()) +print('GPU_DEVICE_TYPE:' + gpu.platform.device_type_get()) + +sys.exit(0)
\ No newline at end of file diff --git a/tests/python/modules/render_report.py b/tests/python/modules/render_report.py index 15441918800..52f388586d8 100755 --- a/tests/python/modules/render_report.py +++ b/tests/python/modules/render_report.py @@ -78,12 +78,18 @@ def test_get_name(filepath): return os.path.splitext(filename)[0] -def test_get_images(output_dir, filepath, reference_dir): +def test_get_images(output_dir, filepath, reference_dir, reference_override_dir): testname = test_get_name(filepath) dirpath = os.path.dirname(filepath) old_dirpath = os.path.join(dirpath, reference_dir) old_img = os.path.join(old_dirpath, testname + ".png") + if reference_override_dir: + override_dirpath = os.path.join(dirpath, reference_override_dir) + override_img = os.path.join(override_dirpath, testname + ".png") + if os.path.exists(override_img): + old_dirpath = override_dirpath + old_img = override_img ref_dirpath = os.path.join(output_dir, os.path.basename(dirpath), "ref") ref_img = os.path.join(ref_dirpath, testname + ".png") @@ -108,6 +114,7 @@ class Report: 'output_dir', 'global_dir', 'reference_dir', + 'reference_override_dir', 'idiff', 'pixelated', 'fail_threshold', @@ -127,6 +134,7 @@ class Report: self.output_dir = output_dir self.global_dir = os.path.dirname(output_dir) self.reference_dir = 'reference_renders' + self.reference_override_dir = None self.idiff = idiff self.compare_engine = None self.fail_threshold = 0.016 @@ -161,6 +169,9 @@ class Report: def set_reference_dir(self, reference_dir): self.reference_dir = reference_dir + def set_reference_override_dir(self, reference_override_dir): + self.reference_override_dir = reference_override_dir + def set_compare_engine(self, other_engine, other_device=None): self.compare_engine = (other_engine, other_device) @@ -343,7 +354,7 @@ class Report: name = test_get_name(filepath) name = name.replace('_', ' ') - old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath, self.reference_dir) + old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath, self.reference_dir, self.reference_override_dir) status = error if error else "" tr_style = """ class="table-danger" """ if error else "" @@ -390,7 +401,7 @@ class Report: self.compare_tests += test_html def _diff_output(self, filepath, tmp_filepath): - old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath, self.reference_dir) + old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath, self.reference_dir, self.reference_override_dir) # Create reference render directory. old_dirpath = os.path.dirname(old_img) |