diff options
author | jon denning <gfxcoder@gmail.com> | 2022-07-29 20:51:49 +0300 |
---|---|---|
committer | jon denning <gfxcoder@gmail.com> | 2022-07-29 20:51:49 +0300 |
commit | 6485941d7a8158381288ce044b657e2c147ff73a (patch) | |
tree | 8fc98916154dfc7d7f57a95732fddb620272d9ac | |
parent | eee25a175ad3c0736878918bacd4995e67195ec0 (diff) | |
parent | 9b9417b66150fd070619006dbd233369709edf1b (diff) |
Merge branch 'master' into retopo_transformretopo_transform
260 files changed, 4505 insertions, 3029 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/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 11e732ec480..5e3f8d839e9 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -12,6 +12,7 @@ #if defined(__EMBREE__) # include "kernel/device/cpu/bvh.h" +# define __BVH2__ #elif defined(__METALRT__) # include "kernel/device/metal/bvh.h" #elif defined(__KERNEL_OPTIX__) @@ -72,6 +73,12 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, return false; } +# ifdef __EMBREE__ + if (kernel_data.device_bvh) { + return kernel_embree_intersect(kg, ray, visibility, isect); + } +# endif + # ifdef __OBJECT_MOTION__ if (kernel_data.bvh.have_motion) { # ifdef __HAIR__ @@ -121,6 +128,12 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg, return false; } +# ifdef __EMBREE__ + if (kernel_data.device_bvh) { + return kernel_embree_intersect_local(kg, ray, local_isect, local_object, lcg_state, max_hits); + } +# endif + # ifdef __OBJECT_MOTION__ if (kernel_data.bvh.have_motion) { return bvh_intersect_local_motion(kg, ray, local_isect, local_object, lcg_state, max_hits); @@ -170,6 +183,13 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, return false; } +# ifdef __EMBREE__ + if (kernel_data.device_bvh) { + return kernel_embree_intersect_shadow_all( + kg, state, ray, visibility, max_hits, num_recorded_hits, throughput); + } +# endif + # ifdef __OBJECT_MOTION__ if (kernel_data.bvh.have_motion) { # ifdef __HAIR__ @@ -254,6 +274,12 @@ ccl_device_intersect uint scene_intersect_volume(KernelGlobals kg, return false; } +# ifdef __EMBREE__ + if (kernel_data.device_bvh) { + return kernel_embree_intersect_volume(kg, ray, isect, max_hits, visibility); + } +# endif + # ifdef __OBJECT_MOTION__ if (kernel_data.bvh.have_motion) { return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits, visibility); diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h index f37af2a1e65..2ffe1496c72 100644 --- a/intern/cycles/kernel/bvh/shadow_all.h +++ b/intern/cycles/kernel/bvh/shadow_all.h @@ -300,11 +300,7 @@ ccl_device_inline kernel_assert(object != OBJECT_NONE); /* Instance pop. */ -#if BVH_FEATURE(BVH_MOTION) - bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir); -#else - bvh_instance_pop(kg, object, ray, &P, &dir, &idir); -#endif + bvh_instance_pop(ray, &P, &dir, &idir); object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr]; diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h index 9069d16912b..f3744aca5c0 100644 --- a/intern/cycles/kernel/bvh/traversal.h +++ b/intern/cycles/kernel/bvh/traversal.h @@ -237,11 +237,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, kernel_assert(object != OBJECT_NONE); /* instance pop */ -#if BVH_FEATURE(BVH_MOTION) - bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir); -#else - bvh_instance_pop(kg, object, ray, &P, &dir, &idir); -#endif + bvh_instance_pop(ray, &P, &dir, &idir); object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr]; diff --git a/intern/cycles/kernel/bvh/volume.h b/intern/cycles/kernel/bvh/volume.h index cc3915b4bf7..664c692dd3d 100644 --- a/intern/cycles/kernel/bvh/volume.h +++ b/intern/cycles/kernel/bvh/volume.h @@ -210,11 +210,7 @@ ccl_device_inline kernel_assert(object != OBJECT_NONE); /* instance pop */ -#if BVH_FEATURE(BVH_MOTION) - bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir); -#else - bvh_instance_pop(kg, object, ray, &P, &dir, &idir); -#endif + bvh_instance_pop(ray, &P, &dir, &idir); object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr]; diff --git a/intern/cycles/kernel/bvh/volume_all.h b/intern/cycles/kernel/bvh/volume_all.h index 5cdea3e354c..721eb555d4d 100644 --- a/intern/cycles/kernel/bvh/volume_all.h +++ b/intern/cycles/kernel/bvh/volume_all.h @@ -242,11 +242,7 @@ ccl_device_inline kernel_assert(object != OBJECT_NONE); /* Instance pop. */ -#if BVH_FEATURE(BVH_MOTION) - bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir); -#else - bvh_instance_pop(kg, object, ray, &P, &dir, &idir); -#endif + bvh_instance_pop(ray, &P, &dir, &idir); object = OBJECT_NONE; node_addr = traversal_stack[stack_ptr]; diff --git a/intern/cycles/kernel/device/cpu/bvh.h b/intern/cycles/kernel/device/cpu/bvh.h index b5ea3d831f4..6c06232a692 100644 --- a/intern/cycles/kernel/device/cpu/bvh.h +++ b/intern/cycles/kernel/device/cpu/bvh.h @@ -166,16 +166,16 @@ ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg, } else { isect->type = kernel_data_fetch(objects, isect->object).primitive_type; - isect->u = 1.0f - hit->v - hit->u; - isect->v = hit->u; + isect->u = hit->u; + isect->v = hit->v; } } ccl_device_inline void kernel_embree_convert_sss_hit( KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int object) { - isect->u = 1.0f - hit->v - hit->u; - isect->v = hit->u; + isect->u = hit->u; + isect->v = hit->v; isect->t = ray->tfar; RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData( rtcGetGeometry(kernel_data.device_bvh, object * 2)); @@ -446,19 +446,11 @@ ccl_device void kernel_embree_filter_occluded_func_backface_cull( /* Scene intersection. */ -ccl_device_intersect bool scene_intersect(KernelGlobals kg, - ccl_private const Ray *ray, - const uint visibility, - ccl_private Intersection *isect) +ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg, + ccl_private const Ray *ray, + const uint visibility, + ccl_private Intersection *isect) { - if (!intersection_ray_valid(ray)) { - return false; - } - - if (!kernel_data.device_bvh) { - return false; - } - isect->t = ray->tmax; CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR); IntersectContext rtc_ctx(&ctx); @@ -476,24 +468,13 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, } #ifdef __BVH_LOCAL__ -ccl_device_intersect bool scene_intersect_local(KernelGlobals kg, - ccl_private const Ray *ray, - ccl_private LocalIntersection *local_isect, - int local_object, - ccl_private uint *lcg_state, - int max_hits) +ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg, + ccl_private const Ray *ray, + ccl_private LocalIntersection *local_isect, + int local_object, + ccl_private uint *lcg_state, + int max_hits) { - if (!intersection_ray_valid(ray)) { - if (local_isect) { - local_isect->num_hits = 0; - } - return false; - } - - if (!kernel_data.device_bvh) { - return false; - } - const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) & SD_OBJECT_TRANSFORM_APPLIED); CCLIntersectContext ctx(kg, @@ -544,24 +525,14 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg, #endif #ifdef __SHADOW_RECORD_ALL__ -ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, - IntegratorShadowStateCPU *state, - ccl_private const Ray *ray, - uint visibility, - uint max_hits, - ccl_private uint *num_recorded_hits, - ccl_private float *throughput) +ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg, + IntegratorShadowStateCPU *state, + ccl_private const Ray *ray, + uint visibility, + uint max_hits, + ccl_private uint *num_recorded_hits, + ccl_private float *throughput) { - if (!intersection_ray_valid(ray)) { - *num_recorded_hits = 0; - *throughput = 1.0f; - return false; - } - - if (!kernel_data.device_bvh) { - return false; - } - CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL); Intersection *isect_array = (Intersection *)state->shadow_isect; ctx.isect_s = isect_array; @@ -579,20 +550,12 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, #endif #ifdef __VOLUME__ -ccl_device_intersect uint scene_intersect_volume(KernelGlobals kg, - ccl_private const Ray *ray, - ccl_private Intersection *isect, - const uint max_hits, - const uint visibility) +ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg, + ccl_private const Ray *ray, + ccl_private Intersection *isect, + const uint max_hits, + const uint visibility) { - if (!intersection_ray_valid(ray)) { - return false; - } - - if (!kernel_data.device_bvh) { - return false; - } - CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL); ctx.isect_s = isect; ctx.max_hits = max_hits; 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/metal/bvh.h b/intern/cycles/kernel/device/metal/bvh.h index f30b21abaf9..03faa3f020f 100644 --- a/intern/cycles/kernel/device/metal/bvh.h +++ b/intern/cycles/kernel/device/metal/bvh.h @@ -129,9 +129,8 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, isect->t = intersection.distance; if (intersection.type == intersection_type::triangle) { - isect->u = 1.0f - intersection.triangle_barycentric_coord.y - - intersection.triangle_barycentric_coord.x; - isect->v = intersection.triangle_barycentric_coord.x; + isect->u = intersection.triangle_barycentric_coord.x; + isect->v = intersection.triangle_barycentric_coord.y; } else { isect->u = payload.u; @@ -346,9 +345,8 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg, isect->t = intersection.distance; if (intersection.type == intersection_type::triangle) { - isect->u = 1.0f - intersection.triangle_barycentric_coord.y - - intersection.triangle_barycentric_coord.x; - isect->v = intersection.triangle_barycentric_coord.x; + isect->u = intersection.triangle_barycentric_coord.x; + isect->v = intersection.triangle_barycentric_coord.y; } else { isect->u = payload.u; diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal index b295e081f3f..3d173b0d601 100644 --- a/intern/cycles/kernel/device/metal/kernel.metal +++ b/intern/cycles/kernel/device/metal/kernel.metal @@ -122,8 +122,8 @@ TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal, isect->object = object; isect->type = kernel_data_fetch(objects, object).primitive_type; - isect->u = 1.0f - barycentrics.y - barycentrics.x; - isect->v = barycentrics.x; + isect->u = barycentrics.x; + isect->v = barycentrics.y; /* Record geometric normal */ const uint tri_vindex = kernel_data_fetch(tri_vindex, isect->prim).w; @@ -185,18 +185,14 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal, return true; } - float u = 0.0f, v = 0.0f; + const float u = barycentrics.x; + const float v = barycentrics.y; int type = 0; if (intersection_type == METALRT_HIT_TRIANGLE) { - u = 1.0f - barycentrics.y - barycentrics.x; - v = barycentrics.x; type = kernel_data_fetch(objects, object).primitive_type; } # ifdef __HAIR__ else { - u = barycentrics.x; - v = barycentrics.y; - const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim); type = segment.type; prim = segment.prim; 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/kernel/device/optix/bvh.h b/intern/cycles/kernel/device/optix/bvh.h index 0fb8156c27d..d1d342f6034 100644 --- a/intern/cycles/kernel/device/optix/bvh.h +++ b/intern/cycles/kernel/device/optix/bvh.h @@ -116,8 +116,8 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit() isect->type = kernel_data_fetch(objects, isect->object).primitive_type; const float2 barycentrics = optixGetTriangleBarycentrics(); - isect->u = 1.0f - barycentrics.y - barycentrics.x; - isect->v = barycentrics.x; + isect->u = barycentrics.x; + isect->v = barycentrics.y; /* Record geometric normal. */ const uint tri_vindex = kernel_data_fetch(tri_vindex, prim).w; @@ -152,8 +152,8 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit() int type = 0; if (optixIsTriangleHit()) { const float2 barycentrics = optixGetTriangleBarycentrics(); - u = 1.0f - barycentrics.y - barycentrics.x; - v = barycentrics.x; + u = barycentrics.x; + v = barycentrics.y; type = kernel_data_fetch(objects, object).primitive_type; } # ifdef __HAIR__ @@ -336,8 +336,8 @@ extern "C" __global__ void __closesthit__kernel_optix_hit() if (optixIsTriangleHit()) { const float2 barycentrics = optixGetTriangleBarycentrics(); - optixSetPayload_1(__float_as_uint(1.0f - barycentrics.y - barycentrics.x)); - optixSetPayload_2(__float_as_uint(barycentrics.x)); + optixSetPayload_1(__float_as_uint(barycentrics.x)); + optixSetPayload_2(__float_as_uint(barycentrics.y)); optixSetPayload_3(prim); optixSetPayload_5(kernel_data_fetch(objects, object).primitive_type); } diff --git a/intern/cycles/kernel/geom/motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h index b59c5c43c20..b30ee7258dc 100644 --- a/intern/cycles/kernel/geom/motion_triangle_intersect.h +++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h @@ -27,8 +27,8 @@ ccl_device_inline float3 motion_triangle_point_from_uv(KernelGlobals kg, const float v, float3 verts[3]) { - float w = 1.0f - u - v; - float3 P = u * verts[0] + v * verts[1] + w * verts[2]; + /* This appears to give slightly better precision than interpolating with w = (1 - u - v). */ + float3 P = verts[0] + u * (verts[1] - verts[0]) + v * (verts[2] - verts[0]); if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { const Transform tfm = object_get_transform(kg, sd); diff --git a/intern/cycles/kernel/geom/object.h b/intern/cycles/kernel/geom/object.h index badfd311985..14ceb636e2e 100644 --- a/intern/cycles/kernel/geom/object.h +++ b/intern/cycles/kernel/geom/object.h @@ -503,20 +503,6 @@ ccl_device_inline void bvh_instance_push(KernelGlobals kg, *idir = bvh_inverse_direction(*dir); } -/* Transform ray to exit static object in BVH. */ - -ccl_device_inline void bvh_instance_pop(KernelGlobals kg, - int object, - ccl_private const Ray *ray, - ccl_private float3 *P, - ccl_private float3 *dir, - ccl_private float3 *idir) -{ - *P = ray->P; - *dir = bvh_clamp_direction(ray->D); - *idir = bvh_inverse_direction(*dir); -} - #ifdef __OBJECT_MOTION__ /* Transform ray into object space to enter motion blurred object in BVH */ @@ -536,22 +522,20 @@ ccl_device_inline void bvh_instance_motion_push(KernelGlobals kg, *idir = bvh_inverse_direction(*dir); } -/* Transform ray to exit motion blurred object in BVH. */ +#endif -ccl_device_inline void bvh_instance_motion_pop(KernelGlobals kg, - int object, - ccl_private const Ray *ray, - ccl_private float3 *P, - ccl_private float3 *dir, - ccl_private float3 *idir) +/* Transform ray to exit static object in BVH. */ + +ccl_device_inline void bvh_instance_pop(ccl_private const Ray *ray, + ccl_private float3 *P, + ccl_private float3 *dir, + ccl_private float3 *idir) { *P = ray->P; *dir = bvh_clamp_direction(ray->D); *idir = bvh_inverse_direction(*dir); } -#endif - /* TODO: This can be removed when we know if no devices will require explicit * address space qualifiers for this case. */ diff --git a/intern/cycles/kernel/geom/subd_triangle.h b/intern/cycles/kernel/geom/subd_triangle.h index 8b73b342e16..c6f883461bd 100644 --- a/intern/cycles/kernel/geom/subd_triangle.h +++ b/intern/cycles/kernel/geom/subd_triangle.h @@ -94,11 +94,11 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg, float2 uv[3]; subd_triangle_patch_uv(kg, sd, uv); - float2 dpdu = uv[0] - uv[2]; - float2 dpdv = uv[1] - uv[2]; + float2 dpdu = uv[1] - uv[0]; + float2 dpdv = uv[2] - uv[0]; /* p is [s, t] */ - float2 p = dpdu * sd->u + dpdv * sd->v + uv[2]; + float2 p = dpdu * sd->u + dpdv * sd->v + uv[0]; float a, dads, dadt; a = patch_eval_float(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt); @@ -165,12 +165,12 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_CORNER) { float2 uv[3]; @@ -195,12 +195,12 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) { if (dx) @@ -233,11 +233,11 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg, float2 uv[3]; subd_triangle_patch_uv(kg, sd, uv); - float2 dpdu = uv[0] - uv[2]; - float2 dpdv = uv[1] - uv[2]; + float2 dpdu = uv[1] - uv[0]; + float2 dpdv = uv[2] - uv[0]; /* p is [s, t] */ - float2 p = dpdu * sd->u + dpdv * sd->v + uv[2]; + float2 p = dpdu * sd->u + dpdv * sd->v + uv[0]; float2 a, dads, dadt; @@ -305,12 +305,12 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_CORNER) { float2 uv[3]; @@ -337,12 +337,12 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) { if (dx) @@ -375,11 +375,11 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg, float2 uv[3]; subd_triangle_patch_uv(kg, sd, uv); - float2 dpdu = uv[0] - uv[2]; - float2 dpdv = uv[1] - uv[2]; + float2 dpdu = uv[1] - uv[0]; + float2 dpdv = uv[2] - uv[0]; /* p is [s, t] */ - float2 p = dpdu * sd->u + dpdv * sd->v + uv[2]; + float2 p = dpdu * sd->u + dpdv * sd->v + uv[0]; float3 a, dads, dadt; a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt); @@ -446,12 +446,12 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_CORNER) { float2 uv[3]; @@ -478,12 +478,12 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) { if (dx) @@ -516,11 +516,11 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg, float2 uv[3]; subd_triangle_patch_uv(kg, sd, uv); - float2 dpdu = uv[0] - uv[2]; - float2 dpdv = uv[1] - uv[2]; + float2 dpdu = uv[1] - uv[0]; + float2 dpdv = uv[2] - uv[0]; /* p is [s, t] */ - float2 p = dpdu * sd->u + dpdv * sd->v + uv[2]; + float2 p = dpdu * sd->u + dpdv * sd->v + uv[0]; float4 a, dads, dadt; if (desc.type == NODE_ATTR_RGBA) { @@ -592,12 +592,12 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) { float2 uv[3]; @@ -636,12 +636,12 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c; + *dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a; if (dy) - *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c; + *dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a; #endif - return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c; + return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) { if (dx) diff --git a/intern/cycles/kernel/geom/triangle.h b/intern/cycles/kernel/geom/triangle.h index 788bfaca7cf..6b9450d59ef 100644 --- a/intern/cycles/kernel/geom/triangle.h +++ b/intern/cycles/kernel/geom/triangle.h @@ -45,8 +45,8 @@ ccl_device_inline void triangle_point_normal(KernelGlobals kg, float3 v1 = kernel_data_fetch(tri_verts, tri_vindex.w + 1); float3 v2 = kernel_data_fetch(tri_verts, tri_vindex.w + 2); /* compute point */ - float t = 1.0f - u - v; - *P = (u * v0 + v * v1 + t * v2); + float w = 1.0f - u - v; + *P = (w * v0 + u * v1 + v * v2); /* get object flags */ int object_flag = kernel_data_fetch(object_flag, object); /* compute normal */ @@ -97,7 +97,7 @@ triangle_smooth_normal(KernelGlobals kg, float3 Ng, int prim, float u, float v) float3 n1 = kernel_data_fetch(tri_vnormal, tri_vindex.y); float3 n2 = kernel_data_fetch(tri_vnormal, tri_vindex.z); - float3 N = safe_normalize((1.0f - u - v) * n2 + u * n0 + v * n1); + float3 N = safe_normalize((1.0f - u - v) * n0 + u * n1 + v * n2); return is_zero(N) ? Ng : N; } @@ -118,7 +118,7 @@ ccl_device_inline float3 triangle_smooth_normal_unnormalized( object_inverse_normal_transform(kg, sd, &n2); } - float3 N = (1.0f - u - v) * n2 + u * n0 + v * n1; + float3 N = (1.0f - u - v) * n0 + u * n1 + v * n2; return is_zero(N) ? Ng : N; } @@ -137,8 +137,8 @@ ccl_device_inline void triangle_dPdudv(KernelGlobals kg, const float3 p2 = kernel_data_fetch(tri_verts, tri_vindex.w + 2); /* compute derivatives of P w.r.t. uv */ - *dPdu = (p0 - p2); - *dPdv = (p1 - p2); + *dPdu = (p1 - p0); + *dPdv = (p2 - p0); } /* Reading attributes on various triangle elements */ @@ -167,12 +167,12 @@ ccl_device float triangle_attribute_float(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2; + *dx = sd->du.dx * f1 + sd->dv.dx * f2 - (sd->du.dx + sd->dv.dx) * f0; if (dy) - *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2; + *dy = sd->du.dy * f1 + sd->dv.dy * f2 - (sd->du.dy + sd->dv.dy) * f0; #endif - return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2; + return sd->u * f1 + sd->v * f2 + (1.0f - sd->u - sd->v) * f0; } else { #ifdef __RAY_DIFFERENTIALS__ @@ -217,12 +217,12 @@ ccl_device float2 triangle_attribute_float2(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2; + *dx = sd->du.dx * f1 + sd->dv.dx * f2 - (sd->du.dx + sd->dv.dx) * f0; if (dy) - *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2; + *dy = sd->du.dy * f1 + sd->dv.dy * f2 - (sd->du.dy + sd->dv.dy) * f0; #endif - return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2; + return sd->u * f1 + sd->v * f2 + (1.0f - sd->u - sd->v) * f0; } else { #ifdef __RAY_DIFFERENTIALS__ @@ -267,12 +267,12 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2; + *dx = sd->du.dx * f1 + sd->dv.dx * f2 - (sd->du.dx + sd->dv.dx) * f0; if (dy) - *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2; + *dy = sd->du.dy * f1 + sd->dv.dy * f2 - (sd->du.dy + sd->dv.dy) * f0; #endif - return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2; + return sd->u * f1 + sd->v * f2 + (1.0f - sd->u - sd->v) * f0; } else { #ifdef __RAY_DIFFERENTIALS__ @@ -328,12 +328,12 @@ ccl_device float4 triangle_attribute_float4(KernelGlobals kg, #ifdef __RAY_DIFFERENTIALS__ if (dx) - *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2; + *dx = sd->du.dx * f1 + sd->dv.dx * f2 - (sd->du.dx + sd->dv.dx) * f0; if (dy) - *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2; + *dy = sd->du.dy * f1 + sd->dv.dy * f2 - (sd->du.dy + sd->dv.dy) * f0; #endif - return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2; + return sd->u * f1 + sd->v * f2 + (1.0f - sd->u - sd->v) * f0; } else { #ifdef __RAY_DIFFERENTIALS__ diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h index f968e537cfa..847ed22fddd 100644 --- a/intern/cycles/kernel/geom/triangle_intersect.h +++ b/intern/cycles/kernel/geom/triangle_intersect.h @@ -145,9 +145,9 @@ ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg, const packed_float3 tri_a = kernel_data_fetch(tri_verts, tri_vindex + 0), tri_b = kernel_data_fetch(tri_verts, tri_vindex + 1), tri_c = kernel_data_fetch(tri_verts, tri_vindex + 2); - float w = 1.0f - u - v; - float3 P = u * tri_a + v * tri_b + w * tri_c; + /* This appears to give slightly better precision than interpolating with w = (1 - u - v). */ + float3 P = tri_a + u * (tri_b - tri_a) + v * (tri_c - tri_a); if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { const Transform tfm = object_get_transform(kg, sd); diff --git a/intern/cycles/kernel/integrator/init_from_bake.h b/intern/cycles/kernel/integrator/init_from_bake.h index bf3f41b52b9..dd26215bcd2 100644 --- a/intern/cycles/kernel/integrator/init_from_bake.h +++ b/intern/cycles/kernel/integrator/init_from_bake.h @@ -155,6 +155,11 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg, 1.0f - u); } + /* Convert from Blender to Cycles/Embree/OptiX barycentric convention. */ + const float tmp = u; + u = v; + v = 1.0f - tmp - v; + /* Position and normal on triangle. */ const int object = kernel_data.bake.object_index; float3 P, Ng; diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h index 7a6f866b1a0..aa72b93c9d2 100644 --- a/intern/cycles/kernel/integrator/mnee.h +++ b/intern/cycles/kernel/integrator/mnee.h @@ -186,7 +186,7 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg, triangle_vertices_and_normals(kg, sd_vtx->prim, verts, normals); /* Compute refined position (same code as in triangle_point_from_uv). */ - sd_vtx->P = isect->u * verts[0] + isect->v * verts[1] + (1.f - isect->u - isect->v) * verts[2]; + sd_vtx->P = (1.f - isect->u - isect->v) * verts[0] + isect->u * verts[1] + isect->v * verts[2]; if (!(sd_vtx->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { const Transform tfm = object_get_transform(kg, sd_vtx); sd_vtx->P = transform_point(&tfm, sd_vtx->P); @@ -213,8 +213,8 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg, } /* Tangent space (position derivatives) WRT barycentric (u, v). */ - float3 dp_du = verts[0] - verts[2]; - float3 dp_dv = verts[1] - verts[2]; + float3 dp_du = verts[1] - verts[0]; + float3 dp_dv = verts[2] - verts[0]; /* Geometric normal. */ vtx->ng = normalize(cross(dp_du, dp_dv)); @@ -223,16 +223,16 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg, /* Shading normals: Interpolate normals between vertices. */ float n_len; - vtx->n = normalize_len(normals[0] * sd_vtx->u + normals[1] * sd_vtx->v + - normals[2] * (1.0f - sd_vtx->u - sd_vtx->v), + vtx->n = normalize_len(normals[0] * (1.0f - sd_vtx->u - sd_vtx->v) + normals[1] * sd_vtx->u + + normals[2] * sd_vtx->v, &n_len); /* Shading normal derivatives WRT barycentric (u, v) * we calculate the derivative of n = |u*n0 + v*n1 + (1-u-v)*n2| using: * d/du [f(u)/|f(u)|] = [d/du f(u)]/|f(u)| - f(u)/|f(u)|^3 <f(u), d/du f(u)>. */ const float inv_n_len = 1.f / n_len; - float3 dn_du = inv_n_len * (normals[0] - normals[2]); - float3 dn_dv = inv_n_len * (normals[1] - normals[2]); + float3 dn_du = inv_n_len * (normals[1] - normals[0]); + float3 dn_dv = inv_n_len * (normals[2] - normals[0]); dn_du -= vtx->n * dot(vtx->n, dn_du); dn_dv -= vtx->n * dot(vtx->n, dn_dv); diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h index 210bb1b35c2..2e309cee43f 100644 --- a/intern/cycles/kernel/light/sample.h +++ b/intern/cycles/kernel/light/sample.h @@ -137,8 +137,9 @@ ccl_device_inline float3 shadow_ray_smooth_surface_offset( triangle_vertices_and_normals(kg, sd->prim, V, N); } - const float u = sd->u, v = sd->v; - const float w = 1 - u - v; + const float u = 1.0f - sd->u - sd->v; + const float v = sd->u; + const float w = sd->v; float3 P = V[0] * u + V[1] * v + V[2] * w; /* Local space */ float3 n = N[0] * u + N[1] * v + N[2] * w; /* We get away without normalization */ diff --git a/intern/cycles/kernel/osl/shaders/node_geometry.osl b/intern/cycles/kernel/osl/shaders/node_geometry.osl index 23d4c2ee66f..cc891abd6e3 100644 --- a/intern/cycles/kernel/osl/shaders/node_geometry.osl +++ b/intern/cycles/kernel/osl/shaders/node_geometry.osl @@ -20,7 +20,7 @@ shader node_geometry(normal NormalIn = N, Normal = NormalIn; TrueNormal = Ng; Incoming = I; - Parametric = point(u, v, 0.0); + Parametric = point(1.0 - u - v, u, 0.0); Backfacing = backfacing(); if (bump_offset == "dx") { diff --git a/intern/cycles/kernel/svm/geometry.h b/intern/cycles/kernel/svm/geometry.h index 4b5368dd765..bbefdcfa755 100644 --- a/intern/cycles/kernel/svm/geometry.h +++ b/intern/cycles/kernel/svm/geometry.h @@ -34,7 +34,7 @@ ccl_device_noinline void svm_node_geometry(KernelGlobals kg, data = sd->Ng; break; case NODE_GEOM_uv: - data = make_float3(sd->u, sd->v, 0.0f); + data = make_float3(1.0f - sd->u - sd->v, sd->u, 0.0f); break; default: data = make_float3(0.0f, 0.0f, 0.0f); @@ -57,7 +57,7 @@ ccl_device_noinline void svm_node_geometry_bump_dx(KernelGlobals kg, data = sd->P + sd->dP.dx; break; case NODE_GEOM_uv: - data = make_float3(sd->u + sd->du.dx, sd->v + sd->dv.dx, 0.0f); + data = make_float3(1.0f - sd->u - sd->du.dx - sd->v - sd->dv.dx, sd->u + sd->du.dx, 0.0f); break; default: svm_node_geometry(kg, sd, stack, type, out_offset); @@ -84,7 +84,7 @@ ccl_device_noinline void svm_node_geometry_bump_dy(KernelGlobals kg, data = sd->P + sd->dP.dy; break; case NODE_GEOM_uv: - data = make_float3(sd->u + sd->du.dy, sd->v + sd->dv.dy, 0.0f); + data = make_float3(1.0f - sd->u - sd->du.dy - sd->v - sd->dv.dy, sd->u + sd->du.dy, 0.0f); break; default: svm_node_geometry(kg, sd, stack, type, out_offset); diff --git a/intern/cycles/scene/mesh_displace.cpp b/intern/cycles/scene/mesh_displace.cpp index e180145daac..cdd5a793530 100644 --- a/intern/cycles/scene/mesh_displace.cpp +++ b/intern/cycles/scene/mesh_displace.cpp @@ -73,16 +73,16 @@ static int fill_shader_input(const Scene *scene, switch (j) { case 0: - u = 1.0f; + u = 0.0f; v = 0.0f; break; case 1: - u = 0.0f; - v = 1.0f; + u = 1.0f; + v = 0.0f; break; default: u = 0.0f; - v = 0.0f; + v = 1.0f; break; } 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/math_intersect.h b/intern/cycles/util/math_intersect.h index 3e5891b2507..37bdc5f1ccf 100644 --- a/intern/cycles/util/math_intersect.h +++ b/intern/cycles/util/math_intersect.h @@ -120,9 +120,9 @@ ccl_device_forceinline bool ray_triangle_intersect(const float3 ray_P, * in Embree. */ /* Calculate vertices relative to ray origin. */ - const float3 v0 = tri_c - ray_P; - const float3 v1 = tri_a - ray_P; - const float3 v2 = tri_b - ray_P; + const float3 v0 = tri_a - ray_P; + const float3 v1 = tri_b - ray_P; + const float3 v2 = tri_c - ray_P; /* Calculate triangle edges. */ const float3 e0 = v2 - v0; @@ -130,11 +130,12 @@ ccl_device_forceinline bool ray_triangle_intersect(const float3 ray_P, const float3 e2 = v1 - v2; /* Perform edge tests. */ - const float U = dot(cross(v2 + v0, e0), ray_D); - const float V = dot(cross(v0 + v1, e1), ray_D); - const float W = dot(cross(v1 + v2, e2), ray_D); + const float U = dot(cross(e0, v2 + v0), ray_D); + const float V = dot(cross(e1, v0 + v1), ray_D); + const float W = dot(cross(e2, v1 + v2), ray_D); - const float eps = FLT_EPSILON * fabsf(U + V + W); + const float UVW = U + V + W; + const float eps = FLT_EPSILON * fabsf(UVW); const float minUVW = min(U, min(V, W)); const float maxUVW = max(U, max(V, W)); @@ -158,8 +159,9 @@ ccl_device_forceinline bool ray_triangle_intersect(const float3 ray_P, return false; } - *isect_u = U / den; - *isect_v = V / den; + const float rcp_UVW = (fabsf(UVW) < 1e-18f) ? 0.0f : 1.0f / UVW; + *isect_u = min(U * rcp_UVW, 1.0f); + *isect_v = min(V * rcp_UVW, 1.0f); *isect_t = t; return true; } 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_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/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 8d21c6fe792..1af3cde1821 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -214,36 +214,33 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr const int domain_num, const AttributeInit &initializer) { + const int old_layer_num = custom_data.totlayer; switch (initializer.type) { case AttributeInit::Type::Default: { - void *data = add_generic_custom_data_layer( + add_generic_custom_data_layer( custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); - return data != nullptr; + break; } case AttributeInit::Type::VArray: { void *data = add_generic_custom_data_layer( custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); - if (data == nullptr) { - return false; + if (data != nullptr) { + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); } - const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray.materialize_to_uninitialized(varray.index_range(), data); - return true; + break; } case AttributeInit::Type::MoveArray: { void *source_data = static_cast<const AttributeInitMove &>(initializer).data; void *data = add_generic_custom_data_layer( custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id); - if (data == nullptr) { + if (source_data != nullptr && data == nullptr) { MEM_freeN(source_data); - return false; } - return true; + break; } } - - BLI_assert_unreachable(); - return false; + return old_layer_num < custom_data.totlayer; } static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, @@ -265,17 +262,25 @@ GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const void *owner) cons return {}; } - const void *data; - if (stored_as_named_attribute_) { - data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()); - } - else { - data = CustomData_get_layer(custom_data, stored_type_); + const void *data = nullptr; + bool found_attribute = false; + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (stored_as_named_attribute_) { + if (layer.name == name_) { + data = layer.data; + found_attribute = true; + break; + } + } + else if (layer.type == stored_type_) { + data = layer.data; + found_attribute = true; + break; + } } - if (data == nullptr) { + if (!found_attribute) { return {}; } - const int element_num = custom_data_access_.get_element_num(owner); return as_read_attribute_(data, element_num); } @@ -291,31 +296,42 @@ GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) } const int element_num = custom_data_access_.get_element_num(owner); - void *data; - if (stored_as_named_attribute_) { - data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()); - } - else { - data = CustomData_get_layer(custom_data, stored_type_); + void *data = nullptr; + bool found_attribute = false; + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (stored_as_named_attribute_) { + if (layer.name == name_) { + data = layer.data; + found_attribute = true; + break; + } + } + else if (layer.type == stored_type_) { + data = layer.data; + found_attribute = true; + break; + } } - if (data == nullptr) { + if (!found_attribute) { return {}; } - void *new_data; - if (stored_as_named_attribute_) { - new_data = CustomData_duplicate_referenced_layer_named( - custom_data, stored_type_, name_.c_str(), element_num); - } - else { - new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num); - } + if (data != nullptr) { + void *new_data; + if (stored_as_named_attribute_) { + new_data = CustomData_duplicate_referenced_layer_named( + custom_data, stored_type_, name_.c_str(), element_num); + } + else { + new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num); + } - if (data != new_data) { - if (custom_data_access_.update_custom_data_pointers) { - custom_data_access_.update_custom_data_pointers(owner); + if (data != new_data) { + if (custom_data_access_.update_custom_data_pointers) { + custom_data_access_.update_custom_data_pointers(owner); + } + data = new_data; } - data = new_data; } std::function<void()> tag_modified_fn; 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/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/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/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_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_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index fef51fa780e..3987c9daf0a 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -177,10 +177,9 @@ void mat3_to_quat_is_ok(float q[4], const float mat[3][3]); /* Other. */ /** - * Utility function that performs `sinf` & `cosf` where the quadrants of the circle - * will have exactly matching values when their sign is flipped. - * This works as long as the denominator can be divided by 2 or 4, - * otherwise `sinf` & `cosf` are used without any additional logic. + * Utility that performs `sinf` & `cosf` intended for plotting a 2D circle, + * where the values of the coordinates with are exactly symmetrical although this + * favors even numbers as odd numbers can only be symmetrical on a single axis. * * Besides adjustments to precision, this function is the equivalent of: * \code {.c} @@ -194,7 +193,7 @@ void mat3_to_quat_is_ok(float q[4], const float mat[3][3]); * \param r_sin: The resulting sine. * \param r_cos: The resulting cosine. */ -void sin_cos_from_fraction(const int numerator, const int denominator, float *r_sin, float *r_cos); +void sin_cos_from_fraction(int numerator, int denominator, float *r_sin, float *r_cos); void print_qt(const char *str, const float q[4]); 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/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index f0bfc7c21e1..03275ce19b4 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -915,53 +915,107 @@ float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[ return len; } -void sin_cos_from_fraction(const int numerator, const int denominator, float *r_sin, float *r_cos) -{ +void sin_cos_from_fraction(int numerator, const int denominator, float *r_sin, float *r_cos) +{ + /* By default, creating an circle from an integer: calling #sinf & #cosf on the fraction doesn't + * create symmetrical values (because of float imprecision). + * Resolve this when the rotation is calculated from a fraction by mapping the `numerator` + * to lower values so X/Y values for points around a circle are exactly symmetrical, see T87779. + * + * - Numbers divisible by 4 are mapped to the lower 8th (8 axis symmetry). + * - Even numbers are mapped to the lower quarter (4 axis symmetry). + * - Odd numbers are mapped to the lower half (1 axis symmetry). + * + * Once the values are calculated, the are mapped back to their position in the circle + * using negation & swapping values. */ + BLI_assert((numerator <= denominator) && (denominator > 0)); + enum { NEGATE_SIN_BIT = 0, NEGATE_COS_BIT = 1, SWAP_SIN_COS_BIT = 2 }; + enum { + NEGATE_SIN = (1 << NEGATE_SIN_BIT), + NEGATE_COS = (1 << NEGATE_COS_BIT), + SWAP_SIN_COS = (1 << SWAP_SIN_COS_BIT), + } xform = 0; if ((denominator & 3) == 0) { + /* The denominator divides by 4, determine the quadrant then further refine the upper 8th. */ const int denominator_4 = denominator / 4; - if (numerator <= denominator_4) { + if (numerator < denominator_4) { /* Fall through. */ } else { - if (numerator <= denominator_4 * 2) { - const float phi = (float)(2.0 * M_PI) * - ((float)(numerator - denominator_4) / (float)denominator); - *r_sin = cosf(phi); - *r_cos = -sinf(phi); + if (numerator < denominator_4 * 2) { + numerator -= denominator_4; + xform = NEGATE_SIN | SWAP_SIN_COS; + } + else if (numerator == denominator_4 * 2) { + numerator = 0; + xform = NEGATE_COS; + } + else if (numerator < denominator_4 * 3) { + numerator -= denominator_4 * 2; + xform = NEGATE_SIN | NEGATE_COS; } - else if (numerator <= denominator_4 * 3) { - const float phi = (float)(2.0 * M_PI) * - ((float)(numerator - (denominator_4 * 2)) / (float)denominator); - *r_sin = -sinf(phi); - *r_cos = -cosf(phi); + else if (numerator == denominator_4 * 3) { + numerator = 0; + xform = NEGATE_COS | SWAP_SIN_COS; } else { - const float phi = (float)(2.0 * M_PI) * - ((float)(numerator - (denominator_4 * 3)) / (float)denominator); - *r_cos = sinf(phi); - *r_sin = -cosf(phi); + numerator -= denominator_4 * 3; + xform = NEGATE_COS | SWAP_SIN_COS; } - return; + } + /* Further increase accuracy by using the range of the upper 8th. */ + const int numerator_test = denominator_4 - numerator; + if (numerator_test < numerator) { + numerator = numerator_test; + xform ^= SWAP_SIN_COS; + /* Swap #NEGATE_SIN, #NEGATE_COS flags. */ + xform = (xform & (uint)(~(NEGATE_SIN | NEGATE_COS))) | + (((xform & NEGATE_SIN) >> NEGATE_SIN_BIT) << NEGATE_COS_BIT) | + (((xform & NEGATE_COS) >> NEGATE_COS_BIT) << NEGATE_SIN_BIT); } } else if ((denominator & 1) == 0) { + /* The denominator divides by 2, determine the quadrant then further refine the upper 4th. */ const int denominator_2 = denominator / 2; - if (numerator <= denominator_2) { + if (numerator < denominator_2) { /* Fall through. */ } + else if (numerator == denominator_2) { + numerator = 0; + xform = NEGATE_COS; + } else { - const float phi = (float)(2.0 * M_PI) * - ((float)(numerator - denominator_2) / (float)denominator); - *r_sin = -sinf(phi); - *r_cos = -cosf(phi); - return; + numerator -= denominator_2; + xform = NEGATE_SIN | NEGATE_COS; + } + /* Further increase accuracy by using the range of the upper 4th. */ + const int numerator_test = denominator_2 - numerator; + if (numerator_test < numerator) { + numerator = numerator_test; + xform ^= NEGATE_COS; + } + } + else { + /* The denominator is an odd number, only refine the upper half. */ + const int numerator_test = denominator - numerator; + if (numerator_test < numerator) { + numerator = numerator_test; + xform ^= NEGATE_SIN; } } const float phi = (float)(2.0 * M_PI) * ((float)numerator / (float)denominator); - *r_sin = sinf(phi); - *r_cos = cosf(phi); + const float sin_phi = sinf(phi) * ((xform & NEGATE_SIN) ? -1.0f : 1.0f); + const float cos_phi = cosf(phi) * ((xform & NEGATE_COS) ? -1.0f : 1.0f); + if ((xform & SWAP_SIN_COS) == 0) { + *r_sin = sin_phi; + *r_cos = cos_phi; + } + else { + *r_sin = cos_phi; + *r_cos = sin_phi; + } } void print_qt(const char *str, const float q[4]) diff --git a/source/blender/blenlib/tests/BLI_math_rotation_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_test.cc index a283118bea2..460cfd2d36c 100644 --- a/source/blender/blenlib/tests/BLI_math_rotation_test.cc +++ b/source/blender/blenlib/tests/BLI_math_rotation_test.cc @@ -7,6 +7,8 @@ #include "BLI_math_rotation.hh" #include "BLI_math_vector.hh" +#include "BLI_vector.hh" + #include <cmath> /* Test that quaternion converts to itself via matrix. */ @@ -150,6 +152,107 @@ TEST(math_rotation, quat_split_swing_and_twist_negative) EXPECT_V4_NEAR(twist, expected_twist, FLT_EPSILON); } +/* -------------------------------------------------------------------- */ +/** \name Test `sin_cos_from_fraction` Accuracy & Exact Symmetry + * \{ */ + +static void test_sin_cos_from_fraction_accuracy(const int range, const float expected_eps) +{ + for (int i = 0; i < range; i++) { + float sin_cos_fl[2]; + sin_cos_from_fraction(i, range, &sin_cos_fl[0], &sin_cos_fl[1]); + const float phi = (float)(2.0 * M_PI) * ((float)i / (float)range); + const float sin_cos_test_fl[2] = {sinf(phi), cosf(phi)}; + EXPECT_V2_NEAR(sin_cos_fl, sin_cos_test_fl, expected_eps); + } +} + +/** Ensure the result of #sin_cos_from_fraction match #sinf & #cosf. */ +TEST(math_rotation, sin_cos_from_fraction_accuracy) +{ + for (int range = 1; range <= 64; range++) { + test_sin_cos_from_fraction_accuracy(range, 1e-6f); + } +} + +/** Ensure values are exactly symmetrical where possible. */ +static void test_sin_cos_from_fraction_symmetry(const int range) +{ + /* The expected number of unique numbers depends on the range being a multiple of 4/2/1. */ + const enum { + MULTIPLE_OF_1 = 1, + MULTIPLE_OF_2 = 2, + MULTIPLE_OF_4 = 3, + } multiple_of = (range & 1) ? MULTIPLE_OF_1 : ((range & 3) ? MULTIPLE_OF_2 : MULTIPLE_OF_4); + + blender::Vector<blender::float2> coords; + coords.reserve(range); + for (int i = 0; i < range; i++) { + float sin_cos_fl[2]; + sin_cos_from_fraction(i, range, &sin_cos_fl[0], &sin_cos_fl[1]); + switch (multiple_of) { + case MULTIPLE_OF_1: { + sin_cos_fl[0] = fabsf(sin_cos_fl[0]); + break; + } + case MULTIPLE_OF_2: { + sin_cos_fl[0] = fabsf(sin_cos_fl[0]); + sin_cos_fl[1] = fabsf(sin_cos_fl[1]); + break; + } + case MULTIPLE_OF_4: { + sin_cos_fl[0] = fabsf(sin_cos_fl[0]); + sin_cos_fl[1] = fabsf(sin_cos_fl[1]); + if (sin_cos_fl[0] > sin_cos_fl[1]) { + SWAP(float, sin_cos_fl[0], sin_cos_fl[1]); + } + break; + } + } + coords.append_unchecked(sin_cos_fl); + } + /* Sort, then count unique items. */ + std::sort(coords.begin(), coords.end(), [](const blender::float2 &a, const blender::float2 &b) { + float delta = b[0] - a[0]; + if (delta == 0.0f) { + delta = b[1] - a[1]; + } + return delta > 0.0f; + }); + int unique_coords_count = 1; + if (range > 1) { + int i_prev = 0; + for (int i = 1; i < range; i_prev = i++) { + if (coords[i_prev] != coords[i]) { + unique_coords_count += 1; + } + } + } + switch (multiple_of) { + case MULTIPLE_OF_1: { + EXPECT_EQ(unique_coords_count, (range / 2) + 1); + break; + } + case MULTIPLE_OF_2: { + EXPECT_EQ(unique_coords_count, (range / 4) + 1); + break; + } + case MULTIPLE_OF_4: { + EXPECT_EQ(unique_coords_count, (range / 8) + 1); + break; + } + } +} + +TEST(math_rotation, sin_cos_from_fraction_symmetry) +{ + for (int range = 1; range <= 64; range++) { + test_sin_cos_from_fraction_symmetry(range); + } +} + +/** \} */ + namespace blender::math::tests { TEST(math_rotation, RotateDirectionAroundAxis) 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/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/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index e91dab3dd6f..26f1a9e626e 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -83,7 +83,7 @@ typedef struct PathContext { /* only to access BMO flags */ BMesh *bm_bmoflag; - BMVert *v_a, *v_b; + BMVert *v_pair[2]; BLI_mempool *link_pool; } PathContext; @@ -593,17 +593,17 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } pc.bm_bmoflag = bm; - pc.v_a = ((BMVert **)op_verts_slot->data.p)[0]; - pc.v_b = ((BMVert **)op_verts_slot->data.p)[1]; + pc.v_pair[0] = ((BMVert **)op_verts_slot->data.p)[0]; + pc.v_pair[1] = ((BMVert **)op_verts_slot->data.p)[1]; /* fail! */ - if (!(pc.v_a && pc.v_b)) { + if (!(pc.v_pair[0] && pc.v_pair[1])) { return; } #ifdef DEBUG_PRINT - printf("%s: v_a: %d\n", __func__, BM_elem_index_get(pc.v_a)); - printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b)); + printf("%s: v_pair[0]: %d\n", __func__, BM_elem_index_get(pc.v_pair[0])); + printf("%s: v_pair[1]: %d\n", __func__, BM_elem_index_get(pc.v_pair[1])); #endif /* tag so we won't touch ever (typically hidden faces) */ @@ -618,15 +618,15 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) /* calculate matrix */ { - bm_vert_pair_to_matrix(&pc.v_a, pc.matrix); - pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_a->co); + bm_vert_pair_to_matrix(pc.v_pair, pc.matrix); + pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_pair[0]->co); } /* add first vertex */ { PathLinkState *state; state = MEM_callocN(sizeof(*state), __func__); - state_link_add(&pc, state, (BMElem *)pc.v_a, NULL); + state_link_add(&pc, state, (BMElem *)pc.v_pair[0], NULL); BLI_heapsimple_insert(pc.states, state->dist, state); } @@ -642,7 +642,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) /* either we insert this into 'pc.states' or its freed */ bool continue_search; - if (state->link_last->ele == (BMElem *)pc.v_b) { + if (state->link_last->ele == (BMElem *)pc.v_pair[1]) { /* pass, wait until all are found */ #ifdef DEBUG_PRINT printf("%s: state %p loop found %.4f\n", __func__, state, state->dist); @@ -698,8 +698,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } while ((link = link->next)); } - BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT); - BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_pair[0], VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_pair[1], VERT_OUT); BLI_mempool_destroy(pc.link_pool); 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/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/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a8d25b75036..afef516b245 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -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/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.c index 0e69b4bb358..d7d1d3ce260 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -35,6 +35,7 @@ #include "UI_interface.h" #include "RNA_access.h" +#include "RNA_path.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index ddd805f6010..4a5919864c7 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -40,6 +40,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_path.h" #include "RNA_prototypes.h" #include "RNA_types.h" diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc index 09902dd6c35..8572e938b30 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" diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 88fe866f717..f460a159a5f 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -39,6 +39,7 @@ #include "WM_types.h" #include "RNA_access.h" +#include "RNA_path.h" #include "UI_interface.h" 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_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/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_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/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc index 6c693376ad3..f6539284f74 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc @@ -126,12 +126,20 @@ struct AddOperationExecutor { Object &surface_ob_orig = *curves_id_orig_->surface; Mesh &surface_orig = *static_cast<Mesh *>(surface_ob_orig.data); + if (surface_orig.totpoly == 0) { + report_empty_original_surface(stroke_extension.reports); + return; + } surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, &surface_ob_orig); if (surface_ob_eval_ == nullptr) { return; } surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_); + if (surface_eval_->totpoly == 0) { + report_empty_evaluated_surface(stroke_extension.reports); + return; + } curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt; brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc index a180a232189..95261f29914 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc @@ -391,6 +391,16 @@ CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C) this->rv3d = CTX_wm_region_view3d(&C); } +void report_empty_original_surface(ReportList *reports) +{ + BKE_report(reports, RPT_WARNING, TIP_("Original surface mesh is empty")); +} + +void report_empty_evaluated_surface(ReportList *reports) +{ + BKE_report(reports, RPT_WARNING, TIP_("Evaluated surface mesh is empty")); +} + void report_missing_surface(ReportList *reports) { BKE_report(reports, RPT_WARNING, TIP_("Missing surface mesh")); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc index e1ac941eb2b..2e03e907e34 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc @@ -115,12 +115,20 @@ struct DensityAddOperationExecutor { surface_ob_orig_ = curves_id_orig_->surface; surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data); + if (surface_orig_->totpoly == 0) { + report_empty_original_surface(stroke_extension.reports); + return; + } surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_); if (surface_ob_eval_ == nullptr) { return; } surface_eval_ = BKE_object_get_evaluated_mesh(surface_ob_eval_); + if (surface_eval_->totpoly == 0) { + report_empty_evaluated_surface(stroke_extension.reports); + return; + } BKE_bvhtree_from_mesh_get(&surface_bvh_eval_, surface_eval_, BVHTREE_FROM_LOOPTRI, 2); BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval_); }); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh index 7d40ed80a65..5c8c0cedc6f 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh @@ -128,6 +128,8 @@ float transform_brush_radius(const float4x4 &transform, const float3 &brush_position, const float old_radius); +void report_empty_original_surface(ReportList *reports); +void report_empty_evaluated_surface(ReportList *reports); void report_missing_surface(ReportList *reports); void report_missing_uv_map_on_original_surface(ReportList *reports); void report_missing_uv_map_on_evaluated_surface(ReportList *reports); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc index 5bfc8ccc667..a955a074df2 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc @@ -67,10 +67,11 @@ static IndexMask retrieve_selected_curves(const CurvesGeometry &curves, return selection.get_internal_single() <= 0.0f ? IndexMask(0) : IndexMask(curves.curves_num()); } + const Span<float> point_selection_span = selection.get_internal_span(); return index_mask_ops::find_indices_based_on_predicate( curves.curves_range(), 512, r_indices, [&](const int curve_i) { for (const int i : curves.points_for_curve(curve_i)) { - if (selection[i] > 0.0f) { + if (point_selection_span[i] > 0.0f) { return true; } } diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc index 443fbcb883c..ebdff8a6c4b 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc @@ -166,6 +166,10 @@ struct SlideOperationExecutor { surface_ob_orig_ = curves_id_orig_->surface; surface_orig_ = static_cast<Mesh *>(surface_ob_orig_->data); + if (surface_orig_->totpoly == 0) { + report_empty_original_surface(stroke_extension.reports); + return; + } surface_looptris_orig_ = {BKE_mesh_runtime_looptri_ensure(surface_orig_), BKE_mesh_runtime_looptri_len(surface_orig_)}; surface_uv_map_orig_ = @@ -189,6 +193,10 @@ struct SlideOperationExecutor { if (surface_eval_ == nullptr) { return; } + if (surface_eval_->totpoly == 0) { + report_empty_evaluated_surface(stroke_extension.reports); + return; + } surface_looptris_eval_ = {BKE_mesh_runtime_looptri_ensure(surface_eval_), BKE_mesh_runtime_looptri_len(surface_eval_)}; surface_uv_map_eval_ = 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_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/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/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index c59269f5a7d..183c543d7e3 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -664,4 +664,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/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/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/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 083a505539a..023d7a32a61 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -185,6 +185,7 @@ static void node_geo_exec(GeoNodeExecParams params) join_component_type<InstancesComponent>(geometry_sets, geometry_set_result); join_component_type<VolumeComponent>(geometry_sets, geometry_set_result); join_component_type<CurveComponent>(geometry_sets, geometry_set_result); + join_component_type<GeometryComponentEditData>(geometry_sets, geometry_set_result); params.set_output("Geometry", std::move(geometry_set_result)); } 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/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_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/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/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index 984a8ef41d0..8b11eebf145 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -705,7 +705,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey) case CTX_MODE_VERTEX_GPENCIL: return "builtin_brush.Draw"; case CTX_MODE_SCULPT_CURVES: - return "builtin_brush.Comb"; + return "builtin_brush.density"; /* end temporary hack. */ case CTX_MODE_PARTICLE: 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/creator.c b/source/creator/creator.c index 6c95ee3e490..e7a803d383f 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -41,7 +41,6 @@ #include "BKE_global.h" #include "BKE_gpencil_modifier.h" #include "BKE_idtype.h" -#include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_modifier.h" 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: + *; +}; |