Compare commits
1 Commits
info-edito
...
temp-pose-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
60d1d13046 |
@@ -113,7 +113,7 @@ include(cmake/expat.cmake)
|
||||
include(cmake/yamlcpp.cmake)
|
||||
include(cmake/opencolorio.cmake)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
|
||||
include(cmake/sse2neon.cmake)
|
||||
endif()
|
||||
|
||||
|
@@ -18,12 +18,6 @@
|
||||
|
||||
set(BOOST_ADDRESS_MODEL 64)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
set(BOOST_ARCHITECTURE arm)
|
||||
else()
|
||||
set(BOOST_ARCHITECTURE x86)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(BOOST_TOOLSET toolset=msvc-14.1)
|
||||
set(BOOST_COMPILER_STRING -vc141)
|
||||
@@ -35,6 +29,7 @@ if(WIN32)
|
||||
if(BUILD_MODE STREQUAL Release)
|
||||
set(BOOST_HARVEST_CMD ${BOOST_HARVEST_CMD} && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/include/boost-${BOOST_VERSION_NODOTS_SHORT}/ ${HARVEST_TARGET}/boost/include/)
|
||||
endif()
|
||||
|
||||
elseif(APPLE)
|
||||
set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
|
||||
set(BOOST_BUILD_COMMAND ./b2)
|
||||
@@ -98,7 +93,7 @@ ExternalProject_Add(external_boost
|
||||
UPDATE_COMMAND ""
|
||||
PATCH_COMMAND ${BOOST_PATCH_COMMAND}
|
||||
CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND}
|
||||
BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=${BOOST_ARCHITECTURE} address-model=${BOOST_ADDRESS_MODEL} link=static threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install
|
||||
BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=x86 address-model=${BOOST_ADDRESS_MODEL} link=static threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "${BOOST_HARVEST_CMD}"
|
||||
)
|
||||
|
@@ -47,7 +47,7 @@ else()
|
||||
set(EMBREE_BUILD_DIR)
|
||||
endif()
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
|
||||
ExternalProject_Add(external_embree
|
||||
GIT_REPOSITORY ${EMBREE_ARM_GIT}
|
||||
GIT_TAG "blender-arm"
|
||||
|
@@ -25,12 +25,19 @@ else()
|
||||
set(GMP_OPTIONS --enable-static --disable-shared )
|
||||
endif()
|
||||
|
||||
if(APPLE AND NOT BLENDER_PLATFORM_ARM)
|
||||
set(GMP_OPTIONS
|
||||
${GMP_OPTIONS}
|
||||
--with-pic
|
||||
)
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
if(APPLE)
|
||||
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
|
||||
set(GMP_OPTIONS
|
||||
${GMP_OPTIONS}
|
||||
--disable-assembly
|
||||
)
|
||||
else()
|
||||
set(GMP_OPTIONS
|
||||
${GMP_OPTIONS}
|
||||
--with-pic
|
||||
)
|
||||
endif()
|
||||
elseif(UNIX)
|
||||
set(GMP_OPTIONS
|
||||
${GMP_OPTIONS}
|
||||
--with-pic
|
||||
@@ -38,13 +45,6 @@ elseif(UNIX AND NOT APPLE)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
set(GMP_OPTIONS
|
||||
${GMP_OPTIONS}
|
||||
--disable-assembly
|
||||
)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_gmp
|
||||
URL file://${PACKAGE_DIR}/${GMP_FILE}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
|
@@ -109,9 +109,9 @@ harvest(llvm/lib llvm/lib "libclang*.a")
|
||||
if(APPLE)
|
||||
harvest(openmp/lib openmp/lib "*")
|
||||
harvest(openmp/include openmp/include "*.h")
|
||||
endif()
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
harvest(sse2neon sse2neon "*.h")
|
||||
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
|
||||
harvest(sse2neon sse2neon "*.h")
|
||||
endif()
|
||||
endif()
|
||||
harvest(ogg/lib ffmpeg/lib "*.a")
|
||||
harvest(openal/include openal/include "*.h")
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
|
||||
set(LLVM_TARGETS AArch64$<SEMICOLON>ARM)
|
||||
else()
|
||||
set(LLVM_TARGETS X86)
|
||||
|
@@ -36,7 +36,7 @@ set(OPENCOLORIO_EXTRA_ARGS
|
||||
-Dyaml-cpp_ROOT=${LIBDIR}/yamlcpp
|
||||
)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
if(APPLE AND NOT("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64"))
|
||||
set(OPENCOLORIO_EXTRA_ARGS
|
||||
${OPENCOLORIO_EXTRA_ARGS}
|
||||
-DOCIO_USE_SSE=OFF
|
||||
|
@@ -137,10 +137,6 @@ else()
|
||||
endif()
|
||||
set(OSX_SYSROOT ${XCODE_DEV_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk)
|
||||
|
||||
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
|
||||
set(BLENDER_PLATFORM_ARM ON)
|
||||
endif()
|
||||
|
||||
set(PLATFORM_CFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
|
||||
set(PLATFORM_CXXFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -std=c++11 -stdlib=libc++ -arch ${CMAKE_OSX_ARCHITECTURES}")
|
||||
set(PLATFORM_LDFLAGS "-isysroot ${OSX_SYSROOT} -mmacosx-version-min=${OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}")
|
||||
@@ -155,10 +151,6 @@ else()
|
||||
-DCMAKE_OSX_SYSROOT:PATH=${OSX_SYSROOT}
|
||||
)
|
||||
else()
|
||||
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64")
|
||||
set(BLENDER_PLATFORM_ARM ON)
|
||||
endif()
|
||||
|
||||
set(PLATFORM_CFLAGS "-fPIC")
|
||||
set(PLATFORM_CXXFLAGS "-std=c++11 -fPIC")
|
||||
set(PLATFORM_LDFLAGS)
|
||||
|
@@ -22,8 +22,8 @@ set(PNG_EXTRA_ARGS
|
||||
-DPNG_STATIC=ON
|
||||
)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=ON -DCMAKE_SYSTEM_PROCESSOR="aarch64")
|
||||
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
|
||||
set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=on -DCMAKE_SYSTEM_PROCESSOR="aarch64")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_png
|
||||
|
@@ -16,13 +16,15 @@
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
ExternalProject_Add(external_sse2neon
|
||||
GIT_REPOSITORY ${SSE2NEON_GIT}
|
||||
GIT_TAG ${SSE2NEON_GIT_HASH}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
PREFIX ${BUILD_DIR}/sse2neon
|
||||
CONFIGURE_COMMAND echo sse2neon - Nothing to configure
|
||||
BUILD_COMMAND echo sse2neon - nothing to build
|
||||
INSTALL_COMMAND mkdir -p ${LIBDIR}/sse2neon && cp ${BUILD_DIR}/sse2neon/src/external_sse2neon/sse2neon.h ${LIBDIR}/sse2neon
|
||||
INSTALL_DIR ${LIBDIR}/sse2neon
|
||||
)
|
||||
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
|
||||
ExternalProject_Add(external_sse2neon
|
||||
GIT_REPOSITORY ${SSE2NEON_GIT}
|
||||
GIT_TAG ${SSE2NEON_GIT_HASH}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
PREFIX ${BUILD_DIR}/sse2neon
|
||||
CONFIGURE_COMMAND echo sse2neon - Nothing to configure
|
||||
BUILD_COMMAND echo sse2neon - nothing to build
|
||||
INSTALL_COMMAND mkdir -p ${LIBDIR}/sse2neon && cp ${BUILD_DIR}/sse2neon/src/external_sse2neon/sse2neon.h ${LIBDIR}/sse2neon
|
||||
INSTALL_DIR ${LIBDIR}/sse2neon
|
||||
)
|
||||
endif()
|
||||
|
@@ -22,9 +22,7 @@ set(SSL_PATCH_CMD echo .)
|
||||
if(APPLE)
|
||||
set(SSL_OS_COMPILER "blender-darwin-${CMAKE_OSX_ARCHITECTURES}")
|
||||
else()
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
set(SSL_OS_COMPILER "blender-linux-aarch64")
|
||||
elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(SSL_EXTRA_ARGS enable-ec_nistp_64_gcc_128)
|
||||
set(SSL_OS_COMPILER "blender-linux-x86_64")
|
||||
else()
|
||||
|
@@ -8,11 +8,6 @@ my %targets = (
|
||||
inherit_from => [ "linux-x86_64" ],
|
||||
cflags => add("-fPIC"),
|
||||
},
|
||||
"blender-linux-aarch64" => {
|
||||
inherit_from => [ "linux-aarch64" ],
|
||||
cxxflags => add("-fPIC"),
|
||||
cflags => add("-fPIC"),
|
||||
},
|
||||
"blender-darwin-x86_64" => {
|
||||
inherit_from => [ "darwin64-x86_64-cc" ],
|
||||
cflags => add("-fPIC"),
|
||||
|
@@ -21,7 +21,6 @@ if(WIN32)
|
||||
-DTBB_BUILD_TBBMALLOC=On
|
||||
-DTBB_BUILD_TBBMALLOC_PROXY=On
|
||||
-DTBB_BUILD_STATIC=Off
|
||||
-DTBB_BUILD_TESTS=Off
|
||||
)
|
||||
set(TBB_LIBRARY tbb)
|
||||
set(TBB_STATIC_LIBRARY Off)
|
||||
@@ -31,7 +30,6 @@ else()
|
||||
-DTBB_BUILD_TBBMALLOC=On
|
||||
-DTBB_BUILD_TBBMALLOC_PROXY=Off
|
||||
-DTBB_BUILD_STATIC=On
|
||||
-DTBB_BUILD_TESTS=Off
|
||||
)
|
||||
set(TBB_LIBRARY tbb_static)
|
||||
set(TBB_STATIC_LIBRARY On)
|
||||
@@ -44,7 +42,7 @@ ExternalProject_Add(external_tbb
|
||||
URL_HASH ${TBB_HASH_TYPE}=${TBB_HASH}
|
||||
PREFIX ${BUILD_DIR}/tbb
|
||||
PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_tbb.txt ${BUILD_DIR}/tbb/src/external_tbb/CMakeLists.txt &&
|
||||
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/tbb/src/external_tbb/build/vs2013/version_string.ver ${BUILD_DIR}/tbb/src/external_tbb/build/version_string.ver.in &&
|
||||
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/tbb/src/external_tbb/build/vs2013/version_string.ver ${BUILD_DIR}/tbb/src/external_tbb/src/tbb/version_string.ver &&
|
||||
${PATCH_CMD} -p 1 -d ${BUILD_DIR}/tbb/src/external_tbb < ${PATCH_DIR}/tbb.diff
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/tbb ${DEFAULT_CMAKE_FLAGS} ${TBB_EXTRA_ARGS}
|
||||
INSTALL_DIR ${LIBDIR}/tbb
|
||||
|
@@ -152,7 +152,7 @@ set(OPENCOLORIO_HASH 1a2e3478b6cd9a1549f24e1b2205e3f0)
|
||||
set(OPENCOLORIO_HASH_TYPE MD5)
|
||||
set(OPENCOLORIO_FILE OpenColorIO-${OPENCOLORIO_VERSION}.tar.gz)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
|
||||
# Newer version required by ISPC with arm support.
|
||||
set(LLVM_VERSION 11.0.1)
|
||||
set(LLVM_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz)
|
||||
@@ -398,20 +398,11 @@ set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df)
|
||||
set(LZMA_HASH_TYPE SHA256)
|
||||
set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
# Need at least 1.1.1i for aarch64 support (https://github.com/openssl/openssl/pull/13218)
|
||||
set(SSL_VERSION 1.1.1i)
|
||||
set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
|
||||
set(SSL_HASH e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242)
|
||||
set(SSL_HASH_TYPE SHA256)
|
||||
set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
|
||||
else()
|
||||
set(SSL_VERSION 1.1.1g)
|
||||
set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
|
||||
set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46)
|
||||
set(SSL_HASH_TYPE SHA256)
|
||||
set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
|
||||
endif()
|
||||
set(SSL_VERSION 1.1.1g)
|
||||
set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz)
|
||||
set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46)
|
||||
set(SSL_HASH_TYPE SHA256)
|
||||
set(SSL_FILE openssl-${SSL_VERSION}.tar.gz)
|
||||
|
||||
set(SQLITE_VERSION 3.31.1)
|
||||
set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip)
|
||||
@@ -462,7 +453,7 @@ set(XR_OPENXR_SDK_HASH 0df6b2fd6045423451a77ff6bc3e1a75)
|
||||
set(XR_OPENXR_SDK_HASH_TYPE MD5)
|
||||
set(XR_OPENXR_SDK_FILE OpenXR-SDK-${XR_OPENXR_SDK_VERSION}.tar.gz)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))
|
||||
# Unreleased version with macOS arm support.
|
||||
set(ISPC_URI https://github.com/ispc/ispc/archive/f5949c055eb9eeb93696978a3da4bfb3a6a30b35.zip)
|
||||
set(ISPC_HASH d382fea18d01dbd0cd05d9e1ede36d7d)
|
||||
|
@@ -20,16 +20,24 @@ if(WIN32)
|
||||
set(X264_EXTRA_ARGS --enable-win32thread --cross-prefix=${MINGW_HOST}- --host=${MINGW_HOST})
|
||||
endif()
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
set(X264_EXTRA_ARGS ${X264_EXTRA_ARGS} "--disable-asm")
|
||||
|
||||
if(APPLE)
|
||||
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
|
||||
set(X264_EXTRA_ARGS ${X264_EXTRA_ARGS} "--disable-asm")
|
||||
set(X264_CONFIGURE_ENV echo .)
|
||||
else()
|
||||
set(X264_CONFIGURE_ENV
|
||||
export AS=${LIBDIR}/nasm/bin/nasm
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
set(X264_CONFIGURE_ENV echo .)
|
||||
endif()
|
||||
|
||||
if((APPLE AND NOT BLENDER_PLATFORM_ARM) OR (UNIX AND NOT APPLE))
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(X264_CONFIGURE_ENV
|
||||
export AS=${LIBDIR}/nasm/bin/nasm
|
||||
)
|
||||
else()
|
||||
set(X264_CONFIGURE_ENV echo .)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_x264
|
||||
|
@@ -1797,10 +1797,6 @@ compile_OCIO() {
|
||||
cmake_d="$cmake_d -D OCIO_BUILD_PYTHON=OFF"
|
||||
cmake_d="$cmake_d -D OCIO_BUILD_GPU_TESTS=OFF"
|
||||
|
||||
if [ $(uname -m) == "aarch64" ]; then
|
||||
cmake_d="$cmake_d -D OCIO_USE_SSE=OFF"
|
||||
fi
|
||||
|
||||
if file /bin/cp | grep -q '32-bit'; then
|
||||
cflags="-fPIC -m32 -march=i686"
|
||||
else
|
||||
@@ -2063,10 +2059,7 @@ compile_OIIO() {
|
||||
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
|
||||
cmake_d="$cmake_d -D STOP_ON_WARNING=OFF"
|
||||
cmake_d="$cmake_d -D LINKSTATIC=OFF"
|
||||
|
||||
if [ $(uname -m) != "aarch64" ]; then
|
||||
cmake_d="$cmake_d -D USE_SIMD=sse2"
|
||||
fi
|
||||
cmake_d="$cmake_d -D USE_SIMD=sse2"
|
||||
|
||||
cmake_d="$cmake_d -D OPENEXR_VERSION=$OPENEXR_VERSION"
|
||||
|
||||
@@ -2086,7 +2079,7 @@ compile_OIIO() {
|
||||
cmake_d="$cmake_d -D USE_OPENCV=OFF"
|
||||
cmake_d="$cmake_d -D BUILD_TESTING=OFF"
|
||||
cmake_d="$cmake_d -D OIIO_BUILD_TESTS=OFF"
|
||||
cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=OFF"
|
||||
cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=ON"
|
||||
cmake_d="$cmake_d -D TXT2MAN="
|
||||
#cmake_d="$cmake_d -D CMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
#cmake_d="$cmake_d -D CMAKE_VERBOSE_MAKEFILE=ON"
|
||||
@@ -2216,15 +2209,10 @@ compile_LLVM() {
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
LLVM_TARGETS="X86"
|
||||
if [ $(uname -m) == "aarch64" ]; then
|
||||
LLVM_TARGETS="AArch64"
|
||||
fi
|
||||
|
||||
cmake_d="-D CMAKE_BUILD_TYPE=Release"
|
||||
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
|
||||
cmake_d="$cmake_d -D LLVM_ENABLE_FFI=ON"
|
||||
cmake_d="$cmake_d -D LLVM_TARGETS_TO_BUILD=$LLVM_TARGETS"
|
||||
cmake_d="$cmake_d -D LLVM_TARGETS_TO_BUILD=X86"
|
||||
cmake_d="$cmake_d -D LLVM_ENABLE_TERMINFO=OFF"
|
||||
|
||||
if [ -d $_FFI_INCLUDE_DIR ]; then
|
||||
@@ -2341,16 +2329,13 @@ compile_OSL() {
|
||||
cmake_d="$cmake_d -D STOP_ON_WARNING=OFF"
|
||||
cmake_d="$cmake_d -D OSL_BUILD_PLUGINS=OFF"
|
||||
cmake_d="$cmake_d -D OSL_BUILD_TESTS=OFF"
|
||||
cmake_d="$cmake_d -D USE_SIMD=sse2"
|
||||
cmake_d="$cmake_d -D USE_LLVM_BITCODE=OFF"
|
||||
cmake_d="$cmake_d -D USE_PARTIO=OFF"
|
||||
cmake_d="$cmake_d -D OSL_BUILD_MATERIALX=OFF"
|
||||
cmake_d="$cmake_d -D USE_QT=OFF"
|
||||
cmake_d="$cmake_d -D USE_PYTHON=OFF"
|
||||
|
||||
if [ $(uname -m) != "aarch64" ]; then
|
||||
cmake_d="$cmake_d -D USE_SIMD=sse2"
|
||||
fi
|
||||
|
||||
cmake_d="$cmake_d -D CMAKE_CXX_STANDARD=14"
|
||||
|
||||
#~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
|
||||
|
@@ -1,32 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
|
||||
|
||||
if (POLICY CMP0048)
|
||||
# cmake warns if loaded from a min-3.0-required parent dir, so silence the warning:
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
endif()
|
||||
|
||||
project (tbb CXX)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckCXXSourceRuns)
|
||||
|
||||
if(POLICY CMP0058)
|
||||
cmake_policy(SET CMP0058 NEW)
|
||||
endif()
|
||||
|
||||
if(POLICY CMP0068)
|
||||
cmake_policy(SET CMP0068 NEW)
|
||||
endif()
|
||||
|
||||
if (POLICY CMP0078)
|
||||
# swig standard target names
|
||||
cmake_policy(SET CMP0078 NEW)
|
||||
endif ()
|
||||
|
||||
if (POLICY CMP0086)
|
||||
# UseSWIG honors SWIG_MODULE_NAME via -module flag
|
||||
cmake_policy(SET CMP0086 NEW)
|
||||
endif ()
|
||||
cmake_minimum_required (VERSION 2.8)
|
||||
project(tbb CXX)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to 'Release' as none was specified.")
|
||||
@@ -35,36 +8,12 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
"MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
if(NOT TBB_INSTALL_RUNTIME_DIR)
|
||||
set(TBB_INSTALL_RUNTIME_DIR bin)
|
||||
endif()
|
||||
if(NOT TBB_INSTALL_LIBRARY_DIR)
|
||||
set(TBB_INSTALL_LIBRARY_DIR lib)
|
||||
endif()
|
||||
if(NOT TBB_INSTALL_ARCHIVE_DIR)
|
||||
set(TBB_INSTALL_ARCHIVE_DIR lib)
|
||||
endif()
|
||||
if(NOT TBB_INSTALL_INCLUDE_DIR)
|
||||
set(TBB_INSTALL_INCLUDE_DIR include)
|
||||
endif()
|
||||
if(NOT TBB_CMAKE_PACKAGE_INSTALL_DIR)
|
||||
set(TBB_CMAKE_PACKAGE_INSTALL_DIR lib/cmake/tbb)
|
||||
endif()
|
||||
|
||||
include_directories(include src src/rml/include ${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(include src src/rml/include )
|
||||
|
||||
option(TBB_BUILD_SHARED "Build TBB shared library" ON)
|
||||
option(TBB_BUILD_STATIC "Build TBB static library" ON)
|
||||
option(TBB_BUILD_TBBMALLOC "Build TBB malloc library" ON)
|
||||
option(TBB_BUILD_TBBMALLOC_PROXY "Build TBB malloc proxy library" ON)
|
||||
option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" ON)
|
||||
option(TBB_NO_DATE "Do not save the configure date in the version string" OFF)
|
||||
option(TBB_BUILD_PYTHON "Build TBB Python bindings" OFF)
|
||||
option(TBB_SET_SOVERSION "Set the SOVERSION (shared library build version suffix)?" OFF)
|
||||
|
||||
# When this repository is part of a larger build system of a parent project
|
||||
# we may not want TBB to set up default installation targets
|
||||
option(TBB_INSTALL_TARGETS "Include build targets for 'make install'" ON)
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_MACOSX_RPATH ON)
|
||||
@@ -90,143 +39,66 @@ set(tbbmalloc_proxy_src
|
||||
src/tbbmalloc/proxy.cpp
|
||||
src/tbbmalloc/tbb_function_replacement.cpp)
|
||||
|
||||
add_library (tbb_interface INTERFACE)
|
||||
add_definitions(-DTBB_SUPPRESS_DEPRECATED_MESSAGES=1)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(i386|x86_64)")
|
||||
if (NOT APPLE AND NOT MINGW)
|
||||
target_compile_definitions(tbb_interface INTERFACE DO_ITT_NOTIFY)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
if (NOT APPLE)
|
||||
add_definitions(-DDO_ITT_NOTIFY)
|
||||
else()
|
||||
# Disable annoying "has no symbols" warnings
|
||||
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
|
||||
endif()
|
||||
|
||||
macro(CHECK_CXX_COMPILER_AND_LINKER_FLAGS _RESULT _CXX_FLAGS _LINKER_FLAGS)
|
||||
set(CMAKE_REQUIRED_FLAGS ${_CXX_FLAGS})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${_LINKER_FLAGS})
|
||||
set(CMAKE_REQUIRED_QUIET TRUE)
|
||||
check_cxx_source_runs("#include <iostream>\nint main(int argc, char **argv) { std::cout << \"test\"; return 0; }" ${_RESULT})
|
||||
set(CMAKE_REQUIRED_FLAGS "")
|
||||
set(CMAKE_REQUIRED_LIBRARIES "")
|
||||
endmacro()
|
||||
|
||||
# Prefer libc++ in conjunction with Clang
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if (CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+")
|
||||
message(STATUS "TBB: using libc++.")
|
||||
else()
|
||||
CHECK_CXX_COMPILER_AND_LINKER_FLAGS(HAS_LIBCPP "-stdlib=libc++" "-stdlib=libc++")
|
||||
if (HAS_LIBCPP)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -D_LIBCPP_VERSION")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++")
|
||||
message(STATUS "TBB: using libc++.")
|
||||
else()
|
||||
message(STATUS "TBB: NOT using libc++.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
|
||||
if (UNIX)
|
||||
target_compile_definitions(tbb_interface INTERFACE USE_PTHREAD)
|
||||
|
||||
check_cxx_compiler_flag ("-mrtm -Werror" SUPPORTS_MRTM)
|
||||
if (SUPPORTS_MRTM)
|
||||
target_compile_options(tbb_interface INTERFACE "-mrtm")
|
||||
endif ()
|
||||
|
||||
elseif(WIN32)
|
||||
target_compile_definitions(tbb_interface INTERFACE USE_WINTHREAD _WIN32_WINNT=0x0600)
|
||||
if (MSVC)
|
||||
enable_language(ASM_MASM)
|
||||
target_compile_options(tbb_interface INTERFACE /GS- /Zc:wchar_t /Zc:forScope)
|
||||
check_cxx_compiler_flag ("/volatile:iso" SUPPORTS_VOLATILE_FLAG)
|
||||
if (SUPPORTS_VOLATILE_FLAG)
|
||||
target_compile_options(tbb_interface INTERFACE /volatile:iso)
|
||||
endif ()
|
||||
target_compile_options(tbb_interface INTERFACE $<$<COMPILE_LANGUAGE:CXX>:/wd4267 /wd4800 /wd4146 /wd4244 /wd4577 /wd4018>)
|
||||
if (NOT CMAKE_SIZEOF_VOID_P)
|
||||
message(FATAL_ERROR "'CMAKE_SIZEOF_VOID_P' is undefined. Please delete your build directory and rerun CMake again!")
|
||||
endif()
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND tbb_src src/tbb/intel64-masm/atomic_support.asm
|
||||
src/tbb/intel64-masm/itsx.asm src/tbb/intel64-masm/intel64_misc.asm)
|
||||
list(APPEND tbbmalloc_src src/tbb/intel64-masm/atomic_support.asm)
|
||||
set(CMAKE_ASM_MASM_FLAGS "/DEM64T=1 ${CMAKE_ASM_MASM_FLAGS}")
|
||||
else()
|
||||
list(APPEND tbb_src src/tbb/ia32-masm/atomic_support.asm
|
||||
src/tbb/ia32-masm/itsx.asm src/tbb/ia32-masm/lock_byte.asm)
|
||||
# Enable SAFESEH feature for assembly (x86 builds only).
|
||||
set(CMAKE_ASM_MASM_FLAGS "/safeseh ${CMAKE_ASM_MASM_FLAGS}")
|
||||
endif()
|
||||
elseif (MINGW)
|
||||
target_compile_options(tbb_interface INTERFACE "-mthreads")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(ENABLE_RTTI "/EHsc /GR ")
|
||||
set(DISABLE_RTTI "/EHs- /GR- ")
|
||||
elseif (UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -DUSE_PTHREAD")
|
||||
if(NOT CMAKE_CXX_FLAGS MATCHES "-mno-rtm")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mrtm")
|
||||
endif()
|
||||
if (APPLE)
|
||||
set(ARCH_PREFIX "mac")
|
||||
else()
|
||||
set(ARCH_PREFIX "lin")
|
||||
endif()
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(ARCH_PREFIX "${ARCH_PREFIX}64")
|
||||
else()
|
||||
set(ARCH_PREFIX "${ARCH_PREFIX}32")
|
||||
endif()
|
||||
set(ENABLE_RTTI "-frtti -fexceptions ")
|
||||
set(DISABLE_RTTI "-fno-rtti -fno-exceptions ")
|
||||
endif ()
|
||||
elseif(WIN32)
|
||||
cmake_minimum_required (VERSION 3.1)
|
||||
enable_language(ASM_MASM)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS- /Zc:wchar_t /Zc:forScope /DUSE_WINTHREAD")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_CRT_SECURE_NO_DEPRECATE /D_WIN32_WINNT=0x0600 /volatile:iso")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4800 /wd4146 /wd4244 /wd4018")
|
||||
|
||||
##--------
|
||||
# - Added TBB_USE_GLIBCXX_VERSION macro to specify the version of GNU
|
||||
# libstdc++ when it cannot be properly recognized, e.g. when used
|
||||
# with Clang on Linux* OS. Inspired by a contribution from David A.
|
||||
if (NOT TBB_USE_GLIBCXX_VERSION AND UNIX AND NOT APPLE)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
string(REPLACE "." "0" TBB_USE_GLIBCXX_VERSION ${CMAKE_CXX_COMPILER_VERSION})
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND tbb_src src/tbb/intel64-masm/atomic_support.asm
|
||||
src/tbb/intel64-masm/itsx.asm src/tbb/intel64-masm/intel64_misc.asm)
|
||||
list(APPEND tbbmalloc_src src/tbb/intel64-masm/atomic_support.asm)
|
||||
set(CMAKE_ASM_MASM_FLAGS "/DEM64T=1")
|
||||
set(ARCH_PREFIX "win64")
|
||||
else()
|
||||
list(APPEND tbb_src src/tbb/ia32-masm/atomic_support.asm
|
||||
src/tbb/ia32-masm/itsx.asm src/tbb/ia32-masm/lock_byte.asm)
|
||||
list(APPEND tbbmalloc_src src/tbb/ia32-masm/atomic_support.asm)
|
||||
set(ARCH_PREFIX "win32")
|
||||
endif()
|
||||
set(ENABLE_RTTI "/EHsc /GR ")
|
||||
set(DISABLE_RTTI "/EHs- /GR- ")
|
||||
endif()
|
||||
|
||||
if (TBB_USE_GLIBCXX_VERSION)
|
||||
target_compile_definitions(tbb_interface INTERFACE TBB_USE_GLIBCXX_VERSION=${TBB_USE_GLIBCXX_VERSION})
|
||||
endif()
|
||||
|
||||
##-------
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
check_cxx_compiler_flag ("-flifetime-dse=1" SUPPORTS_FLIFETIME)
|
||||
if (SUPPORTS_FLIFETIME)
|
||||
target_compile_options(tbb_interface INTERFACE -flifetime-dse=1)
|
||||
endif()
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag("-flifetime-dse=1" SUPPORTS_FLIFETIME)
|
||||
if (SUPPORTS_FLIFETIME)
|
||||
add_definitions(-flifetime-dse=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Linker export definitions
|
||||
if (APPLE)
|
||||
set (ARCH_PREFIX "mac")
|
||||
elseif(WIN32)
|
||||
set (ARCH_PREFIX "win")
|
||||
else()
|
||||
set (ARCH_PREFIX "lin")
|
||||
endif()
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(ARCH_PREFIX "${ARCH_PREFIX}64")
|
||||
else()
|
||||
set(ARCH_PREFIX "${ARCH_PREFIX}32")
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
set (ARCH_PREFIX "${ARCH_PREFIX}-gcc")
|
||||
# there's no win32-gcc-tbb-export.def, use lin32-tbb-export.def
|
||||
execute_process (COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/lin32-tbb-export.def ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/win32-gcc-tbb-export.def)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (WIN32)
|
||||
add_custom_command(OUTPUT tbb.def
|
||||
COMMAND ${CMAKE_CXX_COMPILER} /TC /EP ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include > tbb.def
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def
|
||||
@@ -238,15 +110,18 @@ if (MSVC)
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def
|
||||
COMMENT "Preprocessing tbbmalloc.def"
|
||||
)
|
||||
list(APPEND tbb_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/tbb_resource.rc)
|
||||
list(APPEND tbbmalloc_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc)
|
||||
list(APPEND tbbmalloc_proxy_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/tbbmalloc.rc)
|
||||
else()
|
||||
add_custom_command(OUTPUT tbb.def
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -xc++ -std=c++11 -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def
|
||||
COMMENT "Preprocessing tbb.def"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT tbbmalloc.def
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -xc++ -std=c++11 -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbbmalloc.def
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -xc++ -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbbmalloc.def
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def
|
||||
COMMENT "Preprocessing tbbmalloc.def"
|
||||
)
|
||||
@@ -257,80 +132,34 @@ add_custom_target(tbb_def_files DEPENDS tbb.def tbbmalloc.def)
|
||||
# TBB library
|
||||
if (TBB_BUILD_STATIC)
|
||||
add_library(tbb_static STATIC ${tbb_src})
|
||||
target_link_libraries(tbb_static PRIVATE tbb_interface)
|
||||
target_include_directories(tbb_static INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" "$<INSTALL_INTERFACE:${TBB_INSTALL_INCLUDE_DIR}>")
|
||||
set_property(TARGET tbb_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_BUILD=1")
|
||||
set_property(TARGET tbb_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1")
|
||||
set_property(TARGET tbb_static APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI})
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(TARGETS tbb_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(tbb_static
|
||||
PRIVATE
|
||||
-D__TBB_BUILD=1
|
||||
-D__TBB_DYNAMIC_LOAD_ENABLED=0
|
||||
-D__TBB_SOURCE_DIRECTLY_INCLUDED=1)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_definitions(tbb_static
|
||||
PUBLIC -D__TBB_NO_IMPLICIT_LINKAGE=1
|
||||
PRIVATE -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(tbb_static PUBLIC pthread dl)
|
||||
endif()
|
||||
install(TARGETS tbb_static ARCHIVE DESTINATION lib)
|
||||
endif()
|
||||
|
||||
if (TBB_BUILD_SHARED)
|
||||
add_library(tbb SHARED ${tbb_src})
|
||||
target_link_libraries(tbb PRIVATE tbb_interface)
|
||||
target_include_directories(tbb INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" "$<INSTALL_INTERFACE:${TBB_INSTALL_INCLUDE_DIR}>")
|
||||
set_property(TARGET tbb APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_BUILD=1")
|
||||
set_property(TARGET tbb APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI})
|
||||
if (TBB_SET_SOVERSION)
|
||||
set_property(TARGET tbb PROPERTY SOVERSION 2)
|
||||
endif ()
|
||||
|
||||
target_compile_definitions(tbb
|
||||
PRIVATE -D__TBB_BUILD=1)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_definitions(tbb
|
||||
PUBLIC -D__TBB_NO_IMPLICIT_LINKAGE=1
|
||||
PRIVATE -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
add_dependencies(tbb tbb_def_files)
|
||||
|
||||
if (APPLE)
|
||||
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"")
|
||||
elseif (MSVC)
|
||||
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"")
|
||||
else ()
|
||||
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"")
|
||||
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
|
||||
elseif(UNIX)
|
||||
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
|
||||
elseif(WIN32)
|
||||
set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbb.def")
|
||||
|
||||
endif()
|
||||
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(TARGETS tbb EXPORT TBB
|
||||
LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR}
|
||||
ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}
|
||||
RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR})
|
||||
if (MSVC)
|
||||
install(FILES $<TARGET_PDB_FILE:tbb> DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(tbb PUBLIC pthread dl)
|
||||
install(TARGETS tbb DESTINATION lib)
|
||||
if(WIN32)
|
||||
set_target_properties(tbb PROPERTIES OUTPUT_NAME "tbb$<$<CONFIG:Debug>:_debug>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
# Quench a warning on GCC
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/governor.cpp COMPILE_FLAGS "-Wno-missing-field-initializers ")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# Quench a warning on Clang
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/itt_notify.cpp COMPILE_FLAGS "-Wno-varargs ")
|
||||
elseif(MSVC)
|
||||
# Quench a warning on MSVC
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/scheduler.cpp COMPILE_FLAGS "/wd4458 ")
|
||||
@@ -340,50 +169,24 @@ if(TBB_BUILD_TBBMALLOC)
|
||||
# TBB malloc library
|
||||
if (TBB_BUILD_STATIC)
|
||||
add_library(tbbmalloc_static STATIC ${tbbmalloc_static_src})
|
||||
target_link_libraries(tbbmalloc_static PRIVATE tbb_interface)
|
||||
set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
|
||||
set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_DYNAMIC_LOAD_ENABLED=0")
|
||||
set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1")
|
||||
set_property(TARGET tbbmalloc_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
|
||||
if (MSVC)
|
||||
target_compile_definitions(tbbmalloc_static PUBLIC __TBB_NO_IMPLICIT_LINKAGE=1 __TBBMALLOC_NO_IMPLICIT_LINKAGE=1)
|
||||
endif()
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(TARGETS tbbmalloc_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR})
|
||||
endif()
|
||||
install(TARGETS tbbmalloc_static ARCHIVE DESTINATION lib)
|
||||
endif()
|
||||
|
||||
if (TBB_BUILD_SHARED)
|
||||
add_library(tbbmalloc SHARED ${tbbmalloc_src})
|
||||
target_link_libraries(tbbmalloc PRIVATE tbb_interface)
|
||||
set_property(TARGET tbbmalloc APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
|
||||
set_property(TARGET tbbmalloc APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
|
||||
if (TBB_SET_SOVERSION)
|
||||
set_property(TARGET tbbmalloc PROPERTY SOVERSION 2)
|
||||
endif ()
|
||||
add_dependencies(tbbmalloc tbb_def_files)
|
||||
if (APPLE)
|
||||
set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"")
|
||||
elseif (MSVC)
|
||||
set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"")
|
||||
else ()
|
||||
set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"")
|
||||
endif()
|
||||
if (MSVC)
|
||||
target_compile_definitions(tbbmalloc PUBLIC __TBB_NO_IMPLICIT_LINKAGE=1 __TBBMALLOC_NO_IMPLICIT_LINKAGE=1)
|
||||
endif()
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(TARGETS tbbmalloc EXPORT TBB
|
||||
LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR}
|
||||
ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}
|
||||
RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR})
|
||||
if (MSVC)
|
||||
install(FILES $<TARGET_PDB_FILE:tbbmalloc> DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL)
|
||||
endif()
|
||||
endif()
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(tbbmalloc PUBLIC pthread dl)
|
||||
set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def")
|
||||
elseif(UNIX)
|
||||
set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def")
|
||||
elseif(WIN32)
|
||||
set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "/DEF:${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def")
|
||||
endif()
|
||||
install(TARGETS tbbmalloc DESTINATION lib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -391,298 +194,19 @@ if(TBB_BUILD_TBBMALLOC_PROXY)
|
||||
# TBB malloc proxy library
|
||||
if (TBB_BUILD_STATIC)
|
||||
add_library(tbbmalloc_proxy_static STATIC ${tbbmalloc_proxy_src})
|
||||
target_link_libraries(tbbmalloc_proxy_static PRIVATE tbb_interface)
|
||||
set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
|
||||
set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_DYNAMIC_LOAD_ENABLED=0")
|
||||
set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1")
|
||||
set_property(TARGET tbbmalloc_proxy_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(TARGETS tbbmalloc_proxy_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR})
|
||||
endif()
|
||||
link_libraries(tbbmalloc_proxy_static tbbmalloc)
|
||||
install(TARGETS tbbmalloc_proxy_static ARCHIVE DESTINATION lib)
|
||||
endif()
|
||||
|
||||
if (TBB_BUILD_SHARED)
|
||||
add_library(tbbmalloc_proxy SHARED ${tbbmalloc_proxy_src})
|
||||
target_link_libraries(tbbmalloc_proxy PRIVATE tbb_interface)
|
||||
set_property(TARGET tbbmalloc_proxy APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1")
|
||||
set_property(TARGET tbbmalloc_proxy APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI})
|
||||
if (TBB_SET_SOVERSION)
|
||||
set_property(TARGET tbbmalloc_proxy PROPERTY SOVERSION 2)
|
||||
endif ()
|
||||
target_link_libraries(tbbmalloc_proxy PUBLIC tbbmalloc)
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(TARGETS tbbmalloc_proxy EXPORT TBB
|
||||
LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR}
|
||||
ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}
|
||||
RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR})
|
||||
if (MSVC)
|
||||
install(FILES $<TARGET_PDB_FILE:tbbmalloc_proxy> DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL)
|
||||
endif()
|
||||
endif()
|
||||
if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(tbbmalloc_proxy PUBLIC pthread dl)
|
||||
endif()
|
||||
target_link_libraries(tbbmalloc_proxy tbbmalloc)
|
||||
install(TARGETS tbbmalloc_proxy DESTINATION lib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(DIRECTORY include/tbb DESTINATION ${TBB_INSTALL_INCLUDE_DIR})
|
||||
if (TBB_BUILD_SHARED)
|
||||
install(EXPORT TBB DESTINATION ${TBB_CMAKE_PACKAGE_INSTALL_DIR} NAMESPACE TBB:: FILE TBBConfig.cmake)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# version file
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
set (_VERSION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/include/tbb/tbb_stddef.h)
|
||||
file (STRINGS ${_VERSION_FILE} _VERSION_MAJOR_STRING REGEX ".*define[ ]+TBB_VERSION_MAJOR[ ]+[0-9]+.*")
|
||||
file (STRINGS ${_VERSION_FILE} _VERSION_MINOR_STRING REGEX ".*define[ ]+TBB_VERSION_MINOR[ ]+[0-9]+.*")
|
||||
string (REGEX REPLACE ".*TBB_VERSION_MAJOR[ ]+([0-9]+)" "\\1" TBB_MAJOR_VERSION ${_VERSION_MAJOR_STRING})
|
||||
string (REGEX REPLACE ".*TBB_VERSION_MINOR[ ]+([0-9]+)" "\\1" TBB_MINOR_VERSION ${_VERSION_MINOR_STRING})
|
||||
set (TBB_VERSION_STRING "${TBB_MAJOR_VERSION}.${TBB_MINOR_VERSION}")
|
||||
include (CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file (TBBConfigVersion.cmake VERSION "${TBB_VERSION_STRING}" COMPATIBILITY AnyNewerVersion)
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/TBBConfigVersion.cmake DESTINATION "${TBB_CMAKE_PACKAGE_INSTALL_DIR}")
|
||||
endif()
|
||||
|
||||
# version_string.ver
|
||||
if (UNIX AND NOT TBB_NO_DATE)
|
||||
execute_process (COMMAND date "+%a, %d %b %Y %H:%M:%S %z"
|
||||
OUTPUT_VARIABLE _configure_date
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
elseif (WIN32 AND NOT TBB_NO_DATE)
|
||||
execute_process (COMMAND cmd " /C date /T"
|
||||
OUTPUT_VARIABLE _configure_date
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
else ()
|
||||
set (_configure_date "Unknown")
|
||||
endif()
|
||||
set (TBB_CONFIG_DATE "${_configure_date}" CACHE STRING "First time that TBB was configured")
|
||||
set (_configure_date "${TBB_CONFIG_DATE}")
|
||||
include_directories (${CMAKE_BINARY_DIR})
|
||||
configure_file (build/version_string.ver.in version_string.ver @ONLY)
|
||||
|
||||
if (TBB_BUILD_TESTS)
|
||||
enable_language (C)
|
||||
enable_testing ()
|
||||
|
||||
find_library (LIBRT_LIBRARIES rt)
|
||||
find_library (LIDL_LIBRARIES dl)
|
||||
find_package (Threads)
|
||||
if (NOT APPLE)
|
||||
find_package (OpenMP)
|
||||
endif()
|
||||
|
||||
macro (tbb_add_test testname)
|
||||
set (full_testname tbb_test_${testname})
|
||||
add_executable (${full_testname} src/test/test_${testname}.cpp)
|
||||
target_link_libraries(${full_testname} PRIVATE tbb_interface)
|
||||
if (TBB_BUILD_SHARED)
|
||||
target_link_libraries (${full_testname} PRIVATE tbb tbbmalloc)
|
||||
target_compile_definitions (${full_testname} PRIVATE __TBB_LIB_NAME=tbb)
|
||||
else ()
|
||||
target_link_libraries (${full_testname} PRIVATE tbb_static tbbmalloc_static)
|
||||
target_compile_definitions (${full_testname} PRIVATE __TBB_LIB_NAME=tbb_static)
|
||||
endif ()
|
||||
if (LIBRT_LIBRARIES)
|
||||
target_link_libraries (${full_testname} PRIVATE ${LIBRT_LIBRARIES})
|
||||
endif ()
|
||||
if (LIDL_LIBRARIES)
|
||||
target_link_libraries (${full_testname} PRIVATE ${LIDL_LIBRARIES})
|
||||
endif ()
|
||||
if (Threads_FOUND)
|
||||
target_link_libraries (${full_testname} PRIVATE ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif ()
|
||||
if (OPENMP_FOUND AND "${testname}" MATCHES "openmp")
|
||||
set_target_properties (${full_testname} PROPERTIES COMPILE_FLAGS "${OpenMP_CXX_FLAGS}")
|
||||
set_target_properties (${full_testname} PROPERTIES LINK_FLAGS "${OpenMP_CXX_FLAGS}")
|
||||
endif()
|
||||
if (MINGW)
|
||||
target_link_libraries (${full_testname} PRIVATE psapi)
|
||||
endif ()
|
||||
add_test (NAME ${full_testname} COMMAND ${full_testname})
|
||||
endmacro ()
|
||||
|
||||
tbb_add_test (aggregator)
|
||||
tbb_add_test (aligned_space)
|
||||
tbb_add_test (assembly)
|
||||
if (NOT WIN32)
|
||||
tbb_add_test (async_msg) # msvc64/debug timeouts
|
||||
endif()
|
||||
tbb_add_test (async_node)
|
||||
# tbb_add_test (atomic) # msvc64/debug timeouts: Compile-time initialization fails for static tbb::atomic variables
|
||||
tbb_add_test (blocked_range2d)
|
||||
tbb_add_test (blocked_range3d)
|
||||
tbb_add_test (blocked_range)
|
||||
tbb_add_test (broadcast_node)
|
||||
tbb_add_test (buffer_node)
|
||||
tbb_add_test (cache_aligned_allocator)
|
||||
if (NOT WIN32)
|
||||
tbb_add_test (cache_aligned_allocator_STL)
|
||||
endif()
|
||||
tbb_add_test (cilk_dynamic_load)
|
||||
tbb_add_test (cilk_interop)
|
||||
tbb_add_test (combinable)
|
||||
tbb_add_test (composite_node)
|
||||
tbb_add_test (concurrent_hash_map)
|
||||
tbb_add_test (concurrent_lru_cache)
|
||||
# tbb_add_test (concurrent_monitor) # too long
|
||||
# tbb_add_test (concurrent_priority_queue)
|
||||
if (NOT WIN32)
|
||||
tbb_add_test (concurrent_queue) # msvc64/debug timeouts
|
||||
endif()
|
||||
# tbb_add_test (concurrent_queue_whitebox)
|
||||
tbb_add_test (concurrent_unordered_map)
|
||||
# tbb_add_test (concurrent_unordered_set)
|
||||
tbb_add_test (concurrent_vector)
|
||||
tbb_add_test (continue_node)
|
||||
tbb_add_test (critical_section)
|
||||
tbb_add_test (dynamic_link)
|
||||
# tbb_add_test (eh_algorithms)
|
||||
tbb_add_test (eh_flow_graph)
|
||||
# tbb_add_test (eh_tasks)
|
||||
tbb_add_test (enumerable_thread_specific)
|
||||
tbb_add_test (examples_common_utility)
|
||||
# tbb_add_test (fast_random)
|
||||
tbb_add_test (flow_graph)
|
||||
tbb_add_test (flow_graph_whitebox)
|
||||
# tbb_add_test (fp) # mingw: harness_fp.h:66, assertion !checkConsistency || (ctl.mxcsr & SSE_RND_MODE_MASK) >> 3 == (ctl.x87cw & FE_RND_MODE_MASK): failed
|
||||
# tbb_add_test (function_node) # mingw:random timeout
|
||||
# tbb_add_test (global_control)
|
||||
# tbb_add_test (global_control_whitebox)
|
||||
tbb_add_test (halt)
|
||||
tbb_add_test (handle_perror)
|
||||
# tbb_add_test (hw_concurrency)
|
||||
tbb_add_test (indexer_node)
|
||||
tbb_add_test (inits_loop)
|
||||
tbb_add_test (intrusive_list)
|
||||
tbb_add_test (ittnotify)
|
||||
# tbb_add_test (join_node) #msvc/64: fatal error C1128: number of sections exceeded object file format limit: compile with /bigob
|
||||
tbb_add_test (lambda)
|
||||
tbb_add_test (limiter_node)
|
||||
# tbb_add_test (malloc_atexit)
|
||||
# tbb_add_test (malloc_compliance) #mingw: Limits should be decreased for the test to work
|
||||
tbb_add_test (malloc_init_shutdown)
|
||||
# tbb_add_test (malloc_lib_unload)
|
||||
# tbb_add_test (malloc_overload)
|
||||
tbb_add_test (malloc_pools)
|
||||
tbb_add_test (malloc_regression)
|
||||
# tbb_add_test (malloc_used_by_lib)
|
||||
# tbb_add_test (malloc_whitebox)
|
||||
tbb_add_test (model_plugin)
|
||||
# tbb_add_test (multifunction_node) # too long
|
||||
tbb_add_test (mutex)
|
||||
tbb_add_test (mutex_native_threads)
|
||||
# tbb_add_test (opencl_node)
|
||||
if (OPENMP_FOUND)
|
||||
tbb_add_test (openmp)
|
||||
endif ()
|
||||
tbb_add_test (overwrite_node)
|
||||
# tbb_add_test (parallel_do)
|
||||
# This seems to fail on CI platforms (AppVeyor/Travis), perhaps because the VM exposes just 1 core?
|
||||
tbb_add_test (parallel_for)
|
||||
tbb_add_test (parallel_for_each)
|
||||
tbb_add_test (parallel_for_vectorization)
|
||||
tbb_add_test (parallel_invoke)
|
||||
tbb_add_test (parallel_pipeline)
|
||||
tbb_add_test (parallel_reduce)
|
||||
tbb_add_test (parallel_scan)
|
||||
tbb_add_test (parallel_sort)
|
||||
tbb_add_test (parallel_while)
|
||||
# tbb_add_test (partitioner_whitebox) # too long
|
||||
tbb_add_test (pipeline)
|
||||
# tbb_add_test (pipeline_with_tbf) # takes forever on appveyor
|
||||
tbb_add_test (priority_queue_node)
|
||||
tbb_add_test (queue_node)
|
||||
tbb_add_test (reader_writer_lock)
|
||||
# tbb_add_test (runtime_loader) # LINK : fatal error LNK1104: cannot open file 'tbbproxy.lib' [C:\projects\tbb\test_runtime_loader.vcxproj]
|
||||
tbb_add_test (rwm_upgrade_downgrade)
|
||||
# tbb_add_test (ScalableAllocator)
|
||||
if (NOT WIN32)
|
||||
tbb_add_test (ScalableAllocator_STL)
|
||||
endif()
|
||||
tbb_add_test (semaphore)
|
||||
# tbb_add_test (sequencer_node) # msvc: timeout
|
||||
tbb_add_test (source_node)
|
||||
tbb_add_test (split_node)
|
||||
tbb_add_test (static_assert)
|
||||
tbb_add_test (std_thread)
|
||||
tbb_add_test (tagged_msg)
|
||||
# tbb_add_test (task_arena) # LINK : fatal error LNK1104: cannot open file '__TBB_LIB_NAME.lib' [C:\projects\tbb\test_task_arena.vcxproj]
|
||||
# tbb_add_test (task_assertions)
|
||||
tbb_add_test (task_auto_init)
|
||||
tbb_add_test (task)
|
||||
# tbb_add_test (task_enqueue) # too long
|
||||
tbb_add_test (task_group)
|
||||
# tbb_add_test (task_leaks)
|
||||
# tbb_add_test (task_priority)
|
||||
# tbb_add_test (task_scheduler_init) # msvc: test_task_scheduler_init.cpp:68, assertion !test_mandatory_parallelism || Harness::CanReachConcurrencyLevel(threads): failed
|
||||
tbb_add_test (task_scheduler_observer)
|
||||
tbb_add_test (task_steal_limit)
|
||||
tbb_add_test (tbb_condition_variable)
|
||||
tbb_add_test (tbb_fork)
|
||||
# tbb_add_test (tbb_header)
|
||||
tbb_add_test (tbb_thread)
|
||||
# tbb_add_test (tbb_version)
|
||||
tbb_add_test (tick_count)
|
||||
tbb_add_test (tuple)
|
||||
tbb_add_test (write_once_node)
|
||||
tbb_add_test (yield)
|
||||
endif ()
|
||||
|
||||
if (TBB_BUILD_PYTHON)
|
||||
find_package(PythonInterp)
|
||||
find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT)
|
||||
find_package(SWIG 3)
|
||||
if (PythonLibs_FOUND AND SWIG_FOUND AND TBB_BUILD_SHARED)
|
||||
include (${SWIG_USE_FILE})
|
||||
set_source_files_properties (python/tbb/api.i PROPERTIES CPLUSPLUS ON)
|
||||
set (CMAKE_SWIG_FLAGS "-threads")
|
||||
|
||||
# swig_add_module is deprecated
|
||||
if (CMAKE_VERSION VERSION_LESS 3.8)
|
||||
swig_add_module (api python python/tbb/api.i)
|
||||
else ()
|
||||
swig_add_library (api LANGUAGE python SOURCES python/tbb/api.i)
|
||||
endif ()
|
||||
|
||||
# UseSWIG generates now standard target names
|
||||
if (CMAKE_VERSION VERSION_LESS 3.13)
|
||||
set (module_target ${SWIG_MODULE_api_REAL_NAME})
|
||||
else ()
|
||||
set (module_target api)
|
||||
endif ()
|
||||
|
||||
target_include_directories(${module_target} PRIVATE ${PYTHON_INCLUDE_DIRS})
|
||||
target_link_libraries(${module_target} PRIVATE tbb)
|
||||
if(WIN32)
|
||||
target_link_libraries(${module_target} ${PYTHON_LIBRARIES})
|
||||
elseif(APPLE)
|
||||
set_target_properties(${module_target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set (PYTHON_SITE_PACKAGES Lib/site-packages)
|
||||
else ()
|
||||
set (PYTHON_SITE_PACKAGES lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages)
|
||||
endif ()
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(FILES python/TBB.py
|
||||
DESTINATION ${PYTHON_SITE_PACKAGES})
|
||||
install(FILES python/tbb/__init__.py python/tbb/pool.py python/tbb/test.py python/tbb/__main__.py ${CMAKE_CURRENT_BINARY_DIR}/api.py
|
||||
DESTINATION ${PYTHON_SITE_PACKAGES}/tbb)
|
||||
install(TARGETS ${module_target}
|
||||
DESTINATION ${PYTHON_SITE_PACKAGES}/tbb)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_library(irml SHARED python/rml/ipc_server.cpp python/rml/ipc_utils.cpp src/tbb/cache_aligned_allocator.cpp src/tbb/dynamic_link.cpp src/tbb/tbb_misc_ex.cpp src/tbb/tbb_misc.cpp)
|
||||
target_compile_definitions(irml PRIVATE DO_ITT_NOTIFY=0 USE_PTHREAD=1)
|
||||
target_link_libraries(irml PRIVATE tbb)
|
||||
set_target_properties(irml PROPERTIES VERSION 1)
|
||||
if (TBB_INSTALL_TARGETS)
|
||||
install(TARGETS irml DESTINATION ${TBB_INSTALL_LIBRARY_DIR})
|
||||
endif()
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
install(DIRECTORY include/tbb DESTINATION include)
|
||||
|
@@ -63,19 +63,3 @@ diff -Naur org/CMakeLists.txt external_osl/CMakeLists.txt
|
||||
|
||||
set (OSL_NO_DEFAULT_TEXTURESYSTEM OFF CACHE BOOL "Do not use create a raw OIIO::TextureSystem")
|
||||
if (OSL_NO_DEFAULT_TEXTURESYSTEM)
|
||||
diff --git a/src/liboslexec/llvm_util.cpp b/src/liboslexec/llvm_util.cpp
|
||||
index 445f6400..3d468de2 100644
|
||||
--- a/src/liboslexec/llvm_util.cpp
|
||||
+++ b/src/liboslexec/llvm_util.cpp
|
||||
@@ -3430,8 +3430,9 @@ LLVM_Util::call_function (llvm::Value *func, cspan<llvm::Value *> args)
|
||||
#endif
|
||||
//llvm_gen_debug_printf (std::string("start ") + std::string(name));
|
||||
#if OSL_LLVM_VERSION >= 110
|
||||
- OSL_DASSERT(llvm::isa<llvm::Function>(func));
|
||||
- llvm::Value *r = builder().CreateCall(llvm::cast<llvm::Function>(func), llvm::ArrayRef<llvm::Value *>(args.data(), args.size()));
|
||||
+ llvm::Value* r = builder().CreateCall(
|
||||
+ llvm::cast<llvm::FunctionType>(func->getType()->getPointerElementType()), func,
|
||||
+ llvm::ArrayRef<llvm::Value*>(args.data(), args.size()));
|
||||
#else
|
||||
llvm::Value *r = builder().CreateCall (func, llvm::ArrayRef<llvm::Value *>(args.data(), args.size()));
|
||||
#endif
|
||||
|
@@ -10,15 +10,4 @@ index 7a8d06a0..886699d8 100644
|
||||
+ #if (__cplusplus >= 201402L && (!defined(_MSC_VER) || _MSC_VER >= 1920))
|
||||
#define __TBB_DEPRECATED [[deprecated]]
|
||||
#define __TBB_DEPRECATED_MSG(msg) [[deprecated(msg)]]
|
||||
#elif _MSC_VER
|
||||
--- a/src/tbb/tools_api/ittnotify_config.h
|
||||
+++ b/src/tbb/tools_api/ittnotify_config.h
|
||||
@@ -162,7 +162,7 @@
|
||||
# define ITT_ARCH ITT_ARCH_IA32E
|
||||
# elif defined _M_IA64 || defined __ia64__
|
||||
# define ITT_ARCH ITT_ARCH_IA64
|
||||
-# elif defined _M_ARM || defined __arm__
|
||||
+# elif defined _M_ARM || defined __arm__ || defined __aarch64__
|
||||
# define ITT_ARCH ITT_ARCH_ARM
|
||||
# elif defined __powerpc64__
|
||||
# define ITT_ARCH ITT_ARCH_PPC64
|
||||
#elif _MSC_VER
|
@@ -4,7 +4,7 @@
|
||||
# Some are omitted here because they have special meanings below.
|
||||
1750a | 580 \
|
||||
| a29k \
|
||||
+ | aarch64 \
|
||||
+ | aarch64 \
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
||||
@@ -12,7 +12,7 @@
|
||||
# Recognize the basic CPU types with company name.
|
||||
580-* \
|
||||
| a29k-* \
|
||||
+ | aarch64-* \
|
||||
+ | aarch64-* \
|
||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
|
@@ -53,147 +53,3 @@ diff -ru USD-20.11/pxr/base/tf/pxrLZ4/lz4.cpp external_usd/pxr/base/tf/pxrLZ4/lz
|
||||
|
||||
/*-******************************
|
||||
* Compression functions
|
||||
|
||||
From 442d087962f762deeb8b6e49a0955753fcf9aeb9 Mon Sep 17 00:00:00 2001
|
||||
From: Tsahi Zidenberg <tsahee@amazon.com>
|
||||
Date: Sun, 15 Nov 2020 15:18:24 +0000
|
||||
Subject: [PATCH 1/2] stackTrace: support aarch64/linux
|
||||
|
||||
stacktrace calls syscall directly via assembler. Create compatible
|
||||
aarch64 code.
|
||||
---
|
||||
pxr/base/arch/stackTrace.cpp | 30 ++++++++++++++++++++++++------
|
||||
1 file changed, 24 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/pxr/base/arch/stackTrace.cpp b/pxr/base/arch/stackTrace.cpp
|
||||
index dcc1dfd46..c11aabeb1 100644
|
||||
--- a/pxr/base/arch/stackTrace.cpp
|
||||
+++ b/pxr/base/arch/stackTrace.cpp
|
||||
@@ -583,7 +583,6 @@ nonLockingLinux__execve (const char *file,
|
||||
char *const argv[],
|
||||
char *const envp[])
|
||||
{
|
||||
-#if defined(ARCH_BITS_64)
|
||||
/*
|
||||
* We make a direct system call here, because we can't find an
|
||||
* execve which corresponds with the non-locking fork we call
|
||||
@@ -594,7 +593,27 @@ nonLockingLinux__execve (const char *file,
|
||||
* hangs in a threaded app. (We use the non-locking fork to get
|
||||
* around problems with forking when we have had memory
|
||||
* corruption.) whew.
|
||||
- *
|
||||
+ */
|
||||
+
|
||||
+ unsigned long result;
|
||||
+
|
||||
+#if defined (__aarch64__)
|
||||
+ {
|
||||
+ register long __file_result asm ("x0") = (long)file;
|
||||
+ register char* const* __argv asm ("x1") = argv;
|
||||
+ register char* const* __envp asm ("x2") = envp;
|
||||
+ register long __num_execve asm ("x8") = 221;
|
||||
+ __asm__ __volatile__ (
|
||||
+ "svc 0"
|
||||
+ : "=r" (__file_result)
|
||||
+ : "r"(__num_execve), "r" (__file_result), "r" (__argv), "r" (__envp)
|
||||
+ : "memory"
|
||||
+ );
|
||||
+ result = __file_result;
|
||||
+ }
|
||||
+#elif defined(ARCH_CPU_INTEL) && defined(ARCH_BITS_64)
|
||||
+
|
||||
+ /*
|
||||
* %rdi, %rsi, %rdx, %rcx, %r8, %r9 are args 0-5
|
||||
* syscall clobbers %rcx and %r11
|
||||
*
|
||||
@@ -603,7 +622,6 @@ nonLockingLinux__execve (const char *file,
|
||||
* constraints to gcc.
|
||||
*/
|
||||
|
||||
- unsigned long result;
|
||||
__asm__ __volatile__ (
|
||||
"mov %0, %%rdi \n\t"
|
||||
"mov %%rcx, %%rsi \n\t"
|
||||
@@ -614,6 +632,9 @@ nonLockingLinux__execve (const char *file,
|
||||
: "0" (file), "c" (argv), "d" (envp)
|
||||
: "memory", "cc", "r11"
|
||||
);
|
||||
+#else
|
||||
+#error Unknown architecture
|
||||
+#endif
|
||||
|
||||
if (result >= 0xfffffffffffff000) {
|
||||
errno = -result;
|
||||
@@ -621,9 +642,6 @@ nonLockingLinux__execve (const char *file,
|
||||
}
|
||||
|
||||
return result;
|
||||
-#else
|
||||
-#error Unknown architecture
|
||||
-#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
From a1dffe02519bb3c6ccbbe8c6c58304da5db98995 Mon Sep 17 00:00:00 2001
|
||||
From: Tsahi Zidenberg <tsahee@amazon.com>
|
||||
Date: Sun, 15 Nov 2020 15:22:52 +0000
|
||||
Subject: [PATCH 2/2] timing: support aarch64/linux
|
||||
|
||||
The aarch64 arch-timer is directly accessible to userspace via two
|
||||
registers:
|
||||
CNTVCT_EL0 - holds the current counter value
|
||||
CNTFRQ_EL0 - holds the counter frequency (in Hz)
|
||||
---
|
||||
pxr/base/arch/timing.cpp | 6 ++++++
|
||||
pxr/base/arch/timing.h | 6 +++++-
|
||||
2 files changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/pxr/base/arch/timing.cpp b/pxr/base/arch/timing.cpp
|
||||
index 27ad58fed..9022950c1 100644
|
||||
--- a/pxr/base/arch/timing.cpp
|
||||
+++ b/pxr/base/arch/timing.cpp
|
||||
@@ -59,6 +59,11 @@ ARCH_HIDDEN
|
||||
void
|
||||
Arch_InitTickTimer()
|
||||
{
|
||||
+#ifdef __aarch64__
|
||||
+ uint64_t counter_hz;
|
||||
+ __asm __volatile("mrs %0, CNTFRQ_EL0" : "=&r" (counter_hz));
|
||||
+ Arch_NanosecondsPerTick = double(1e9) / double(counter_hz);
|
||||
+#else
|
||||
// NOTE: Normally ifstream would be cleaner, but it causes crashes when
|
||||
// used in conjunction with DSOs and the Intel Compiler.
|
||||
FILE *in;
|
||||
@@ -135,6 +140,7 @@ Arch_InitTickTimer()
|
||||
}
|
||||
|
||||
Arch_NanosecondsPerTick = double(1e9) / double(cpuHz);
|
||||
+#endif
|
||||
}
|
||||
#elif defined(ARCH_OS_WINDOWS)
|
||||
|
||||
diff --git a/pxr/base/arch/timing.h b/pxr/base/arch/timing.h
|
||||
index 67ec0d15f..6dc3e85a0 100644
|
||||
--- a/pxr/base/arch/timing.h
|
||||
+++ b/pxr/base/arch/timing.h
|
||||
@@ -36,7 +36,7 @@
|
||||
/// \addtogroup group_arch_SystemFunctions
|
||||
///@{
|
||||
|
||||
-#if defined(ARCH_OS_LINUX)
|
||||
+#if defined(ARCH_OS_LINUX) && defined(ARCH_CPU_INTEL)
|
||||
#include <x86intrin.h>
|
||||
#elif defined(ARCH_OS_DARWIN)
|
||||
#include <mach/mach_time.h>
|
||||
@@ -69,6 +69,10 @@ ArchGetTickTime()
|
||||
#elif defined(ARCH_CPU_INTEL)
|
||||
// On Intel we'll use the rdtsc instruction.
|
||||
return __rdtsc();
|
||||
+#elif defined (__aarch64__)
|
||||
+ uint64_t result;
|
||||
+ __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
|
||||
+ return result;
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
|
@@ -85,8 +85,8 @@ class VersionInfo:
|
||||
version_number = int(self._parse_header_file(blender_h, 'BLENDER_VERSION'))
|
||||
version_number_patch = int(self._parse_header_file(blender_h, 'BLENDER_VERSION_PATCH'))
|
||||
version_numbers = (version_number // 100, version_number % 100, version_number_patch)
|
||||
self.short_version = "%d.%d" % (version_numbers[0], version_numbers[1])
|
||||
self.version = "%d.%d.%d" % version_numbers
|
||||
self.short_version = "%d.%02d" % (version_numbers[0], version_numbers[1])
|
||||
self.version = "%d.%02d.%d" % version_numbers
|
||||
self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE')
|
||||
self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
|
||||
|
||||
|
@@ -34,7 +34,7 @@ FIND_PATH(EMBREE_INCLUDE_DIR
|
||||
include
|
||||
)
|
||||
|
||||
IF(NOT (("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") OR (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))))
|
||||
IF(NOT (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")))
|
||||
SET(_embree_SIMD_COMPONENTS
|
||||
embree_sse42
|
||||
embree_avx
|
||||
|
@@ -923,6 +923,10 @@ function(get_blender_version)
|
||||
math(EXPR _out_version_major "${_out_version} / 100")
|
||||
math(EXPR _out_version_minor "${_out_version} % 100")
|
||||
|
||||
# Zero pad the minor version so `_out_version_minor` is always two characters.
|
||||
# This is needed if the minor version is a single digit.
|
||||
string(REGEX REPLACE "^([0-9])$" "0\\1" _out_version_minor "${_out_version_minor}")
|
||||
|
||||
# output vars
|
||||
set(BLENDER_VERSION "${_out_version_major}.${_out_version_minor}" PARENT_SCOPE)
|
||||
set(BLENDER_VERSION_MAJOR "${_out_version_major}" PARENT_SCOPE)
|
||||
|
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "V3.0"
|
||||
PROJECT_NUMBER = "V2.93"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
@@ -50,8 +50,7 @@ you should be able to find the poll function with no knowledge of C.
|
||||
|
||||
Blender does have the functionality for poll functions to describe why they fail,
|
||||
but its currently not used much, if you're interested to help improve the API
|
||||
feel free to add calls to :class:`bpy.types.Operator.poll_message_set` (``CTX_wm_operator_poll_msg_set`` in C)
|
||||
where its not obvious why poll fails, e.g:
|
||||
feel free to add calls to ``CTX_wm_operator_poll_msg_set`` where its not obvious why poll fails, e.g:
|
||||
|
||||
>>> bpy.ops.gpencil.draw()
|
||||
RuntimeError: Operator bpy.ops.gpencil.draw.poll() Failed to find Grease Pencil data to draw into
|
||||
|
@@ -93,7 +93,6 @@ set(SRC_BVH_HEADERS
|
||||
bvh/bvh_local.h
|
||||
bvh/bvh_traversal.h
|
||||
bvh/bvh_types.h
|
||||
bvh/bvh_util.h
|
||||
bvh/bvh_volume.h
|
||||
bvh/bvh_volume_all.h
|
||||
bvh/bvh_embree.h
|
||||
|
@@ -29,11 +29,10 @@
|
||||
# include "kernel/bvh/bvh_embree.h"
|
||||
#endif
|
||||
|
||||
#include "kernel/bvh/bvh_types.h"
|
||||
#include "kernel/bvh/bvh_util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#include "kernel/bvh/bvh_types.h"
|
||||
|
||||
#ifndef __KERNEL_OPTIX__
|
||||
|
||||
/* Regular BVH traversal */
|
||||
@@ -534,4 +533,97 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
|
||||
}
|
||||
#endif /* __VOLUME_RECORD_ALL__ */
|
||||
|
||||
/* Ray offset to avoid self intersection.
|
||||
*
|
||||
* This function should be used to compute a modified ray start position for
|
||||
* rays leaving from a surface. */
|
||||
|
||||
ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
|
||||
{
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
const float epsilon_f = 1e-5f;
|
||||
/* ideally this should match epsilon_f, but instancing and motion blur
|
||||
* precision makes it problematic */
|
||||
const float epsilon_test = 1.0f;
|
||||
const int epsilon_i = 32;
|
||||
|
||||
float3 res;
|
||||
|
||||
/* x component */
|
||||
if (fabsf(P.x) < epsilon_test) {
|
||||
res.x = P.x + Ng.x * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint ix = __float_as_uint(P.x);
|
||||
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.x = __uint_as_float(ix);
|
||||
}
|
||||
|
||||
/* y component */
|
||||
if (fabsf(P.y) < epsilon_test) {
|
||||
res.y = P.y + Ng.y * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iy = __float_as_uint(P.y);
|
||||
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.y = __uint_as_float(iy);
|
||||
}
|
||||
|
||||
/* z component */
|
||||
if (fabsf(P.z) < epsilon_test) {
|
||||
res.z = P.z + Ng.z * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iz = __float_as_uint(P.z);
|
||||
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.z = __uint_as_float(iz);
|
||||
}
|
||||
|
||||
return res;
|
||||
#else
|
||||
const float epsilon_f = 1e-4f;
|
||||
return P + epsilon_f * Ng;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__))
|
||||
/* ToDo: Move to another file? */
|
||||
ccl_device int intersections_compare(const void *a, const void *b)
|
||||
{
|
||||
const Intersection *isect_a = (const Intersection *)a;
|
||||
const Intersection *isect_b = (const Intersection *)b;
|
||||
|
||||
if (isect_a->t < isect_b->t)
|
||||
return -1;
|
||||
else if (isect_a->t > isect_b->t)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SHADOW_RECORD_ALL__)
|
||||
ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits)
|
||||
{
|
||||
# ifdef __KERNEL_GPU__
|
||||
/* Use bubble sort which has more friendly memory pattern on GPU. */
|
||||
bool swapped;
|
||||
do {
|
||||
swapped = false;
|
||||
for (int j = 0; j < num_hits - 1; ++j) {
|
||||
if (hits[j].t > hits[j + 1].t) {
|
||||
struct Intersection tmp = hits[j];
|
||||
hits[j] = hits[j + 1];
|
||||
hits[j + 1] = tmp;
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
--num_hits;
|
||||
} while (swapped);
|
||||
# else
|
||||
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
|
||||
# endif
|
||||
}
|
||||
#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -180,10 +180,25 @@ ccl_device_inline
|
||||
|
||||
/* todo: optimize so primitive visibility flag indicates if
|
||||
* the primitive has a transparent shadow shader? */
|
||||
const int flags = intersection_get_shader_flags(kg, isect_array);
|
||||
int prim = kernel_tex_fetch(__prim_index, isect_array->prim);
|
||||
int shader = 0;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if (kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
|
||||
#endif
|
||||
{
|
||||
shader = kernel_tex_fetch(__tri_shader, prim);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else {
|
||||
float4 str = kernel_tex_fetch(__curves, prim);
|
||||
shader = __float_as_int(str.z);
|
||||
}
|
||||
#endif
|
||||
int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
|
||||
|
||||
/* if no transparent shadows, all light is blocked */
|
||||
if (!(flags & SD_HAS_TRANSPARENT_SHADOW)) {
|
||||
if (!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
|
||||
return true;
|
||||
}
|
||||
/* if maximum number of hits reached, block all light */
|
||||
|
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2013 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Ray offset to avoid self intersection.
|
||||
*
|
||||
* This function should be used to compute a modified ray start position for
|
||||
* rays leaving from a surface. */
|
||||
|
||||
ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
|
||||
{
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
const float epsilon_f = 1e-5f;
|
||||
/* ideally this should match epsilon_f, but instancing and motion blur
|
||||
* precision makes it problematic */
|
||||
const float epsilon_test = 1.0f;
|
||||
const int epsilon_i = 32;
|
||||
|
||||
float3 res;
|
||||
|
||||
/* x component */
|
||||
if (fabsf(P.x) < epsilon_test) {
|
||||
res.x = P.x + Ng.x * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint ix = __float_as_uint(P.x);
|
||||
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.x = __uint_as_float(ix);
|
||||
}
|
||||
|
||||
/* y component */
|
||||
if (fabsf(P.y) < epsilon_test) {
|
||||
res.y = P.y + Ng.y * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iy = __float_as_uint(P.y);
|
||||
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.y = __uint_as_float(iy);
|
||||
}
|
||||
|
||||
/* z component */
|
||||
if (fabsf(P.z) < epsilon_test) {
|
||||
res.z = P.z + Ng.z * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iz = __float_as_uint(P.z);
|
||||
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.z = __uint_as_float(iz);
|
||||
}
|
||||
|
||||
return res;
|
||||
#else
|
||||
const float epsilon_f = 1e-4f;
|
||||
return P + epsilon_f * Ng;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__))
|
||||
/* ToDo: Move to another file? */
|
||||
ccl_device int intersections_compare(const void *a, const void *b)
|
||||
{
|
||||
const Intersection *isect_a = (const Intersection *)a;
|
||||
const Intersection *isect_b = (const Intersection *)b;
|
||||
|
||||
if (isect_a->t < isect_b->t)
|
||||
return -1;
|
||||
else if (isect_a->t > isect_b->t)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SHADOW_RECORD_ALL__)
|
||||
ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits)
|
||||
{
|
||||
kernel_assert(num_hits > 0);
|
||||
|
||||
# ifdef __KERNEL_GPU__
|
||||
/* Use bubble sort which has more friendly memory pattern on GPU. */
|
||||
bool swapped;
|
||||
do {
|
||||
swapped = false;
|
||||
for (int j = 0; j < num_hits - 1; ++j) {
|
||||
if (hits[j].t > hits[j + 1].t) {
|
||||
struct Intersection tmp = hits[j];
|
||||
hits[j] = hits[j + 1];
|
||||
hits[j + 1] = tmp;
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
--num_hits;
|
||||
} while (swapped);
|
||||
# else
|
||||
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
|
||||
# endif
|
||||
}
|
||||
#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */
|
||||
|
||||
/* Utility to quickly get a shader flags from an intersection. */
|
||||
|
||||
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals *ccl_restrict kg,
|
||||
const Intersection *isect)
|
||||
{
|
||||
const int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
int shader = 0;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE)
|
||||
#endif
|
||||
{
|
||||
shader = kernel_tex_fetch(__tri_shader, prim);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else {
|
||||
float4 str = kernel_tex_fetch(__curves, prim);
|
||||
shader = __float_as_int(str.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
|
||||
}
|
||||
|
||||
ccl_device_forceinline int intersection_get_shader(KernelGlobals *ccl_restrict kg,
|
||||
const Intersection *isect)
|
||||
{
|
||||
const int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
int shader = 0;
|
||||
|
||||
#ifdef __HAIR__
|
||||
if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE)
|
||||
#endif
|
||||
{
|
||||
shader = kernel_tex_fetch(__tri_shader, prim);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else {
|
||||
float4 str = kernel_tex_fetch(__curves, prim);
|
||||
shader = __float_as_int(str.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
return shader & SHADER_MASK;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -65,6 +65,7 @@ ccl_device_forceinline bool kernel_path_scene_intersect(KernelGlobals *kg,
|
||||
uint visibility = path_state_ray_visibility(kg, state);
|
||||
|
||||
if (path_state_ao_bounce(kg, state)) {
|
||||
visibility = PATH_RAY_SHADOW;
|
||||
ray->t = kernel_data.background.ao_distance;
|
||||
}
|
||||
|
||||
@@ -415,13 +416,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
||||
break;
|
||||
}
|
||||
else if (path_state_ao_bounce(kg, state)) {
|
||||
if (intersection_get_shader_flags(kg, &isect) &
|
||||
(SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
|
||||
state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Setup shader data. */
|
||||
@@ -559,13 +554,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
|
||||
break;
|
||||
}
|
||||
else if (path_state_ao_bounce(kg, state)) {
|
||||
if (intersection_get_shader_flags(kg, &isect) &
|
||||
(SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
|
||||
state->flag |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Setup shader data. */
|
||||
|
@@ -605,13 +605,6 @@ ccl_device_noinline
|
||||
if (hit) {
|
||||
t = ray->t;
|
||||
}
|
||||
else if (bounce == 0) {
|
||||
/* Restore original position if nothing was hit after the first bounce.
|
||||
* Otherwise if the ray_offset() to avoid self-intersection is relatively
|
||||
* large compared to the scattering radius, we go never backup high enough
|
||||
* to exit the surface. */
|
||||
ray->P = sd->P;
|
||||
}
|
||||
|
||||
/* Advance to new scatter location. */
|
||||
ray->P += t * ray->D;
|
||||
|
@@ -895,8 +895,6 @@ enum ShaderDataFlag {
|
||||
SD_HAS_CONSTANT_EMISSION = (1 << 27),
|
||||
/* Needs to access attributes for volume rendering */
|
||||
SD_NEED_VOLUME_ATTRIBUTES = (1 << 28),
|
||||
/* Shader has emission */
|
||||
SD_HAS_EMISSION = (1 << 29),
|
||||
|
||||
SD_SHADER_FLAGS = (SD_USE_MIS | SD_HAS_TRANSPARENT_SHADOW | SD_HAS_VOLUME | SD_HAS_ONLY_VOLUME |
|
||||
SD_HETEROGENEOUS_VOLUME | SD_HAS_BSSRDF_BUMP | SD_VOLUME_EQUIANGULAR |
|
||||
|
@@ -528,8 +528,6 @@ void ShaderManager::device_update_common(Device *device,
|
||||
|
||||
if (shader->get_use_mis())
|
||||
flag |= SD_USE_MIS;
|
||||
if (shader->has_surface_emission)
|
||||
flag |= SD_HAS_EMISSION;
|
||||
if (shader->has_surface_transparent && shader->get_use_transparent_shadow())
|
||||
flag |= SD_HAS_TRANSPARENT_SHADOW;
|
||||
if (shader->has_volume) {
|
||||
|
@@ -124,7 +124,7 @@ static struct StepTy {
|
||||
template<class type, int i0, int i1, int i2, int i3> type shuffle_neon(const type &a)
|
||||
{
|
||||
if (i0 == i1 && i0 == i2 && i0 == i3) {
|
||||
return type(vdupq_laneq_s32(int32x4_t(a), i0));
|
||||
return vdupq_laneq_s32(a, i0);
|
||||
}
|
||||
static const uint8_t tbl[16] = {(i0 * 4) + 0,
|
||||
(i0 * 4) + 1,
|
||||
@@ -143,7 +143,7 @@ template<class type, int i0, int i1, int i2, int i3> type shuffle_neon(const typ
|
||||
(i3 * 4) + 2,
|
||||
(i3 * 4) + 3};
|
||||
|
||||
return type(vqtbl1q_s8(int8x16_t(a), *(uint8x16_t *)tbl));
|
||||
return vqtbl1q_s8(int8x16_t(a), *(int8x16_t *)tbl);
|
||||
}
|
||||
|
||||
template<class type, int i0, int i1, int i2, int i3>
|
||||
@@ -167,7 +167,7 @@ type shuffle_neon(const type &a, const type &b)
|
||||
(i3 * 4) + 2,
|
||||
(i3 * 4) + 3};
|
||||
|
||||
return type(vqtbl1q_s8(int8x16_t(b), *(uint8x16_t *)tbl));
|
||||
return vqtbl1q_s8(int8x16_t(b), *(int8x16_t *)tbl);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -188,7 +188,7 @@ type shuffle_neon(const type &a, const type &b)
|
||||
(i3 * 4) + 2 + 16,
|
||||
(i3 * 4) + 3 + 16};
|
||||
|
||||
return type(vqtbl2q_s8((int8x16x2_t){int8x16_t(a), int8x16_t(b)}, *(uint8x16_t *)tbl));
|
||||
return vqtbl2q_s8((int8x16x2_t){a, b}, *(int8x16_t *)tbl);
|
||||
}
|
||||
}
|
||||
#endif /* __KERNEL_NEON */
|
||||
|
@@ -283,7 +283,7 @@ __forceinline uint32_t popcnt(const sseb &a)
|
||||
{
|
||||
# if defined(__KERNEL_NEON__)
|
||||
const int32x4_t mask = {1, 1, 1, 1};
|
||||
int32x4_t t = vandq_s32(vreinterpretq_s32_m128(a.m128), mask);
|
||||
int32x4_t t = vandq_s32(a.m128, mask);
|
||||
return vaddvq_s32(t);
|
||||
# else
|
||||
return _mm_popcnt_u32(_mm_movemask_ps(a));
|
||||
@@ -299,7 +299,7 @@ __forceinline uint32_t popcnt(const sseb &a)
|
||||
__forceinline bool reduce_and(const sseb &a)
|
||||
{
|
||||
# if defined(__KERNEL_NEON__)
|
||||
return vaddvq_s32(vreinterpretq_s32_m128(a.m128)) == -4;
|
||||
return vaddvq_s32(a.m128) == -4;
|
||||
# else
|
||||
return _mm_movemask_ps(a) == 0xf;
|
||||
# endif
|
||||
@@ -307,7 +307,7 @@ __forceinline bool reduce_and(const sseb &a)
|
||||
__forceinline bool reduce_or(const sseb &a)
|
||||
{
|
||||
# if defined(__KERNEL_NEON__)
|
||||
return vaddvq_s32(vreinterpretq_s32_m128(a.m128)) != 0x0;
|
||||
return vaddvq_s32(a.m128) != 0x0;
|
||||
# else
|
||||
return _mm_movemask_ps(a) != 0x0;
|
||||
# endif
|
||||
@@ -315,7 +315,7 @@ __forceinline bool reduce_or(const sseb &a)
|
||||
__forceinline bool all(const sseb &b)
|
||||
{
|
||||
# if defined(__KERNEL_NEON__)
|
||||
return vaddvq_s32(vreinterpretq_s32_m128(b.m128)) == -4;
|
||||
return vaddvq_s32(b.m128) == -4;
|
||||
# else
|
||||
return _mm_movemask_ps(b) == 0xf;
|
||||
# endif
|
||||
@@ -323,7 +323,7 @@ __forceinline bool all(const sseb &b)
|
||||
__forceinline bool any(const sseb &b)
|
||||
{
|
||||
# if defined(__KERNEL_NEON__)
|
||||
return vaddvq_s32(vreinterpretq_s32_m128(b.m128)) != 0x0;
|
||||
return vaddvq_s32(b.m128) != 0x0;
|
||||
# else
|
||||
return _mm_movemask_ps(b) != 0x0;
|
||||
# endif
|
||||
@@ -331,7 +331,7 @@ __forceinline bool any(const sseb &b)
|
||||
__forceinline bool none(const sseb &b)
|
||||
{
|
||||
# if defined(__KERNEL_NEON__)
|
||||
return vaddvq_s32(vreinterpretq_s32_m128(b.m128)) == 0x0;
|
||||
return vaddvq_s32(b.m128) == 0x0;
|
||||
# else
|
||||
return _mm_movemask_ps(b) == 0x0;
|
||||
# endif
|
||||
|
@@ -596,7 +596,7 @@ template<size_t i0, size_t i1, size_t i2, size_t i3>
|
||||
__forceinline const ssef shuffle(const ssef &b)
|
||||
{
|
||||
# ifdef __KERNEL_NEON__
|
||||
return shuffle_neon<float32x4_t, i0, i1, i2, i3>(b.m128);
|
||||
return shuffle_neon<ssef, i0, i1, i2, i3>(b.m128);
|
||||
# else
|
||||
return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(i3, i2, i1, i0)));
|
||||
# endif
|
||||
@@ -625,7 +625,7 @@ __forceinline const ssef shuffle(const ssef &a, const ssef &b)
|
||||
template<size_t i0> __forceinline const ssef shuffle(const ssef &a, const ssef &b)
|
||||
{
|
||||
# ifdef __KERNEL_NEON__
|
||||
return shuffle_neon<float32x4_t, i0, i0, i0, i0>(a, b);
|
||||
return shuffle<float32x4_t, i0, i0, i0, i0>(a, b);
|
||||
# else
|
||||
return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i0, i0, i0, i0));
|
||||
# endif
|
||||
|
@@ -446,8 +446,7 @@ template<size_t i0, size_t i1, size_t i2, size_t i3>
|
||||
__forceinline const ssei shuffle(const ssei &a)
|
||||
{
|
||||
# ifdef __KERNEL_NEON__
|
||||
int32x4_t result = shuffle_neon<int32x4_t, i0, i1, i2, i3>(vreinterpretq_s32_m128i(a));
|
||||
return vreinterpretq_m128i_s32(result);
|
||||
return shuffle_neon<ssei, i0, i1, i2, i3>(a);
|
||||
# else
|
||||
return _mm_shuffle_epi32(a, _MM_SHUFFLE(i3, i2, i1, i0));
|
||||
# endif
|
||||
@@ -457,8 +456,7 @@ template<size_t i0, size_t i1, size_t i2, size_t i3>
|
||||
__forceinline const ssei shuffle(const ssei &a, const ssei &b)
|
||||
{
|
||||
# ifdef __KERNEL_NEON__
|
||||
int32x4_t result = shuffle_neon<int32x4_t, i0, i1, i2, i3>(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b));
|
||||
return vreinterpretq_m128i_s32(result);
|
||||
return shuffle_neon<ssei, i0, i1, i2, i3>(a, b);
|
||||
# else
|
||||
return _mm_castps_si128(
|
||||
_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
|
||||
@@ -516,7 +514,7 @@ __forceinline const ssei vreduce_add(const ssei &v)
|
||||
__forceinline int reduce_min(const ssei &v)
|
||||
{
|
||||
# ifdef __KERNEL_NEON__
|
||||
return vminvq_s32(vreinterpretq_s32_m128i(v));
|
||||
return vminvq_s32(v);
|
||||
# else
|
||||
return extract<0>(vreduce_min(v));
|
||||
# endif
|
||||
@@ -524,7 +522,7 @@ __forceinline int reduce_min(const ssei &v)
|
||||
__forceinline int reduce_max(const ssei &v)
|
||||
{
|
||||
# ifdef __KERNEL_NEON__
|
||||
return vmaxvq_s32(vreinterpretq_s32_m128i(v));
|
||||
return vmaxvq_s32(v);
|
||||
# else
|
||||
return extract<0>(vreduce_max(v));
|
||||
# endif
|
||||
@@ -532,7 +530,7 @@ __forceinline int reduce_max(const ssei &v)
|
||||
__forceinline int reduce_add(const ssei &v)
|
||||
{
|
||||
# ifdef __KERNEL_NEON__
|
||||
return vaddvq_s32(vreinterpretq_s32_m128i(v));
|
||||
return vaddvq_s32(v);
|
||||
# else
|
||||
return extract<0>(vreduce_add(v));
|
||||
# endif
|
||||
|
@@ -166,33 +166,12 @@ static void __cpuid(int data[4], int selector)
|
||||
|
||||
string system_cpu_brand_string()
|
||||
{
|
||||
#if !defined(WIN32) && !defined(__x86_64__) && !defined(__i386__)
|
||||
FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
|
||||
if (cpuinfo != nullptr) {
|
||||
char cpuinfo_buf[513] = "";
|
||||
fread(cpuinfo_buf, sizeof(cpuinfo_buf) - 1, 1, cpuinfo);
|
||||
fclose(cpuinfo);
|
||||
|
||||
char *modelname = strstr(cpuinfo_buf, "model name");
|
||||
if (modelname != nullptr) {
|
||||
modelname = strchr(modelname, ':');
|
||||
if (modelname != nullptr) {
|
||||
modelname += 2;
|
||||
char *modelname_end = strchr(modelname, '\n');
|
||||
if (modelname_end != nullptr) {
|
||||
*modelname_end = '\0';
|
||||
return modelname;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
char buf[49] = {0};
|
||||
int result[4] = {0};
|
||||
|
||||
__cpuid(result, 0x80000000);
|
||||
|
||||
if (result[0] != 0 && result[0] >= (int)0x80000004) {
|
||||
if (result[0] >= (int)0x80000004) {
|
||||
__cpuid((int *)(buf + 0), 0x80000002);
|
||||
__cpuid((int *)(buf + 16), 0x80000003);
|
||||
__cpuid((int *)(buf + 32), 0x80000004);
|
||||
@@ -204,7 +183,7 @@ string system_cpu_brand_string()
|
||||
|
||||
return brand;
|
||||
}
|
||||
#endif
|
||||
|
||||
return "Unknown CPU";
|
||||
}
|
||||
|
||||
|
@@ -561,7 +561,6 @@ static OCIO_GPUDisplayShader &getGPUDisplayShader(
|
||||
GpuShaderDescRcPtr shaderdesc_to_scene_linear = GpuShaderDesc::CreateShaderDesc();
|
||||
shaderdesc_to_scene_linear->setLanguage(GPU_LANGUAGE_GLSL_1_3);
|
||||
shaderdesc_to_scene_linear->setFunctionName("OCIO_to_scene_linear");
|
||||
shaderdesc_to_scene_linear->setResourcePrefix("to_scene");
|
||||
(*(ConstProcessorRcPtr *)processor_to_scene_linear)
|
||||
->getDefaultGPUProcessor()
|
||||
->extractGpuShaderInfo(shaderdesc_to_scene_linear);
|
||||
@@ -570,7 +569,6 @@ static OCIO_GPUDisplayShader &getGPUDisplayShader(
|
||||
GpuShaderDescRcPtr shaderdesc_to_display = GpuShaderDesc::CreateShaderDesc();
|
||||
shaderdesc_to_display->setLanguage(GPU_LANGUAGE_GLSL_1_3);
|
||||
shaderdesc_to_display->setFunctionName("OCIO_to_display");
|
||||
shaderdesc_to_scene_linear->setResourcePrefix("to_display");
|
||||
(*(ConstProcessorRcPtr *)processor_to_display)
|
||||
->getDefaultGPUProcessor()
|
||||
->extractGpuShaderInfo(shaderdesc_to_display);
|
||||
|
Binary file not shown.
Submodule release/scripts/addons updated: 4cb833e84a...1dbdb95ed9
Submodule release/scripts/addons_contrib updated: 8970953d4a...5523cbaed6
@@ -219,40 +219,6 @@ def RKS_GEN_scaling(_ksi, _context, ks, data):
|
||||
else:
|
||||
ks.paths.add(id_block, path)
|
||||
|
||||
|
||||
# Custom Properties
|
||||
def RKS_GEN_custom_props(_ksi, _context, ks, data):
|
||||
# get id-block and path info
|
||||
id_block, base_path, grouping = get_transform_generators_base_info(data)
|
||||
|
||||
# Only some RNA types can be animated.
|
||||
prop_type_compat = {bpy.types.BoolProperty,
|
||||
bpy.types.IntProperty,
|
||||
bpy.types.FloatProperty}
|
||||
|
||||
# When working with a pose, 'id_block' is the armature object (which should
|
||||
# get the animation data), whereas 'data' is the bone being keyed.
|
||||
for cprop_name in data.keys():
|
||||
# ignore special "_RNA_UI" used for UI editing
|
||||
if cprop_name == "_RNA_UI":
|
||||
continue
|
||||
|
||||
prop_path = '["%s"]' % bpy.utils.escape_identifier(cprop_name)
|
||||
try:
|
||||
rna_property = data.path_resolve(prop_path, False)
|
||||
except ValueError as ex:
|
||||
# This happens when a custom property is set to None. In that case it cannot
|
||||
# be converted to an FCurve-compatible value, so we can't keyframe it anyway.
|
||||
continue
|
||||
if rna_property.rna_type not in prop_type_compat:
|
||||
continue
|
||||
|
||||
path = "%s%s" % (base_path, prop_path)
|
||||
if grouping:
|
||||
ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
|
||||
else:
|
||||
ks.paths.add(id_block, path)
|
||||
|
||||
# ------
|
||||
|
||||
|
||||
|
@@ -99,15 +99,6 @@ class PREFERENCES_OT_copy_prev(Operator):
|
||||
version = bpy.app.version
|
||||
version_new = ((version[0] * 100) + version[1])
|
||||
version_old = ((version[0] * 100) + version[1]) - 1
|
||||
|
||||
# Special case, remove when the version is > 3.0.
|
||||
if version_new == 300:
|
||||
version_new = 294
|
||||
version_old = 293
|
||||
else:
|
||||
print("TODO: remove exception!")
|
||||
# End special case.
|
||||
|
||||
# Ensure we only try to copy files from a point release.
|
||||
# The check below ensures the second numbers match.
|
||||
while (version_new % 100) // 10 == (version_old % 100) // 10:
|
||||
|
@@ -71,10 +71,10 @@ class POINTCLOUD_MT_add_attribute(Menu):
|
||||
layout = self.layout
|
||||
pointcloud = context.pointcloud
|
||||
|
||||
self.add_standard_attribute(layout, pointcloud, 'radius', 'FLOAT', 'POINT')
|
||||
self.add_standard_attribute(layout, pointcloud, 'color', 'FLOAT_COLOR', 'POINT')
|
||||
self.add_standard_attribute(layout, pointcloud, 'id', 'INT', 'POINT')
|
||||
self.add_standard_attribute(layout, pointcloud, 'velocity', 'FLOAT_VECTOR', 'POINT')
|
||||
self.add_standard_attribute(layout, pointcloud, 'Radius', 'FLOAT', 'POINT')
|
||||
self.add_standard_attribute(layout, pointcloud, 'Color', 'FLOAT_COLOR', 'POINT')
|
||||
self.add_standard_attribute(layout, pointcloud, 'Particle ID', 'INT', 'POINT')
|
||||
self.add_standard_attribute(layout, pointcloud, 'Velocity', 'FLOAT_VECTOR', 'POINT')
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@@ -821,12 +821,6 @@ class GreasePencilLayerMasksPanel:
|
||||
col2.menu("GPENCIL_MT_layer_mask_menu", icon='ADD', text="")
|
||||
col2.operator("gpencil.layer_mask_remove", icon='REMOVE', text="")
|
||||
|
||||
col2.separator()
|
||||
|
||||
sub = col2.column(align=True)
|
||||
sub.operator("gpencil.layer_mask_move", icon='TRIA_UP', text="").type = 'UP'
|
||||
sub.operator("gpencil.layer_mask_move", icon='TRIA_DOWN', text="").type = 'DOWN'
|
||||
|
||||
|
||||
class GreasePencilLayerRelationsPanel:
|
||||
|
||||
|
@@ -246,12 +246,11 @@ class IMAGE_MT_image(Menu):
|
||||
layout.separator()
|
||||
layout.operator("image.pack", text="Pack")
|
||||
|
||||
if ima and context.area.ui_type == 'IMAGE_EDITOR':
|
||||
if ima:
|
||||
layout.separator()
|
||||
layout.operator("palette.extract_from_image", text="Extract Palette")
|
||||
layout.operator("gpencil.image_to_grease_pencil", text="Generate Grease Pencil")
|
||||
|
||||
|
||||
class IMAGE_MT_image_flip(Menu):
|
||||
bl_label = "Flip"
|
||||
|
||||
|
@@ -92,15 +92,16 @@ class INFO_MT_area(Menu):
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("screen.screen_full_area")
|
||||
layout.operator(
|
||||
"screen.screen_full_area",
|
||||
text="Toggle Fullscreen Area").use_hide_panels = True
|
||||
layout.operator("screen.area_dupli")
|
||||
layout.operator("screen.area_dupli", icon='WINDOW')
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("screen.area_close")
|
||||
layout.operator("screen.screen_full_area")
|
||||
layout.operator(
|
||||
"screen.screen_full_area",
|
||||
text="Toggle Fullscreen Area",
|
||||
icon='FULLSCREEN_ENTER',
|
||||
).use_hide_panels = True
|
||||
|
||||
|
||||
class INFO_MT_context_menu(Menu):
|
||||
|
@@ -570,7 +570,7 @@ class USERPREF_PT_system_sound(SystemPanel, CenterAlignMixIn, Panel):
|
||||
layout.prop(system, "audio_device", expand=False)
|
||||
|
||||
sub = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False)
|
||||
sub.active = system.audio_device not in {'NONE', 'None'}
|
||||
sub.active = system.audio_device not in {'NONE', 'Null'}
|
||||
sub.prop(system, "audio_channels", text="Channels")
|
||||
sub.prop(system, "audio_mixing_buffer", text="Mixing Buffer")
|
||||
sub.prop(system, "audio_sample_rate", text="Sample Rate")
|
||||
|
@@ -44,7 +44,6 @@ ANIM_KS_LOCATION_ID = "Location"
|
||||
ANIM_KS_ROTATION_ID = "Rotation"
|
||||
ANIM_KS_SCALING_ID = "Scaling"
|
||||
ANIM_KS_LOC_ROT_SCALE_ID = "LocRotScale"
|
||||
ANIM_KS_LOC_ROT_SCALE_CPROP_ID = "LocRotScaleCProp"
|
||||
ANIM_KS_AVAILABLE_ID = "Available"
|
||||
ANIM_KS_WHOLE_CHARACTER_ID = "WholeCharacter"
|
||||
ANIM_KS_WHOLE_CHARACTER_SELECTED_ID = "WholeCharacterSelected"
|
||||
@@ -160,22 +159,6 @@ class BUILTIN_KSI_LocRotScale(KeyingSetInfo):
|
||||
keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
|
||||
|
||||
|
||||
# LocRotScaleCProp
|
||||
class BUILTIN_KSI_LocRotScaleCProp(KeyingSetInfo):
|
||||
"""Key location/rotation/scale as well as custom properties"""
|
||||
bl_idname = ANIM_KS_LOC_ROT_SCALE_CPROP_ID
|
||||
bl_label = "Location, Rotation, Scale & Custom Properties"
|
||||
|
||||
poll = keyingsets_utils.RKS_POLL_selected_items
|
||||
iterator = keyingsets_utils.RKS_ITER_selected_item
|
||||
|
||||
def generate(self, context, ks, data):
|
||||
keyingsets_utils.RKS_GEN_location(self, context, ks, data)
|
||||
keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
|
||||
keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
|
||||
keyingsets_utils.RKS_GEN_custom_props(self, context, ks, data)
|
||||
|
||||
|
||||
# RotScale
|
||||
class BUILTIN_KSI_RotScale(KeyingSetInfo):
|
||||
"""Insert a keyframe on each of the rotation and scale channels"""
|
||||
@@ -367,7 +350,7 @@ class BUILTIN_KSI_Available(KeyingSetInfo):
|
||||
bl_label = "Available"
|
||||
|
||||
# poll - selected objects or selected object with animation data
|
||||
def poll(self, context):
|
||||
def poll(ksi, context):
|
||||
ob = context.active_object
|
||||
if ob:
|
||||
# TODO: this fails if one animation-less object is active, but many others are selected
|
||||
@@ -383,7 +366,14 @@ class BUILTIN_KSI_Available(KeyingSetInfo):
|
||||
|
||||
###############################
|
||||
|
||||
class WholeCharacterMixin:
|
||||
|
||||
# All properties that are likely to get animated in a character rig
|
||||
class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
|
||||
"""Insert a keyframe for all properties that are likely to get animated in a character rig """ \
|
||||
"""(useful when blocking out a shot)"""
|
||||
bl_idname = ANIM_KS_WHOLE_CHARACTER_ID
|
||||
bl_label = "Whole Character"
|
||||
|
||||
# these prefixes should be avoided, as they are not really bones
|
||||
# that animators should be touching (or need to touch)
|
||||
badBonePrefixes = (
|
||||
@@ -397,37 +387,38 @@ class WholeCharacterMixin:
|
||||
)
|
||||
|
||||
# poll - pose-mode on active object only
|
||||
def poll(self, context):
|
||||
def poll(ksi, context):
|
||||
return ((context.active_object) and (context.active_object.pose) and
|
||||
(context.active_object.mode == 'POSE'))
|
||||
|
||||
# iterator - all bones regardless of selection
|
||||
def iterator(self, context, ks):
|
||||
def iterator(ksi, context, ks):
|
||||
for bone in context.active_object.pose.bones:
|
||||
if not bone.name.startswith(self.badBonePrefixes):
|
||||
self.generate(context, ks, bone)
|
||||
if not bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
|
||||
ksi.generate(context, ks, bone)
|
||||
|
||||
# generator - all unlocked bone transforms + custom properties
|
||||
def generate(self, context, ks, bone):
|
||||
def generate(ksi, context, ks, bone):
|
||||
# loc, rot, scale - only include unlocked ones
|
||||
if not bone.bone.use_connect:
|
||||
self.doLoc(ks, bone)
|
||||
ksi.doLoc(ks, bone)
|
||||
|
||||
if bone.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
|
||||
self.doRot4d(ks, bone)
|
||||
ksi.doRot4d(ks, bone)
|
||||
else:
|
||||
self.doRot3d(ks, bone)
|
||||
self.doScale(ks, bone)
|
||||
ksi.doRot3d(ks, bone)
|
||||
ksi.doScale(ks, bone)
|
||||
|
||||
# bbone properties?
|
||||
self.doBBone(context, ks, bone)
|
||||
ksi.doBBone(context, ks, bone)
|
||||
|
||||
# custom props?
|
||||
self.doCustomProps(ks, bone)
|
||||
ksi.doCustomProps(ks, bone)
|
||||
|
||||
# ----------------
|
||||
|
||||
# helper to add some bone's property to the Keying Set
|
||||
def addProp(self, ks, bone, prop, index=-1, use_groups=True):
|
||||
def addProp(ksi, ks, bone, prop, index=-1, use_groups=True):
|
||||
# add the property name to the base path
|
||||
id_path = bone.path_from_id()
|
||||
id_block = bone.id_data
|
||||
@@ -448,16 +439,16 @@ class WholeCharacterMixin:
|
||||
# ----------------
|
||||
|
||||
# location properties
|
||||
def doLoc(self, ks, bone):
|
||||
def doLoc(ksi, ks, bone):
|
||||
if bone.lock_location == (False, False, False):
|
||||
self.addProp(ks, bone, "location")
|
||||
ksi.addProp(ks, bone, "location")
|
||||
else:
|
||||
for i in range(3):
|
||||
if not bone.lock_location[i]:
|
||||
self.addProp(ks, bone, "location", i)
|
||||
ksi.addProp(ks, bone, "location", i)
|
||||
|
||||
# rotation properties
|
||||
def doRot4d(self, ks, bone):
|
||||
def doRot4d(ksi, ks, bone):
|
||||
# rotation mode affects the property used
|
||||
if bone.rotation_mode == 'QUATERNION':
|
||||
prop = "rotation_quaternion"
|
||||
@@ -468,40 +459,40 @@ class WholeCharacterMixin:
|
||||
if bone.lock_rotations_4d:
|
||||
# can check individually
|
||||
if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w is False):
|
||||
self.addProp(ks, bone, prop)
|
||||
ksi.addProp(ks, bone, prop)
|
||||
else:
|
||||
if bone.lock_rotation_w is False:
|
||||
self.addProp(ks, bone, prop, 0) # w = 0
|
||||
ksi.addProp(ks, bone, prop, 0) # w = 0
|
||||
|
||||
for i in range(3):
|
||||
if not bone.lock_rotation[i]:
|
||||
self.addProp(ks, bone, prop, i + 1) # i + 1, since here x/y/z = 1,2,3, and w=0
|
||||
ksi.addProp(ks, bone, prop, i + 1) # i + 1, since here x/y/z = 1,2,3, and w=0
|
||||
elif True not in bone.lock_rotation:
|
||||
# if axis-angle rotations get locked as eulers, then it's too messy to allow anything
|
||||
# other than all open unless we keyframe the whole lot
|
||||
self.addProp(ks, bone, prop)
|
||||
ksi.addProp(ks, bone, prop)
|
||||
|
||||
def doRot3d(self, ks, bone):
|
||||
def doRot3d(ksi, ks, bone):
|
||||
if bone.lock_rotation == (False, False, False):
|
||||
self.addProp(ks, bone, "rotation_euler")
|
||||
ksi.addProp(ks, bone, "rotation_euler")
|
||||
else:
|
||||
for i in range(3):
|
||||
if not bone.lock_rotation[i]:
|
||||
self.addProp(ks, bone, "rotation_euler", i)
|
||||
ksi.addProp(ks, bone, "rotation_euler", i)
|
||||
|
||||
# scale properties
|
||||
def doScale(self, ks, bone):
|
||||
def doScale(ksi, ks, bone):
|
||||
if bone.lock_scale == (0, 0, 0):
|
||||
self.addProp(ks, bone, "scale")
|
||||
ksi.addProp(ks, bone, "scale")
|
||||
else:
|
||||
for i in range(3):
|
||||
if not bone.lock_scale[i]:
|
||||
self.addProp(ks, bone, "scale", i)
|
||||
ksi.addProp(ks, bone, "scale", i)
|
||||
|
||||
# ----------------
|
||||
|
||||
# bendy bone properties
|
||||
def doBBone(self, context, ks, pchan):
|
||||
def doBBone(ksi, context, ks, pchan):
|
||||
bone = pchan.bone
|
||||
|
||||
# This check is crude, but is the best we can do for now
|
||||
@@ -509,12 +500,12 @@ class WholeCharacterMixin:
|
||||
# (and the bone is a control bone). This may lead to some
|
||||
# false positives...
|
||||
if bone.bbone_segments > 1:
|
||||
keyingsets_utils.RKS_GEN_bendy_bones(self, context, ks, pchan)
|
||||
keyingsets_utils.RKS_GEN_bendy_bones(ksi, context, ks, pchan)
|
||||
|
||||
# ----------------
|
||||
|
||||
# custom properties
|
||||
def doCustomProps(self, ks, bone):
|
||||
def doCustomProps(ksi, ks, bone):
|
||||
|
||||
prop_type_compat = {bpy.types.BoolProperty,
|
||||
bpy.types.IntProperty,
|
||||
@@ -537,34 +528,39 @@ class WholeCharacterMixin:
|
||||
# be converted to an FCurve-compatible value, so we can't keyframe it anyway.
|
||||
continue
|
||||
if rna_property.rna_type in prop_type_compat:
|
||||
self.addProp(ks, bone, prop_path)
|
||||
ksi.addProp(ks, bone, prop_path)
|
||||
elif prop_rna.is_animatable:
|
||||
self.addProp(ks, bone, prop)
|
||||
ksi.addProp(ks, bone, prop)
|
||||
|
||||
# All properties that are likely to get animated in a character rig, only selected bones.
|
||||
|
||||
|
||||
class BUILTIN_KSI_WholeCharacter(WholeCharacterMixin, KeyingSetInfo):
|
||||
"""Insert a keyframe for all properties that are likely to get animated in a character rig """ \
|
||||
"""(useful when blocking out a shot)"""
|
||||
bl_idname = ANIM_KS_WHOLE_CHARACTER_ID
|
||||
bl_label = "Whole Character"
|
||||
|
||||
|
||||
class BUILTIN_KSI_WholeCharacterSelected(WholeCharacterMixin, KeyingSetInfo):
|
||||
class BUILTIN_KSI_WholeCharacterSelected(KeyingSetInfo):
|
||||
"""Insert a keyframe for all properties that are likely to get animated in a character rig """ \
|
||||
"""(only selected bones)"""
|
||||
bl_idname = ANIM_KS_WHOLE_CHARACTER_SELECTED_ID
|
||||
bl_label = "Whole Character (Selected Bones Only)"
|
||||
|
||||
# iterator - all bones regardless of selection
|
||||
def iterator(self, context, ks):
|
||||
def iterator(ksi, context, ks):
|
||||
# Use either the selected bones, or all of them if none are selected.
|
||||
bones = context.selected_pose_bones_from_active_object or context.active_object.pose.bones
|
||||
|
||||
for bone in bones:
|
||||
if bone.name.startswith(self.badBonePrefixes):
|
||||
if bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
|
||||
continue
|
||||
self.generate(context, ks, bone)
|
||||
ksi.generate(context, ks, bone)
|
||||
|
||||
# Poor man's subclassing. Blender breaks when we actually subclass BUILTIN_KSI_WholeCharacter.
|
||||
poll = BUILTIN_KSI_WholeCharacter.poll
|
||||
generate = BUILTIN_KSI_WholeCharacter.generate
|
||||
addProp = BUILTIN_KSI_WholeCharacter.addProp
|
||||
doLoc = BUILTIN_KSI_WholeCharacter.doLoc
|
||||
doRot4d = BUILTIN_KSI_WholeCharacter.doRot4d
|
||||
doRot3d = BUILTIN_KSI_WholeCharacter.doRot3d
|
||||
doScale = BUILTIN_KSI_WholeCharacter.doScale
|
||||
doBBone = BUILTIN_KSI_WholeCharacter.doBBone
|
||||
doCustomProps = BUILTIN_KSI_WholeCharacter.doCustomProps
|
||||
|
||||
###############################
|
||||
|
||||
@@ -582,7 +578,7 @@ class BUILTIN_KSI_DeltaLocation(KeyingSetInfo):
|
||||
iterator = keyingsets_utils.RKS_ITER_selected_objects
|
||||
|
||||
# generator - delta location channels only
|
||||
def generate(self, context, ks, data):
|
||||
def generate(ksi, context, ks, data):
|
||||
# get id-block and path info
|
||||
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
|
||||
|
||||
@@ -608,7 +604,7 @@ class BUILTIN_KSI_DeltaRotation(KeyingSetInfo):
|
||||
iterator = keyingsets_utils.RKS_ITER_selected_objects
|
||||
|
||||
# generator - delta location channels only
|
||||
def generate(self, context, ks, data):
|
||||
def generate(ksi, context, ks, data):
|
||||
# get id-block and path info
|
||||
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
|
||||
|
||||
@@ -642,7 +638,7 @@ class BUILTIN_KSI_DeltaScale(KeyingSetInfo):
|
||||
iterator = keyingsets_utils.RKS_ITER_selected_objects
|
||||
|
||||
# generator - delta location channels only
|
||||
def generate(self, context, ks, data):
|
||||
def generate(ksi, context, ks, data):
|
||||
# get id-block and path info
|
||||
id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
|
||||
|
||||
@@ -668,7 +664,6 @@ classes = (
|
||||
BUILTIN_KSI_Scaling,
|
||||
BUILTIN_KSI_LocRot,
|
||||
BUILTIN_KSI_LocRotScale,
|
||||
BUILTIN_KSI_LocRotScaleCProp,
|
||||
BUILTIN_KSI_LocScale,
|
||||
BUILTIN_KSI_RotScale,
|
||||
BUILTIN_KSI_DeltaLocation,
|
||||
|
@@ -550,7 +550,6 @@ geometry_node_categories = [
|
||||
NodeItem("ShaderNodeMath"),
|
||||
NodeItem("FunctionNodeBooleanMath"),
|
||||
NodeItem("FunctionNodeFloatCompare"),
|
||||
NodeItem("GeometryNodeSwitch"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_VECTOR", "Vector", items=[
|
||||
NodeItem("ShaderNodeSeparateXYZ"),
|
||||
|
@@ -41,7 +41,6 @@
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utf8.h"
|
||||
@@ -641,12 +640,18 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
|
||||
(size_t)buf_info->ch);
|
||||
float *fbuf = buf_info->fbuf + buf_ofs;
|
||||
|
||||
float font_pixel[4];
|
||||
font_pixel[0] = b_col_float[0] * a;
|
||||
font_pixel[1] = b_col_float[1] * a;
|
||||
font_pixel[2] = b_col_float[2] * a;
|
||||
font_pixel[3] = a;
|
||||
blend_color_mix_float(fbuf, fbuf, font_pixel);
|
||||
if (a >= 1.0f) {
|
||||
fbuf[0] = b_col_float[0];
|
||||
fbuf[1] = b_col_float[1];
|
||||
fbuf[2] = b_col_float[2];
|
||||
fbuf[3] = 1.0f;
|
||||
}
|
||||
else {
|
||||
fbuf[0] = (b_col_float[0] * a) + (fbuf[0] * (1.0f - a));
|
||||
fbuf[1] = (b_col_float[1] * a) + (fbuf[1] * (1.0f - a));
|
||||
fbuf[2] = (b_col_float[2] * a) + (fbuf[2] * (1.0f - a));
|
||||
fbuf[3] = MIN2(fbuf[3] + a, 1.0f); /* clamp to 1.0 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,12 +677,19 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
|
||||
(size_t)buf_info->ch);
|
||||
unsigned char *cbuf = buf_info->cbuf + buf_ofs;
|
||||
|
||||
uchar font_pixel[4];
|
||||
font_pixel[0] = b_col_char[0];
|
||||
font_pixel[1] = b_col_char[1];
|
||||
font_pixel[2] = b_col_char[2];
|
||||
font_pixel[3] = unit_float_to_uchar_clamp(a);
|
||||
blend_color_mix_byte(cbuf, cbuf, font_pixel);
|
||||
if (a >= 1.0f) {
|
||||
cbuf[0] = b_col_char[0];
|
||||
cbuf[1] = b_col_char[1];
|
||||
cbuf[2] = b_col_char[2];
|
||||
cbuf[3] = 255;
|
||||
}
|
||||
else {
|
||||
cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a)));
|
||||
cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a)));
|
||||
cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a)));
|
||||
/* clamp to 255 */
|
||||
cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255), 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "FN_cpp_type.hh"
|
||||
#include "FN_generic_span.hh"
|
||||
#include "FN_generic_virtual_array.hh"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
|
||||
@@ -31,10 +30,6 @@
|
||||
namespace blender::bke {
|
||||
|
||||
using fn::CPPType;
|
||||
using fn::GVArray;
|
||||
using fn::GVArrayPtr;
|
||||
using fn::GVMutableArray;
|
||||
using fn::GVMutableArrayPtr;
|
||||
|
||||
const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
|
||||
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
|
||||
@@ -42,97 +37,42 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
|
||||
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
|
||||
|
||||
/**
|
||||
* Used when looking up a "plain attribute" based on a name for reading from it.
|
||||
* This class offers an indirection for reading an attribute.
|
||||
* This is useful for the following reasons:
|
||||
* - Blender does not store all attributes the same way.
|
||||
* The simplest case are custom data layers with primitive types.
|
||||
* A bit more complex are mesh attributes like the position of vertices,
|
||||
* which are embedded into the MVert struct.
|
||||
* Even more complex to access are vertex weights.
|
||||
* - Sometimes attributes are stored on one domain, but we want to access
|
||||
* the attribute on a different domain. Therefore, we have to interpolate
|
||||
* between the domains.
|
||||
*/
|
||||
struct ReadAttributeLookup {
|
||||
/* The virtual array that is used to read from this attribute. */
|
||||
GVArrayPtr varray;
|
||||
/* Domain the attribute lives on in the geometry. */
|
||||
AttributeDomain domain;
|
||||
class ReadAttribute {
|
||||
protected:
|
||||
const AttributeDomain domain_;
|
||||
const CPPType &cpp_type_;
|
||||
const CustomDataType custom_data_type_;
|
||||
const int64_t size_;
|
||||
|
||||
/* Convenience function to check if the attribute has been found. */
|
||||
operator bool() const
|
||||
{
|
||||
return this->varray.get() != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used when looking up a "plain attribute" based on a name for reading from it and writing to it.
|
||||
*/
|
||||
struct WriteAttributeLookup {
|
||||
/* The virtual array that is used to read from and write to the attribute. */
|
||||
GVMutableArrayPtr varray;
|
||||
/* Domain the attributes lives on in the geometry. */
|
||||
AttributeDomain domain;
|
||||
|
||||
/* Convenience function to check if the attribute has been found. */
|
||||
operator bool() const
|
||||
{
|
||||
return this->varray.get() != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An output attribute allows writing to an attribute (and optionally reading as well). It adds
|
||||
* some convenience features on top of `GVMutableArray` that are very commonly used.
|
||||
*
|
||||
* Supported convenience features:
|
||||
* - Implicit type conversion when writing to builtin attributes.
|
||||
* - Supports simple access to a span containing the attribute values (that avoids the use of
|
||||
* VMutableArray_Span in many cases).
|
||||
* - An output attribute can live side by side with an existing attribute with a different domain
|
||||
* or data type. The old attribute will only be overwritten when the #save function is called.
|
||||
*/
|
||||
class OutputAttribute {
|
||||
public:
|
||||
using SaveFn = std::function<void(OutputAttribute &)>;
|
||||
|
||||
private:
|
||||
GVMutableArrayPtr varray_;
|
||||
AttributeDomain domain_;
|
||||
SaveFn save_;
|
||||
std::optional<fn::GVMutableArray_GSpan> optional_span_varray_;
|
||||
bool ignore_old_values_ = false;
|
||||
bool save_has_been_called_ = false;
|
||||
/* Protects the span below, so that no two threads initialize it at the same time. */
|
||||
mutable std::mutex span_mutex_;
|
||||
/* When it is not null, it points to the attribute array or a temporary array that contains all
|
||||
* the attribute values. */
|
||||
mutable void *array_buffer_ = nullptr;
|
||||
/* Is true when the buffer above is owned by the attribute accessor. */
|
||||
mutable bool array_is_temporary_ = false;
|
||||
|
||||
public:
|
||||
OutputAttribute() = default;
|
||||
|
||||
OutputAttribute(GVMutableArrayPtr varray,
|
||||
AttributeDomain domain,
|
||||
SaveFn save,
|
||||
const bool ignore_old_values)
|
||||
: varray_(std::move(varray)),
|
||||
domain_(domain),
|
||||
save_(std::move(save)),
|
||||
ignore_old_values_(ignore_old_values)
|
||||
ReadAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
|
||||
: domain_(domain),
|
||||
cpp_type_(cpp_type),
|
||||
custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
|
||||
size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
OutputAttribute(OutputAttribute &&other) = default;
|
||||
|
||||
~OutputAttribute();
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return varray_.get() != nullptr;
|
||||
}
|
||||
|
||||
GVMutableArray &operator*()
|
||||
{
|
||||
return *varray_;
|
||||
}
|
||||
|
||||
GVMutableArray *operator->()
|
||||
{
|
||||
return varray_.get();
|
||||
}
|
||||
|
||||
GVMutableArray &varray()
|
||||
{
|
||||
return *varray_;
|
||||
}
|
||||
virtual ~ReadAttribute();
|
||||
|
||||
AttributeDomain domain() const
|
||||
{
|
||||
@@ -141,94 +81,238 @@ class OutputAttribute {
|
||||
|
||||
const CPPType &cpp_type() const
|
||||
{
|
||||
return varray_->type();
|
||||
return cpp_type_;
|
||||
}
|
||||
|
||||
CustomDataType custom_data_type() const
|
||||
{
|
||||
return cpp_type_to_custom_data_type(this->cpp_type());
|
||||
return custom_data_type_;
|
||||
}
|
||||
|
||||
fn::GMutableSpan as_span()
|
||||
int64_t size() const
|
||||
{
|
||||
if (!optional_span_varray_.has_value()) {
|
||||
const bool materialize_old_values = !ignore_old_values_;
|
||||
optional_span_varray_.emplace(*varray_, materialize_old_values);
|
||||
}
|
||||
fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
|
||||
return span_varray;
|
||||
return size_;
|
||||
}
|
||||
|
||||
template<typename T> MutableSpan<T> as_span()
|
||||
void get(const int64_t index, void *r_value) const
|
||||
{
|
||||
return this->as_span().typed<T>();
|
||||
BLI_assert(index < size_);
|
||||
this->get_internal(index, r_value);
|
||||
}
|
||||
|
||||
void save();
|
||||
/* Get a span that contains all attribute values. */
|
||||
fn::GSpan get_span() const;
|
||||
|
||||
template<typename T> Span<T> get_span() const
|
||||
{
|
||||
return this->get_span().typed<T>();
|
||||
}
|
||||
|
||||
protected:
|
||||
/* r_value is expected to be uninitialized. */
|
||||
virtual void get_internal(const int64_t index, void *r_value) const = 0;
|
||||
|
||||
virtual void initialize_span() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as OutputAttribute, but should be used when the data type is known at compile time.
|
||||
* This exists for similar reasons as the ReadAttribute class, except that
|
||||
* it does not deal with interpolation between domains.
|
||||
*/
|
||||
template<typename T> class OutputAttribute_Typed {
|
||||
private:
|
||||
OutputAttribute attribute_;
|
||||
std::optional<fn::GVMutableArray_Typed<T>> optional_varray_;
|
||||
VMutableArray<T> *varray_ = nullptr;
|
||||
class WriteAttribute {
|
||||
protected:
|
||||
const AttributeDomain domain_;
|
||||
const CPPType &cpp_type_;
|
||||
const CustomDataType custom_data_type_;
|
||||
const int64_t size_;
|
||||
|
||||
/* When not null, this points either to the attribute array or to a temporary array. */
|
||||
void *array_buffer_ = nullptr;
|
||||
/* True, when the buffer points to a temporary array. */
|
||||
bool array_is_temporary_ = false;
|
||||
/* This helps to protect against forgetting to apply changes done to the array. */
|
||||
bool array_should_be_applied_ = false;
|
||||
|
||||
public:
|
||||
OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute))
|
||||
WriteAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
|
||||
: domain_(domain),
|
||||
cpp_type_(cpp_type),
|
||||
custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
|
||||
size_(size)
|
||||
{
|
||||
if (attribute_) {
|
||||
optional_varray_.emplace(attribute_.varray());
|
||||
varray_ = &**optional_varray_;
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return varray_ != nullptr;
|
||||
}
|
||||
|
||||
VMutableArray<T> &operator*()
|
||||
{
|
||||
return *varray_;
|
||||
}
|
||||
|
||||
VMutableArray<T> *operator->()
|
||||
{
|
||||
return varray_;
|
||||
}
|
||||
|
||||
VMutableArray<T> &varray()
|
||||
{
|
||||
return *varray_;
|
||||
}
|
||||
virtual ~WriteAttribute();
|
||||
|
||||
AttributeDomain domain() const
|
||||
{
|
||||
return attribute_.domain();
|
||||
return domain_;
|
||||
}
|
||||
|
||||
const CPPType &cpp_type() const
|
||||
{
|
||||
return CPPType::get<T>();
|
||||
return cpp_type_;
|
||||
}
|
||||
|
||||
CustomDataType custom_data_type() const
|
||||
{
|
||||
return cpp_type_to_custom_data_type(this->cpp_type());
|
||||
return custom_data_type_;
|
||||
}
|
||||
|
||||
MutableSpan<T> as_span()
|
||||
int64_t size() const
|
||||
{
|
||||
return attribute_.as_span<T>();
|
||||
return size_;
|
||||
}
|
||||
|
||||
void save()
|
||||
void get(const int64_t index, void *r_value) const
|
||||
{
|
||||
attribute_.save();
|
||||
BLI_assert(index < size_);
|
||||
this->get_internal(index, r_value);
|
||||
}
|
||||
|
||||
void set(const int64_t index, const void *value)
|
||||
{
|
||||
BLI_assert(index < size_);
|
||||
this->set_internal(index, value);
|
||||
}
|
||||
|
||||
/* Get a span that new attribute values can be written into. When all values have been changed,
|
||||
* #apply_span has to be called. */
|
||||
fn::GMutableSpan get_span();
|
||||
/* The span returned by this method might not contain the current attribute values. */
|
||||
fn::GMutableSpan get_span_for_write_only();
|
||||
/* Write the changes to the span into the actual attribute, if they aren't already. */
|
||||
void apply_span();
|
||||
|
||||
template<typename T> MutableSpan<T> get_span()
|
||||
{
|
||||
return this->get_span().typed<T>();
|
||||
}
|
||||
|
||||
template<typename T> MutableSpan<T> get_span_for_write_only()
|
||||
{
|
||||
return this->get_span_for_write_only().typed<T>();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void get_internal(const int64_t index, void *r_value) const = 0;
|
||||
virtual void set_internal(const int64_t index, const void *value) = 0;
|
||||
|
||||
virtual void initialize_span(const bool write_only);
|
||||
virtual void apply_span_if_necessary();
|
||||
};
|
||||
|
||||
using ReadAttributePtr = std::unique_ptr<ReadAttribute>;
|
||||
using WriteAttributePtr = std::unique_ptr<WriteAttribute>;
|
||||
|
||||
/* This provides type safe access to an attribute.
|
||||
* The underlying ReadAttribute is owned optionally. */
|
||||
template<typename T> class TypedReadAttribute {
|
||||
private:
|
||||
std::unique_ptr<const ReadAttribute> owned_attribute_;
|
||||
const ReadAttribute *attribute_;
|
||||
|
||||
public:
|
||||
TypedReadAttribute(ReadAttributePtr attribute) : TypedReadAttribute(*attribute)
|
||||
{
|
||||
owned_attribute_ = std::move(attribute);
|
||||
BLI_assert(owned_attribute_);
|
||||
}
|
||||
|
||||
TypedReadAttribute(const ReadAttribute &attribute) : attribute_(&attribute)
|
||||
{
|
||||
BLI_assert(attribute_->cpp_type().is<T>());
|
||||
}
|
||||
|
||||
int64_t size() const
|
||||
{
|
||||
return attribute_->size();
|
||||
}
|
||||
|
||||
T operator[](const int64_t index) const
|
||||
{
|
||||
BLI_assert(index < attribute_->size());
|
||||
T value;
|
||||
value.~T();
|
||||
attribute_->get(index, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Get a span to that contains all attribute values for faster and more convenient access. */
|
||||
Span<T> get_span() const
|
||||
{
|
||||
return attribute_->get_span().template typed<T>();
|
||||
}
|
||||
};
|
||||
|
||||
/* This provides type safe access to an attribute.
|
||||
* The underlying WriteAttribute is owned optionally. */
|
||||
template<typename T> class TypedWriteAttribute {
|
||||
private:
|
||||
std::unique_ptr<WriteAttribute> owned_attribute_;
|
||||
WriteAttribute *attribute_;
|
||||
|
||||
public:
|
||||
TypedWriteAttribute(WriteAttributePtr attribute) : TypedWriteAttribute(*attribute)
|
||||
{
|
||||
owned_attribute_ = std::move(attribute);
|
||||
BLI_assert(owned_attribute_);
|
||||
}
|
||||
|
||||
TypedWriteAttribute(WriteAttribute &attribute) : attribute_(&attribute)
|
||||
{
|
||||
BLI_assert(attribute_->cpp_type().is<T>());
|
||||
}
|
||||
|
||||
int64_t size() const
|
||||
{
|
||||
return attribute_->size();
|
||||
}
|
||||
|
||||
T operator[](const int64_t index) const
|
||||
{
|
||||
BLI_assert(index < attribute_->size());
|
||||
T value;
|
||||
value.~T();
|
||||
attribute_->get(index, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void set(const int64_t index, const T &value)
|
||||
{
|
||||
attribute_->set(index, &value);
|
||||
}
|
||||
|
||||
/* Get a span that new values can be written into. Once all values have been updated #apply_span
|
||||
* has to be called. */
|
||||
MutableSpan<T> get_span()
|
||||
{
|
||||
return attribute_->get_span().typed<T>();
|
||||
}
|
||||
/* The span returned by this method might not contain the current attribute values. */
|
||||
MutableSpan<T> get_span_for_write_only()
|
||||
{
|
||||
return attribute_->get_span_for_write_only().typed<T>();
|
||||
}
|
||||
|
||||
/* Write back all changes to the actual attribute, if necessary. */
|
||||
void apply_span()
|
||||
{
|
||||
attribute_->apply_span();
|
||||
}
|
||||
};
|
||||
|
||||
using BooleanReadAttribute = TypedReadAttribute<bool>;
|
||||
using FloatReadAttribute = TypedReadAttribute<float>;
|
||||
using Float2ReadAttribute = TypedReadAttribute<float2>;
|
||||
using Float3ReadAttribute = TypedReadAttribute<float3>;
|
||||
using Int32ReadAttribute = TypedReadAttribute<int>;
|
||||
using Color4fReadAttribute = TypedReadAttribute<Color4f>;
|
||||
using BooleanWriteAttribute = TypedWriteAttribute<bool>;
|
||||
using FloatWriteAttribute = TypedWriteAttribute<float>;
|
||||
using Float2WriteAttribute = TypedWriteAttribute<float2>;
|
||||
using Float3WriteAttribute = TypedWriteAttribute<float3>;
|
||||
using Int32WriteAttribute = TypedWriteAttribute<int>;
|
||||
using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;
|
||||
|
||||
} // namespace blender::bke
|
||||
|
@@ -21,17 +21,13 @@
|
||||
|
||||
#include "DNA_customdata_types.h"
|
||||
|
||||
#include "FN_cpp_type.hh"
|
||||
|
||||
namespace blender::attribute_math {
|
||||
|
||||
using fn::CPPType;
|
||||
|
||||
/**
|
||||
* Utility function that simplifies calling a templated function based on a custom data type.
|
||||
*/
|
||||
template<typename Func>
|
||||
inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
|
||||
void convert_to_static_type(const CustomDataType data_type, const Func &func)
|
||||
{
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT:
|
||||
@@ -58,32 +54,6 @@ inline void convert_to_static_type(const CustomDataType data_type, const Func &f
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func)
|
||||
{
|
||||
if (cpp_type.is<float>()) {
|
||||
func(float());
|
||||
}
|
||||
else if (cpp_type.is<float2>()) {
|
||||
func(float2());
|
||||
}
|
||||
else if (cpp_type.is<float3>()) {
|
||||
func(float3());
|
||||
}
|
||||
else if (cpp_type.is<int>()) {
|
||||
func(int());
|
||||
}
|
||||
else if (cpp_type.is<bool>()) {
|
||||
func(bool());
|
||||
}
|
||||
else if (cpp_type.is<Color4f>()) {
|
||||
func(Color4f());
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mix three values of the same type.
|
||||
*
|
||||
|
@@ -31,7 +31,7 @@ extern "C" {
|
||||
*/
|
||||
|
||||
/* Blender major and minor version. */
|
||||
#define BLENDER_VERSION 300
|
||||
#define BLENDER_VERSION 293
|
||||
/* Blender patch version for bugfix releases. */
|
||||
#define BLENDER_VERSION_PATCH 0
|
||||
/** Blender release cycle stage: alpha/beta/rc/release. */
|
||||
@@ -39,7 +39,7 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 0
|
||||
#define BLENDER_FILE_SUBVERSION 17
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
@@ -112,9 +112,7 @@ bool BKE_scene_collections_object_remove(struct Main *bmain,
|
||||
struct Object *object,
|
||||
const bool free_us);
|
||||
void BKE_collections_object_remove_nulls(struct Main *bmain);
|
||||
void BKE_collections_child_remove_nulls(struct Main *bmain,
|
||||
struct Collection *parent_collection,
|
||||
struct Collection *child_collection);
|
||||
void BKE_collections_child_remove_nulls(struct Main *bmain, struct Collection *old_collection);
|
||||
|
||||
/* Dependencies. */
|
||||
|
||||
|
@@ -206,25 +206,8 @@ void CTX_wm_area_set(bContext *C, struct ScrArea *area);
|
||||
void CTX_wm_region_set(bContext *C, struct ARegion *region);
|
||||
void CTX_wm_menu_set(bContext *C, struct ARegion *menu);
|
||||
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
|
||||
|
||||
/**
|
||||
* Values to create the message that describes the reason poll failed.
|
||||
*
|
||||
* \note This must be called in the same context as the poll function that created it.
|
||||
*/
|
||||
struct bContextPollMsgDyn_Params {
|
||||
/** The result is allocated . */
|
||||
char *(*get_fn)(bContext *C, void *user_data);
|
||||
/** Optionally free the user-data. */
|
||||
void (*free_fn)(bContext *C, void *user_data);
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
const char *CTX_wm_operator_poll_msg_get(struct bContext *C, bool *r_free);
|
||||
const char *CTX_wm_operator_poll_msg_get(struct bContext *C);
|
||||
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg);
|
||||
void CTX_wm_operator_poll_msg_set_dynamic(bContext *C,
|
||||
const struct bContextPollMsgDyn_Params *params);
|
||||
void CTX_wm_operator_poll_msg_clear(struct bContext *C);
|
||||
|
||||
/* Data Context
|
||||
*
|
||||
|
@@ -55,6 +55,60 @@ class ComponentAttributeProviders;
|
||||
|
||||
class GeometryComponent;
|
||||
|
||||
/**
|
||||
* An #OutputAttributePtr wraps a #WriteAttributePtr that might not be stored in its final
|
||||
* destination yet. Therefore, once the attribute has been filled with data, the #save method has
|
||||
* to be called, to store the attribute where it belongs (possibly by replacing an existing
|
||||
* attribute with the same name).
|
||||
*
|
||||
* This is useful for example in the Attribute Color Ramp node, when the same attribute name is
|
||||
* used as input and output. Typically the input is a float attribute, and the output is a color.
|
||||
* Those two attributes cannot exist at the same time, due to a name collision. To handle this
|
||||
* situation well, first the output colors have to be computed before the input floats are deleted.
|
||||
* Therefore, the outputs have to be written to a temporary buffer that replaces the existing
|
||||
* attribute once all computations are done.
|
||||
*/
|
||||
class OutputAttributePtr {
|
||||
private:
|
||||
blender::bke::WriteAttributePtr attribute_;
|
||||
|
||||
public:
|
||||
OutputAttributePtr() = default;
|
||||
OutputAttributePtr(blender::bke::WriteAttributePtr attribute);
|
||||
OutputAttributePtr(GeometryComponent &component,
|
||||
AttributeDomain domain,
|
||||
std::string name,
|
||||
CustomDataType data_type);
|
||||
|
||||
~OutputAttributePtr();
|
||||
|
||||
/* Returns false, when this wrapper is empty. */
|
||||
operator bool() const
|
||||
{
|
||||
return static_cast<bool>(attribute_);
|
||||
}
|
||||
|
||||
/* Get a reference to the underlying #WriteAttribute. */
|
||||
blender::bke::WriteAttribute &get()
|
||||
{
|
||||
BLI_assert(attribute_);
|
||||
return *attribute_;
|
||||
}
|
||||
|
||||
blender::bke::WriteAttribute &operator*()
|
||||
{
|
||||
return *attribute_;
|
||||
}
|
||||
|
||||
blender::bke::WriteAttribute *operator->()
|
||||
{
|
||||
return attribute_.get();
|
||||
}
|
||||
|
||||
void save();
|
||||
void apply_span_and_save();
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains information about an attribute in a geometry component.
|
||||
* More information can be added in the future. E.g. whether the attribute is builtin and how it is
|
||||
@@ -69,65 +123,6 @@ struct AttributeMetaData {
|
||||
using AttributeForeachCallback = blender::FunctionRef<bool(blender::StringRefNull attribute_name,
|
||||
const AttributeMetaData &meta_data)>;
|
||||
|
||||
/**
|
||||
* Base class for the attribute intializer types described below.
|
||||
*/
|
||||
struct AttributeInit {
|
||||
enum class Type {
|
||||
Default,
|
||||
VArray,
|
||||
MoveArray,
|
||||
};
|
||||
Type type;
|
||||
AttributeInit(const Type type) : type(type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an attribute using the default value for the data type.
|
||||
* The default values may depend on the attribute provider implementation.
|
||||
*/
|
||||
struct AttributeInitDefault : public AttributeInit {
|
||||
AttributeInitDefault() : AttributeInit(Type::Default)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an attribute by copying data from an existing virtual array. The virtual array
|
||||
* must have the same type as the newly created attribute.
|
||||
*
|
||||
* Note that this can be used to fill the new attribute with the default
|
||||
*/
|
||||
struct AttributeInitVArray : public AttributeInit {
|
||||
const blender::fn::GVArray *varray;
|
||||
|
||||
AttributeInitVArray(const blender::fn::GVArray *varray)
|
||||
: AttributeInit(Type::VArray), varray(varray)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an attribute with a by passing ownership of a pre-allocated contiguous array of data.
|
||||
* Sometimes data is created before a geometry component is available. In that case, it's
|
||||
* preferable to move data directly to the created attribute to avoid a new allocation and a copy.
|
||||
*
|
||||
* Note that this will only have a benefit for attributes that are stored directly as contigious
|
||||
* arrays, so not for some built-in attributes.
|
||||
*
|
||||
* The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it
|
||||
* can't be used directly, and that is generally how Blender expects custom data to be allocated.
|
||||
*/
|
||||
struct AttributeInitMove : public AttributeInit {
|
||||
void *data = nullptr;
|
||||
|
||||
AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the base class for specialized geometry component types.
|
||||
*/
|
||||
@@ -161,34 +156,26 @@ class GeometryComponent {
|
||||
/* Return true when any attribute with this name exists, including built in attributes. */
|
||||
bool attribute_exists(const blender::StringRef attribute_name) const;
|
||||
|
||||
/* Return the data type and domain of an attribute with the given name if it exists. */
|
||||
std::optional<AttributeMetaData> attribute_get_meta_data(
|
||||
const blender::StringRef attribute_name) const;
|
||||
|
||||
/* Returns true when the geometry component supports this attribute domain. */
|
||||
bool attribute_domain_supported(const AttributeDomain domain) const;
|
||||
/* Can only be used with supported domain types. */
|
||||
virtual int attribute_domain_size(const AttributeDomain domain) const;
|
||||
|
||||
bool attribute_is_builtin(const blender::StringRef attribute_name) const;
|
||||
|
||||
/* Get read-only access to the highest priority attribute with the given name.
|
||||
* Returns null if the attribute does not exist. */
|
||||
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
|
||||
blender::bke::ReadAttributePtr attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name) const;
|
||||
|
||||
/* Get read and write access to the highest priority attribute with the given name.
|
||||
* Returns null if the attribute does not exist. */
|
||||
blender::bke::WriteAttributeLookup attribute_try_get_for_write(
|
||||
blender::bke::WriteAttributePtr attribute_try_get_for_write(
|
||||
const blender::StringRef attribute_name);
|
||||
|
||||
/* Get a read-only attribute for the domain based on the given attribute. This can be used to
|
||||
* interpolate from one domain to another.
|
||||
* Returns null if the interpolation is not implemented. */
|
||||
virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
|
||||
std::unique_ptr<blender::fn::GVArray> varray,
|
||||
const AttributeDomain from_domain,
|
||||
const AttributeDomain to_domain) const;
|
||||
virtual blender::bke::ReadAttributePtr attribute_try_adapt_domain(
|
||||
blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const;
|
||||
|
||||
/* Returns true when the attribute has been deleted. */
|
||||
bool attribute_try_delete(const blender::StringRef attribute_name);
|
||||
@@ -196,104 +183,82 @@ class GeometryComponent {
|
||||
/* Returns true when the attribute has been created. */
|
||||
bool attribute_try_create(const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer);
|
||||
|
||||
/* Try to create the builtin attribute with the given name. No data type or domain has to be
|
||||
* provided, because those are fixed for builtin attributes. */
|
||||
bool attribute_try_create_builtin(const blender::StringRef attribute_name,
|
||||
const AttributeInit &initializer);
|
||||
const CustomDataType data_type);
|
||||
|
||||
blender::Set<std::string> attribute_names() const;
|
||||
bool attribute_foreach(const AttributeForeachCallback callback) const;
|
||||
|
||||
virtual bool is_empty() const;
|
||||
|
||||
/* Get a virtual array to read the data of an attribute on the given domain and data type.
|
||||
* Returns null when the attribute does not exist or cannot be converted to the requested domain
|
||||
* and data type. */
|
||||
std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
|
||||
/* Get a read-only attribute for the given domain and data type.
|
||||
* Returns null when it does not exist. */
|
||||
blender::bke::ReadAttributePtr attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type) const;
|
||||
|
||||
/* Get a virtual array to read the data of an attribute on the given domain. The data type is
|
||||
* left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
|
||||
* requested domain. */
|
||||
std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
|
||||
/* Get a read-only attribute interpolated to the input domain, leaving the data type unchanged.
|
||||
* Returns null when the attribute does not exist. */
|
||||
blender::bke::ReadAttributePtr attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name, const AttributeDomain domain) const;
|
||||
|
||||
/* Get a virtual array to read data of an attribute with the given data type. The domain is
|
||||
* left unchanged. Returns null when the attribute does not exist or cannot be converted to the
|
||||
* requested data type. */
|
||||
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name, const CustomDataType data_type) const;
|
||||
/* Get a read-only attribute for the given domain and data type.
|
||||
* Returns a constant attribute based on the default value if the attribute does not exist.
|
||||
* Never returns null. */
|
||||
blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value) const;
|
||||
|
||||
/* Get a virtual array to read the data of an attribute. If that is not possible, the returned
|
||||
* virtual array will contain a default value. This never returns null. */
|
||||
std::unique_ptr<blender::fn::GVArray> attribute_get_for_read(
|
||||
/* Get a typed read-only attribute for the given domain and type. */
|
||||
template<typename T>
|
||||
blender::bke::TypedReadAttribute<T> attribute_get_for_read(
|
||||
const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value = nullptr) const;
|
||||
|
||||
/* Should be used instead of the method above when the requested data type is known at compile
|
||||
* time for better type safety. */
|
||||
template<typename T>
|
||||
blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const T &default_value) const
|
||||
const T &default_value) const
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
std::unique_ptr varray = this->attribute_get_for_read(
|
||||
attribute_name, domain, type, &default_value);
|
||||
return blender::fn::GVArray_Typed<T>(std::move(varray));
|
||||
return this->attribute_get_for_read(attribute_name, domain, type, &default_value);
|
||||
}
|
||||
|
||||
/* Get a read-only dummy attribute that always returns the same value. */
|
||||
blender::bke::ReadAttributePtr attribute_get_constant_for_read(const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *value) const;
|
||||
|
||||
/* Create a read-only dummy attribute that always returns the same value.
|
||||
* The given value is converted to the correct type if necessary. */
|
||||
blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted(
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType in_data_type,
|
||||
const CustomDataType out_data_type,
|
||||
const void *value) const;
|
||||
|
||||
/* Get a read-only dummy attribute that always returns the same value. */
|
||||
template<typename T>
|
||||
blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain,
|
||||
const T &value) const
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
return this->attribute_get_constant_for_read(domain, type, &value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an "output attribute", which is essentially a mutable virtual array with some commonly
|
||||
* used convince features. The returned output attribute might be empty if requested attribute
|
||||
* cannot exist on the geometry.
|
||||
* If an attribute with the given params exist, it is returned.
|
||||
* If no attribute with the given name exists, create it and
|
||||
* fill it with the default value if it is provided.
|
||||
* If an attribute with the given name but different domain or type exists, a temporary attribute
|
||||
* is created that has to be saved after the output has been computed. This avoids deleting
|
||||
* another attribute, before a computation is finished.
|
||||
*
|
||||
* The included convenience features are:
|
||||
* - Implicit type conversion when writing to builtin attributes.
|
||||
* - If the attribute name exists already, but has a different type/domain, a temporary attribute
|
||||
* is created that will overwrite the existing attribute in the end.
|
||||
* This might return no attribute when the attribute cannot exist on the component.
|
||||
*/
|
||||
blender::bke::OutputAttribute attribute_try_get_for_output(
|
||||
const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value = nullptr);
|
||||
|
||||
/* Same as attribute_try_get_for_output, but should be used when the original values in the
|
||||
* attributes are not read, i.e. the attribute is used only for output. Since values are not read
|
||||
* from this attribute, no default value is necessary. */
|
||||
blender::bke::OutputAttribute attribute_try_get_for_output_only(
|
||||
const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type);
|
||||
|
||||
/* Statically typed method corresponding to the equally named generic one. */
|
||||
template<typename T>
|
||||
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
|
||||
const blender::StringRef attribute_name, const AttributeDomain domain, const T default_value)
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
return this->attribute_try_get_for_output(attribute_name, domain, data_type, &default_value);
|
||||
}
|
||||
|
||||
/* Statically typed method corresponding to the equally named generic one. */
|
||||
template<typename T>
|
||||
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
|
||||
const blender::StringRef attribute_name, const AttributeDomain domain)
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
return this->attribute_try_get_for_output_only(attribute_name, domain, data_type);
|
||||
}
|
||||
OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value = nullptr);
|
||||
|
||||
private:
|
||||
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
|
||||
@@ -412,10 +377,8 @@ class MeshComponent : public GeometryComponent {
|
||||
Mesh *get_for_write();
|
||||
|
||||
int attribute_domain_size(const AttributeDomain domain) const final;
|
||||
std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
|
||||
std::unique_ptr<blender::fn::GVArray> varray,
|
||||
const AttributeDomain from_domain,
|
||||
const AttributeDomain to_domain) const final;
|
||||
blender::bke::ReadAttributePtr attribute_try_adapt_domain(
|
||||
blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const final;
|
||||
|
||||
bool is_empty() const final;
|
||||
|
||||
|
@@ -325,7 +325,7 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
|
||||
{ \
|
||||
Object *_instance; \
|
||||
Base *_base; \
|
||||
for (_base = (Base *)(view_layer)->object_bases.first; _base; _base = _base->next) { \
|
||||
for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \
|
||||
_instance = _base->object;
|
||||
|
||||
#define FOREACH_OBJECT_END \
|
||||
|
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "FN_generic_virtual_array.hh"
|
||||
|
||||
#include "BLI_float3.hh"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
|
||||
struct Mesh;
|
||||
|
||||
namespace blender::bke::mesh_surface_sample {
|
||||
|
||||
using fn::CPPType;
|
||||
using fn::GMutableSpan;
|
||||
using fn::GSpan;
|
||||
using fn::GVArray;
|
||||
|
||||
void sample_point_attribute(const Mesh &mesh,
|
||||
Span<int> looptri_indices,
|
||||
Span<float3> bary_coords,
|
||||
const GVArray &data_in,
|
||||
GMutableSpan data_out);
|
||||
|
||||
void sample_corner_attribute(const Mesh &mesh,
|
||||
Span<int> looptri_indices,
|
||||
Span<float3> bary_coords,
|
||||
const GVArray &data_in,
|
||||
GMutableSpan data_out);
|
||||
|
||||
void sample_face_attribute(const Mesh &mesh,
|
||||
Span<int> looptri_indices,
|
||||
const GVArray &data_in,
|
||||
GMutableSpan data_out);
|
||||
|
||||
} // namespace blender::bke::mesh_surface_sample
|
@@ -1413,7 +1413,6 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
||||
#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040
|
||||
#define GEO_NODE_ATTRIBUTE_CLAMP 1041
|
||||
#define GEO_NODE_BOUNDING_BOX 1042
|
||||
#define GEO_NODE_SWITCH 1043
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@@ -152,7 +152,6 @@ void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bma
|
||||
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain);
|
||||
|
||||
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph);
|
||||
void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, const bool clear_recalc);
|
||||
|
||||
void BKE_scene_view_layer_graph_evaluated_ensure(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
|
@@ -190,7 +190,6 @@ set(SRC
|
||||
intern/mesh_remap.c
|
||||
intern/mesh_remesh_voxel.c
|
||||
intern/mesh_runtime.c
|
||||
intern/mesh_sample.cc
|
||||
intern/mesh_tangent.c
|
||||
intern/mesh_validate.c
|
||||
intern/mesh_validate.cc
|
||||
@@ -380,7 +379,6 @@ set(SRC
|
||||
BKE_mesh_remap.h
|
||||
BKE_mesh_remesh_voxel.h
|
||||
BKE_mesh_runtime.h
|
||||
BKE_mesh_sample.hh
|
||||
BKE_mesh_tangent.h
|
||||
BKE_mesh_types.h
|
||||
BKE_mesh_wrapper.h
|
||||
|
@@ -137,7 +137,7 @@ static char *blender_version_decimal(const int version)
|
||||
{
|
||||
static char version_str[5];
|
||||
BLI_assert(version < 1000);
|
||||
BLI_snprintf(version_str, sizeof(version_str), "%d.%d", version / 100, version % 100);
|
||||
BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", version / 100, version % 100);
|
||||
return version_str;
|
||||
}
|
||||
|
||||
|
@@ -44,10 +44,194 @@ using blender::float3;
|
||||
using blender::Set;
|
||||
using blender::StringRef;
|
||||
using blender::StringRefNull;
|
||||
using blender::bke::ReadAttributePtr;
|
||||
using blender::bke::WriteAttributePtr;
|
||||
using blender::fn::GMutableSpan;
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Attribute Accessor implementations
|
||||
* \{ */
|
||||
|
||||
ReadAttribute::~ReadAttribute()
|
||||
{
|
||||
if (array_is_temporary_ && array_buffer_ != nullptr) {
|
||||
cpp_type_.destruct_n(array_buffer_, size_);
|
||||
MEM_freeN(array_buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
fn::GSpan ReadAttribute::get_span() const
|
||||
{
|
||||
if (size_ == 0) {
|
||||
return fn::GSpan(cpp_type_);
|
||||
}
|
||||
if (array_buffer_ == nullptr) {
|
||||
std::lock_guard lock{span_mutex_};
|
||||
if (array_buffer_ == nullptr) {
|
||||
this->initialize_span();
|
||||
}
|
||||
}
|
||||
return fn::GSpan(cpp_type_, array_buffer_, size_);
|
||||
}
|
||||
|
||||
void ReadAttribute::initialize_span() const
|
||||
{
|
||||
const int element_size = cpp_type_.size();
|
||||
array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
|
||||
array_is_temporary_ = true;
|
||||
for (const int i : IndexRange(size_)) {
|
||||
this->get_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
|
||||
}
|
||||
}
|
||||
|
||||
WriteAttribute::~WriteAttribute()
|
||||
{
|
||||
if (array_should_be_applied_) {
|
||||
CLOG_ERROR(&LOG, "Forgot to call apply_span.");
|
||||
}
|
||||
if (array_is_temporary_ && array_buffer_ != nullptr) {
|
||||
cpp_type_.destruct_n(array_buffer_, size_);
|
||||
MEM_freeN(array_buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mutable span that can be modified. When all modifications to the attribute are done,
|
||||
* #apply_span should be called. */
|
||||
fn::GMutableSpan WriteAttribute::get_span()
|
||||
{
|
||||
if (size_ == 0) {
|
||||
return fn::GMutableSpan(cpp_type_);
|
||||
}
|
||||
if (array_buffer_ == nullptr) {
|
||||
this->initialize_span(false);
|
||||
}
|
||||
array_should_be_applied_ = true;
|
||||
return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
|
||||
}
|
||||
|
||||
fn::GMutableSpan WriteAttribute::get_span_for_write_only()
|
||||
{
|
||||
if (size_ == 0) {
|
||||
return fn::GMutableSpan(cpp_type_);
|
||||
}
|
||||
if (array_buffer_ == nullptr) {
|
||||
this->initialize_span(true);
|
||||
}
|
||||
array_should_be_applied_ = true;
|
||||
return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
|
||||
}
|
||||
|
||||
void WriteAttribute::initialize_span(const bool write_only)
|
||||
{
|
||||
const int element_size = cpp_type_.size();
|
||||
array_buffer_ = MEM_mallocN_aligned(element_size * size_, cpp_type_.alignment(), __func__);
|
||||
array_is_temporary_ = true;
|
||||
if (write_only) {
|
||||
/* This does nothing for trivial types, but is necessary for general correctness. */
|
||||
cpp_type_.construct_default_n(array_buffer_, size_);
|
||||
}
|
||||
else {
|
||||
for (const int i : IndexRange(size_)) {
|
||||
this->get(i, POINTER_OFFSET(array_buffer_, i * element_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteAttribute::apply_span()
|
||||
{
|
||||
this->apply_span_if_necessary();
|
||||
array_should_be_applied_ = false;
|
||||
}
|
||||
|
||||
void WriteAttribute::apply_span_if_necessary()
|
||||
{
|
||||
/* Only works when the span has been initialized beforehand. */
|
||||
BLI_assert(array_buffer_ != nullptr);
|
||||
|
||||
const int element_size = cpp_type_.size();
|
||||
for (const int i : IndexRange(size_)) {
|
||||
this->set_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
|
||||
}
|
||||
}
|
||||
|
||||
/* This is used by the #OutputAttributePtr class. */
|
||||
class TemporaryWriteAttribute final : public WriteAttribute {
|
||||
public:
|
||||
GMutableSpan data;
|
||||
GeometryComponent &component;
|
||||
std::string final_name;
|
||||
|
||||
TemporaryWriteAttribute(AttributeDomain domain,
|
||||
GMutableSpan data,
|
||||
GeometryComponent &component,
|
||||
std::string final_name)
|
||||
: WriteAttribute(domain, data.type(), data.size()),
|
||||
data(data),
|
||||
component(component),
|
||||
final_name(std::move(final_name))
|
||||
{
|
||||
}
|
||||
|
||||
~TemporaryWriteAttribute() override
|
||||
{
|
||||
if (data.data() != nullptr) {
|
||||
cpp_type_.destruct_n(data.data(), data.size());
|
||||
MEM_freeN(data.data());
|
||||
}
|
||||
}
|
||||
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
data.type().copy_to_uninitialized(data[index], r_value);
|
||||
}
|
||||
|
||||
void set_internal(const int64_t index, const void *value) override
|
||||
{
|
||||
data.type().copy_to_initialized(value, data[index]);
|
||||
}
|
||||
|
||||
void initialize_span(const bool UNUSED(write_only)) override
|
||||
{
|
||||
array_buffer_ = data.data();
|
||||
array_is_temporary_ = false;
|
||||
}
|
||||
|
||||
void apply_span_if_necessary() override
|
||||
{
|
||||
/* Do nothing, because the span contains the attribute itself already. */
|
||||
}
|
||||
};
|
||||
|
||||
class ConvertedReadAttribute final : public ReadAttribute {
|
||||
private:
|
||||
const CPPType &from_type_;
|
||||
const CPPType &to_type_;
|
||||
ReadAttributePtr base_attribute_;
|
||||
const nodes::DataTypeConversions &conversions_;
|
||||
|
||||
public:
|
||||
ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
|
||||
: ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
|
||||
from_type_(base_attribute->cpp_type()),
|
||||
to_type_(to_type),
|
||||
base_attribute_(std::move(base_attribute)),
|
||||
conversions_(nodes::get_implicit_type_conversions())
|
||||
{
|
||||
}
|
||||
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
|
||||
base_attribute_->get(index, buffer);
|
||||
conversions_.convert(from_type_, to_type_, buffer, r_value);
|
||||
}
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -182,27 +366,7 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
|
||||
return highest_priority_domain;
|
||||
}
|
||||
|
||||
void OutputAttribute::save()
|
||||
{
|
||||
save_has_been_called_ = true;
|
||||
if (optional_span_varray_.has_value()) {
|
||||
optional_span_varray_->save();
|
||||
}
|
||||
if (save_) {
|
||||
save_(*this);
|
||||
}
|
||||
}
|
||||
|
||||
OutputAttribute::~OutputAttribute()
|
||||
{
|
||||
if (!save_has_been_called_) {
|
||||
if (varray_) {
|
||||
std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read(
|
||||
ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
|
||||
const GeometryComponent &component) const
|
||||
{
|
||||
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
|
||||
@@ -218,7 +382,7 @@ GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read(
|
||||
return as_read_attribute_(data, domain_size);
|
||||
}
|
||||
|
||||
GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write(
|
||||
WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write(
|
||||
GeometryComponent &component) const
|
||||
{
|
||||
if (writable_ != Writable) {
|
||||
@@ -264,43 +428,7 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
|
||||
return delete_success;
|
||||
}
|
||||
|
||||
static bool add_custom_data_layer_from_attribute_init(CustomData &custom_data,
|
||||
const CustomDataType data_type,
|
||||
const int domain_size,
|
||||
const AttributeInit &initializer)
|
||||
{
|
||||
switch (initializer.type) {
|
||||
case AttributeInit::Type::Default: {
|
||||
void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
|
||||
return data != nullptr;
|
||||
}
|
||||
case AttributeInit::Type::VArray: {
|
||||
void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size);
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
|
||||
varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
|
||||
return true;
|
||||
}
|
||||
case AttributeInit::Type::MoveArray: {
|
||||
void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
|
||||
void *data = CustomData_add_layer(
|
||||
&custom_data, data_type, CD_ASSIGN, source_data, domain_size);
|
||||
if (data == nullptr) {
|
||||
MEM_freeN(source_data);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
|
||||
const AttributeInit &initializer) const
|
||||
bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const
|
||||
{
|
||||
if (createable_ != Creatable) {
|
||||
return false;
|
||||
@@ -313,10 +441,10 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
|
||||
/* Exists already. */
|
||||
return false;
|
||||
}
|
||||
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
const bool success = add_custom_data_layer_from_attribute_init(
|
||||
*custom_data, stored_type_, domain_size, initializer);
|
||||
const void *data = CustomData_add_layer(
|
||||
custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size);
|
||||
const bool success = data != nullptr;
|
||||
if (success) {
|
||||
custom_data_access_.update_custom_data_pointers(component);
|
||||
}
|
||||
@@ -333,7 +461,7 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
|
||||
return data != nullptr;
|
||||
}
|
||||
|
||||
ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
|
||||
ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
|
||||
const GeometryComponent &component, const StringRef attribute_name) const
|
||||
{
|
||||
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
|
||||
@@ -366,7 +494,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
|
||||
return {};
|
||||
}
|
||||
|
||||
WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
|
||||
WriteAttributePtr CustomDataAttributeProvider::try_get_for_write(
|
||||
GeometryComponent &component, const StringRef attribute_name) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(component);
|
||||
@@ -418,52 +546,10 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool add_named_custom_data_layer_from_attribute_init(const StringRef attribute_name,
|
||||
CustomData &custom_data,
|
||||
const CustomDataType data_type,
|
||||
const int domain_size,
|
||||
const AttributeInit &initializer)
|
||||
{
|
||||
char attribute_name_c[MAX_NAME];
|
||||
attribute_name.copy(attribute_name_c);
|
||||
|
||||
switch (initializer.type) {
|
||||
case AttributeInit::Type::Default: {
|
||||
void *data = CustomData_add_layer_named(
|
||||
&custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
|
||||
return data != nullptr;
|
||||
}
|
||||
case AttributeInit::Type::VArray: {
|
||||
void *data = CustomData_add_layer_named(
|
||||
&custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
|
||||
varray->materialize_to_uninitialized(IndexRange(varray->size()), data);
|
||||
return true;
|
||||
}
|
||||
case AttributeInit::Type::MoveArray: {
|
||||
void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
|
||||
void *data = CustomData_add_layer_named(
|
||||
&custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_name_c);
|
||||
if (data == nullptr) {
|
||||
MEM_freeN(source_data);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
|
||||
const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer) const
|
||||
const CustomDataType data_type) const
|
||||
{
|
||||
if (domain_ != domain) {
|
||||
return false;
|
||||
@@ -481,8 +567,10 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
|
||||
}
|
||||
}
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
add_named_custom_data_layer_from_attribute_init(
|
||||
attribute_name, *custom_data, data_type, domain_size, initializer);
|
||||
char attribute_name_c[MAX_NAME];
|
||||
attribute_name.copy(attribute_name_c);
|
||||
CustomData_add_layer_named(
|
||||
custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -505,7 +593,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
|
||||
return true;
|
||||
}
|
||||
|
||||
ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
|
||||
ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
|
||||
const GeometryComponent &component, const StringRef attribute_name) const
|
||||
{
|
||||
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
|
||||
@@ -516,14 +604,14 @@ ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
|
||||
if (layer.type == stored_type_) {
|
||||
if (layer.name == attribute_name) {
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
return {as_read_attribute_(layer.data, domain_size), domain_};
|
||||
return as_read_attribute_(layer.data, domain_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
|
||||
WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
|
||||
GeometryComponent &component, const StringRef attribute_name) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(component);
|
||||
@@ -540,7 +628,7 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
|
||||
if (data_old != data_new) {
|
||||
custom_data_access_.update_custom_data_pointers(component);
|
||||
}
|
||||
return {as_write_attribute_(layer.data, domain_size), domain_};
|
||||
return as_write_attribute_(layer.data, domain_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -618,17 +706,7 @@ int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_name) const
|
||||
{
|
||||
using namespace blender::bke;
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
if (providers == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return providers->builtin_attribute_providers().contains_as(attribute_name);
|
||||
}
|
||||
|
||||
blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
|
||||
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
|
||||
const StringRef attribute_name) const
|
||||
{
|
||||
using namespace blender::bke;
|
||||
@@ -639,11 +717,11 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()};
|
||||
return builtin_provider->try_get_for_read(*this);
|
||||
}
|
||||
for (const DynamicAttributesProvider *dynamic_provider :
|
||||
providers->dynamic_attribute_providers()) {
|
||||
ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
|
||||
ReadAttributePtr attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
|
||||
if (attribute) {
|
||||
return attribute;
|
||||
}
|
||||
@@ -651,19 +729,16 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain(
|
||||
std::unique_ptr<blender::fn::GVArray> varray,
|
||||
const AttributeDomain from_domain,
|
||||
const AttributeDomain to_domain) const
|
||||
ReadAttributePtr GeometryComponent::attribute_try_adapt_domain(
|
||||
ReadAttributePtr attribute, const AttributeDomain new_domain) const
|
||||
{
|
||||
if (from_domain == to_domain) {
|
||||
return varray;
|
||||
if (attribute && attribute->domain() == new_domain) {
|
||||
return attribute;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write(
|
||||
const StringRef attribute_name)
|
||||
WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef attribute_name)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
@@ -673,11 +748,11 @@ blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_writ
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
|
||||
return builtin_provider->try_get_for_write(*this);
|
||||
}
|
||||
for (const DynamicAttributesProvider *dynamic_provider :
|
||||
providers->dynamic_attribute_providers()) {
|
||||
WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
|
||||
WriteAttributePtr attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
|
||||
if (attribute) {
|
||||
return attribute;
|
||||
}
|
||||
@@ -707,8 +782,7 @@ bool GeometryComponent::attribute_try_delete(const StringRef attribute_name)
|
||||
|
||||
bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer)
|
||||
const CustomDataType data_type)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
if (attribute_name.is_empty()) {
|
||||
@@ -727,36 +801,17 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
|
||||
if (builtin_provider->data_type() != data_type) {
|
||||
return false;
|
||||
}
|
||||
return builtin_provider->try_create(*this, initializer);
|
||||
return builtin_provider->try_create(*this);
|
||||
}
|
||||
for (const DynamicAttributesProvider *dynamic_provider :
|
||||
providers->dynamic_attribute_providers()) {
|
||||
if (dynamic_provider->try_create(*this, attribute_name, domain, data_type, initializer)) {
|
||||
if (dynamic_provider->try_create(*this, attribute_name, domain, data_type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name,
|
||||
const AttributeInit &initializer)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
if (attribute_name.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
if (providers == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
|
||||
if (builtin_provider == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return builtin_provider->try_create(*this, initializer);
|
||||
}
|
||||
|
||||
Set<std::string> GeometryComponent::attribute_names() const
|
||||
{
|
||||
Set<std::string> attributes;
|
||||
@@ -810,283 +865,264 @@ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
|
||||
|
||||
bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
|
||||
{
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
if (attribute) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
|
||||
const StringRef attribute_name) const
|
||||
static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute,
|
||||
const blender::fn::CPPType &to_type)
|
||||
{
|
||||
std::optional<AttributeMetaData> result{std::nullopt};
|
||||
this->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (attribute_name == name) {
|
||||
result = meta_data;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
const blender::fn::CPPType &from_type = attribute->cpp_type();
|
||||
if (from_type == to_type) {
|
||||
return attribute;
|
||||
}
|
||||
|
||||
static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type(
|
||||
std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type)
|
||||
{
|
||||
const blender::nodes::DataTypeConversions &conversions =
|
||||
blender::nodes::get_implicit_type_conversions();
|
||||
return conversions.try_convert(std::move(varray), to_type);
|
||||
if (!conversions.is_convertible(from_type, to_type)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::make_unique<blender::bke::ConvertedReadAttribute>(std::move(attribute), to_type);
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read(
|
||||
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
|
||||
const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type) const
|
||||
{
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray);
|
||||
if (domain != ATTR_DOMAIN_AUTO && attribute.domain != domain) {
|
||||
varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain);
|
||||
if (!varray) {
|
||||
if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) {
|
||||
attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
if (varray->type() != *cpp_type) {
|
||||
varray = try_adapt_data_type(std::move(varray), *cpp_type);
|
||||
if (!varray) {
|
||||
if (attribute->cpp_type() != *cpp_type) {
|
||||
attribute = try_adapt_data_type(std::move(attribute), *cpp_type);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return varray;
|
||||
return attribute;
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read(
|
||||
const StringRef attribute_name, const AttributeDomain domain) const
|
||||
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(const StringRef attribute_name,
|
||||
const AttributeDomain domain) const
|
||||
{
|
||||
if (!this->attribute_domain_supported(domain)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (attribute.domain != domain) {
|
||||
return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain);
|
||||
if (attribute->domain() != domain) {
|
||||
attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(attribute.varray);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name, const CustomDataType data_type) const
|
||||
ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value) const
|
||||
{
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
BLI_assert(type != nullptr);
|
||||
if (attribute.varray->type() == *type) {
|
||||
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type);
|
||||
if (attribute) {
|
||||
return attribute;
|
||||
}
|
||||
const blender::nodes::DataTypeConversions &conversions =
|
||||
blender::nodes::get_implicit_type_conversions();
|
||||
return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
|
||||
return this->attribute_get_constant_for_read(domain, data_type, default_value);
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read(
|
||||
const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value) const
|
||||
blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read(
|
||||
const AttributeDomain domain, const CustomDataType data_type, const void *value) const
|
||||
{
|
||||
std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read(
|
||||
attribute_name, domain, data_type);
|
||||
if (varray) {
|
||||
return varray;
|
||||
}
|
||||
const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
if (default_value == nullptr) {
|
||||
default_value = type->default_value();
|
||||
BLI_assert(this->attribute_domain_supported(domain));
|
||||
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
if (value == nullptr) {
|
||||
value = cpp_type->default_value();
|
||||
}
|
||||
const int domain_size = this->attribute_domain_size(domain);
|
||||
return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value);
|
||||
return std::make_unique<blender::bke::ConstantReadAttribute>(
|
||||
domain, domain_size, *cpp_type, value);
|
||||
}
|
||||
|
||||
class GVMutableAttribute_For_OutputAttribute
|
||||
: public blender::fn::GVMutableArray_For_GMutableSpan {
|
||||
public:
|
||||
GeometryComponent *component;
|
||||
std::string final_name;
|
||||
|
||||
GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
|
||||
GeometryComponent &component,
|
||||
std::string final_name)
|
||||
: blender::fn::GVMutableArray_For_GMutableSpan(data),
|
||||
component(&component),
|
||||
final_name(std::move(final_name))
|
||||
{
|
||||
}
|
||||
|
||||
~GVMutableAttribute_For_OutputAttribute() override
|
||||
{
|
||||
type_->destruct_n(data_, size_);
|
||||
MEM_freeN(data_);
|
||||
}
|
||||
};
|
||||
|
||||
static void save_output_attribute(blender::bke::OutputAttribute &output_attribute)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::fn;
|
||||
using namespace blender::bke;
|
||||
|
||||
GVMutableAttribute_For_OutputAttribute &varray =
|
||||
dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray());
|
||||
|
||||
GeometryComponent &component = *varray.component;
|
||||
const StringRefNull name = varray.final_name;
|
||||
const AttributeDomain domain = output_attribute.domain();
|
||||
const CustomDataType data_type = output_attribute.custom_data_type();
|
||||
const CPPType &cpp_type = output_attribute.cpp_type();
|
||||
|
||||
component.attribute_try_delete(name);
|
||||
if (!component.attribute_try_create(
|
||||
varray.final_name, domain, data_type, AttributeInitDefault())) {
|
||||
CLOG_WARN(&LOG,
|
||||
"Could not create the '%s' attribute with type '%s'.",
|
||||
name.c_str(),
|
||||
cpp_type.name().c_str());
|
||||
return;
|
||||
}
|
||||
WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name);
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer);
|
||||
for (const int i : IndexRange(varray.size())) {
|
||||
varray.get(i, buffer);
|
||||
write_attribute.varray->set_by_relocate(i, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static blender::bke::OutputAttribute create_output_attribute(
|
||||
GeometryComponent &component,
|
||||
const blender::StringRef attribute_name,
|
||||
blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read_converted(
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const bool ignore_old_values,
|
||||
const void *default_value)
|
||||
const CustomDataType in_data_type,
|
||||
const CustomDataType out_data_type,
|
||||
const void *value) const
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::fn;
|
||||
using namespace blender::bke;
|
||||
|
||||
if (attribute_name.is_empty()) {
|
||||
return {};
|
||||
BLI_assert(this->attribute_domain_supported(domain));
|
||||
if (value == nullptr || in_data_type == out_data_type) {
|
||||
return this->attribute_get_constant_for_read(domain, out_data_type, value);
|
||||
}
|
||||
|
||||
const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
|
||||
const blender::fn::CPPType *in_cpp_type = blender::bke::custom_data_type_to_cpp_type(
|
||||
in_data_type);
|
||||
const blender::fn::CPPType *out_cpp_type = blender::bke::custom_data_type_to_cpp_type(
|
||||
out_data_type);
|
||||
BLI_assert(in_cpp_type != nullptr);
|
||||
BLI_assert(out_cpp_type != nullptr);
|
||||
|
||||
const blender::nodes::DataTypeConversions &conversions =
|
||||
blender::nodes::get_implicit_type_conversions();
|
||||
BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type));
|
||||
|
||||
void *out_value = alloca(out_cpp_type->size());
|
||||
conversions.convert(*in_cpp_type, *out_cpp_type, value, out_value);
|
||||
|
||||
const int domain_size = this->attribute_domain_size(domain);
|
||||
blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>(
|
||||
domain, domain_size, *out_cpp_type, out_value);
|
||||
|
||||
out_cpp_type->destruct(out_value);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value)
|
||||
{
|
||||
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
|
||||
|
||||
if (component.attribute_is_builtin(attribute_name)) {
|
||||
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
|
||||
if (!attribute) {
|
||||
if (default_value) {
|
||||
const int64_t domain_size = component.attribute_domain_size(domain);
|
||||
const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value};
|
||||
component.attribute_try_create_builtin(attribute_name,
|
||||
AttributeInitVArray(&default_varray));
|
||||
}
|
||||
else {
|
||||
component.attribute_try_create_builtin(attribute_name, AttributeInitDefault());
|
||||
}
|
||||
attribute = component.attribute_try_get_for_write(attribute_name);
|
||||
if (!attribute) {
|
||||
/* Builtin attribute does not exist and can't be created. */
|
||||
return {};
|
||||
}
|
||||
WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name);
|
||||
|
||||
/* If the attribute doesn't exist, make a new one with the correct type. */
|
||||
if (!attribute) {
|
||||
this->attribute_try_create(attribute_name, domain, data_type);
|
||||
attribute = this->attribute_try_get_for_write(attribute_name);
|
||||
if (attribute && default_value != nullptr) {
|
||||
void *data = attribute->get_span_for_write_only().data();
|
||||
cpp_type->fill_initialized(default_value, data, attribute->size());
|
||||
attribute->apply_span();
|
||||
}
|
||||
if (attribute.domain != domain) {
|
||||
/* Builtin attribute is on different domain. */
|
||||
return {};
|
||||
}
|
||||
GVMutableArrayPtr varray = std::move(attribute.varray);
|
||||
if (varray->type() == *cpp_type) {
|
||||
/* Builtin attribute matches exactly. */
|
||||
return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
|
||||
}
|
||||
/* Builtin attribute is on the same domain but has a different data type. */
|
||||
varray = conversions.try_convert(std::move(varray), *cpp_type);
|
||||
return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
|
||||
return OutputAttributePtr(std::move(attribute));
|
||||
}
|
||||
|
||||
/* If an existing attribute has a matching domain and type, just use that. */
|
||||
if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
|
||||
return OutputAttributePtr(std::move(attribute));
|
||||
}
|
||||
|
||||
/* Otherwise create a temporary buffer to use before saving the new attribute. */
|
||||
return OutputAttributePtr(*this, domain, attribute_name, data_type);
|
||||
}
|
||||
|
||||
/* Construct from an attribute that already exists in the geometry component. */
|
||||
OutputAttributePtr::OutputAttributePtr(WriteAttributePtr attribute)
|
||||
: attribute_(std::move(attribute))
|
||||
{
|
||||
}
|
||||
|
||||
/* Construct a temporary attribute that has to replace an existing one later on. */
|
||||
OutputAttributePtr::OutputAttributePtr(GeometryComponent &component,
|
||||
AttributeDomain domain,
|
||||
std::string final_name,
|
||||
CustomDataType data_type)
|
||||
{
|
||||
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
|
||||
const int domain_size = component.attribute_domain_size(domain);
|
||||
void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__);
|
||||
GMutableSpan new_span{*cpp_type, buffer, domain_size};
|
||||
|
||||
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
|
||||
if (!attribute) {
|
||||
if (default_value) {
|
||||
const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value};
|
||||
component.attribute_try_create(
|
||||
attribute_name, domain, data_type, AttributeInitVArray(&default_varray));
|
||||
}
|
||||
else {
|
||||
component.attribute_try_create(attribute_name, domain, data_type, AttributeInitDefault());
|
||||
}
|
||||
|
||||
attribute = component.attribute_try_get_for_write(attribute_name);
|
||||
if (!attribute) {
|
||||
/* Can't create the attribute. */
|
||||
return {};
|
||||
}
|
||||
}
|
||||
if (attribute.domain == domain && attribute.varray->type() == *cpp_type) {
|
||||
/* Existing generic attribute matches exactly. */
|
||||
return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values);
|
||||
/* Copy converted values from conflicting attribute, in case the value is read.
|
||||
* TODO: An optimization could be to not do this, when the caller says that the attribute will
|
||||
* only be written. */
|
||||
ReadAttributePtr src_attribute = component.attribute_get_for_read(
|
||||
final_name, domain, data_type, nullptr);
|
||||
for (const int i : blender::IndexRange(domain_size)) {
|
||||
src_attribute->get(i, new_span[i]);
|
||||
}
|
||||
|
||||
/* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
|
||||
* attribute after processing is done. */
|
||||
void *data = MEM_mallocN_aligned(
|
||||
cpp_type->size() * domain_size, cpp_type->alignment(), __func__);
|
||||
if (ignore_old_values) {
|
||||
/* This does nothing for trivially constructible types, but is necessary for correctness. */
|
||||
cpp_type->construct_default_n(data, domain);
|
||||
}
|
||||
else {
|
||||
/* Fill the temporary array with values from the existing attribute. */
|
||||
GVArrayPtr old_varray = component.attribute_get_for_read(
|
||||
attribute_name, domain, data_type, default_value);
|
||||
old_varray->materialize_to_uninitialized(IndexRange(domain_size), data);
|
||||
}
|
||||
GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>(
|
||||
GMutableSpan{*cpp_type, data, domain_size}, component, attribute_name);
|
||||
|
||||
return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
|
||||
attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>(
|
||||
domain, new_span, component, std::move(final_name));
|
||||
}
|
||||
|
||||
blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output(
|
||||
const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value)
|
||||
/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This
|
||||
* might delete another attribute with the same name. */
|
||||
void OutputAttributePtr::save()
|
||||
{
|
||||
return create_output_attribute(*this, attribute_name, domain, data_type, false, default_value);
|
||||
if (!attribute_) {
|
||||
CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore.");
|
||||
return;
|
||||
}
|
||||
|
||||
blender::bke::TemporaryWriteAttribute *attribute =
|
||||
dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get());
|
||||
|
||||
if (attribute == nullptr) {
|
||||
/* The attribute is saved already. */
|
||||
attribute_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
StringRefNull name = attribute->final_name;
|
||||
const blender::fn::CPPType &cpp_type = attribute->cpp_type();
|
||||
|
||||
/* Delete an existing attribute with the same name if necessary. */
|
||||
attribute->component.attribute_try_delete(name);
|
||||
|
||||
if (!attribute->component.attribute_try_create(
|
||||
name, attribute_->domain(), attribute_->custom_data_type())) {
|
||||
/* Cannot create the target attribute for some reason. */
|
||||
CLOG_WARN(&LOG,
|
||||
"Creating the '%s' attribute with type '%s' failed.",
|
||||
name.c_str(),
|
||||
cpp_type.name().c_str());
|
||||
attribute_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name);
|
||||
|
||||
GMutableSpan temp_span = attribute->data;
|
||||
GMutableSpan new_span = new_attribute->get_span_for_write_only();
|
||||
BLI_assert(temp_span.size() == new_span.size());
|
||||
|
||||
/* Currently we copy over the attribute. In the future we want to reuse the buffer. */
|
||||
cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size());
|
||||
new_attribute->apply_span();
|
||||
|
||||
attribute_.reset();
|
||||
}
|
||||
|
||||
blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
|
||||
const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type)
|
||||
OutputAttributePtr::~OutputAttributePtr()
|
||||
{
|
||||
return create_output_attribute(*this, attribute_name, domain, data_type, true, nullptr);
|
||||
if (attribute_) {
|
||||
CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Utility function to call #apply_span and #save in the right order. */
|
||||
void OutputAttributePtr::apply_span_and_save()
|
||||
{
|
||||
BLI_assert(attribute_);
|
||||
attribute_->apply_span();
|
||||
this->save();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -24,8 +24,166 @@
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
using fn::GVArrayPtr;
|
||||
using fn::GVMutableArrayPtr;
|
||||
class ConstantReadAttribute final : public ReadAttribute {
|
||||
private:
|
||||
void *value_;
|
||||
|
||||
public:
|
||||
ConstantReadAttribute(AttributeDomain domain,
|
||||
const int64_t size,
|
||||
const CPPType &type,
|
||||
const void *value)
|
||||
: ReadAttribute(domain, type, size)
|
||||
{
|
||||
value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
|
||||
type.copy_to_uninitialized(value, value_);
|
||||
}
|
||||
|
||||
~ConstantReadAttribute() override
|
||||
{
|
||||
this->cpp_type_.destruct(value_);
|
||||
MEM_freeN(value_);
|
||||
}
|
||||
|
||||
void get_internal(const int64_t UNUSED(index), void *r_value) const override
|
||||
{
|
||||
this->cpp_type_.copy_to_uninitialized(value_, r_value);
|
||||
}
|
||||
|
||||
void initialize_span() const override
|
||||
{
|
||||
const int element_size = cpp_type_.size();
|
||||
array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
|
||||
array_is_temporary_ = true;
|
||||
cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class ArrayReadAttribute final : public ReadAttribute {
|
||||
private:
|
||||
Span<T> data_;
|
||||
|
||||
public:
|
||||
ArrayReadAttribute(AttributeDomain domain, Span<T> data)
|
||||
: ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
|
||||
{
|
||||
}
|
||||
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
new (r_value) T(data_[index]);
|
||||
}
|
||||
|
||||
void initialize_span() const override
|
||||
{
|
||||
/* The data will not be modified, so this const_cast is fine. */
|
||||
array_buffer_ = const_cast<T *>(data_.data());
|
||||
array_is_temporary_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
|
||||
private:
|
||||
Array<T> data_;
|
||||
|
||||
public:
|
||||
OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
|
||||
: ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
|
||||
{
|
||||
}
|
||||
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
new (r_value) T(data_[index]);
|
||||
}
|
||||
|
||||
void initialize_span() const override
|
||||
{
|
||||
/* The data will not be modified, so this const_cast is fine. */
|
||||
array_buffer_ = const_cast<T *>(data_.data());
|
||||
array_is_temporary_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
|
||||
class DerivedArrayReadAttribute final : public ReadAttribute {
|
||||
private:
|
||||
Span<StructT> data_;
|
||||
|
||||
public:
|
||||
DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
|
||||
: ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
|
||||
{
|
||||
}
|
||||
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
const StructT &struct_value = data_[index];
|
||||
const ElemT value = GetFunc(struct_value);
|
||||
new (r_value) ElemT(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
|
||||
private:
|
||||
MutableSpan<T> data_;
|
||||
|
||||
public:
|
||||
ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
|
||||
: WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
|
||||
{
|
||||
}
|
||||
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
new (r_value) T(data_[index]);
|
||||
}
|
||||
|
||||
void set_internal(const int64_t index, const void *value) override
|
||||
{
|
||||
data_[index] = *reinterpret_cast<const T *>(value);
|
||||
}
|
||||
|
||||
void initialize_span(const bool UNUSED(write_only)) override
|
||||
{
|
||||
array_buffer_ = data_.data();
|
||||
array_is_temporary_ = false;
|
||||
}
|
||||
|
||||
void apply_span_if_necessary() override
|
||||
{
|
||||
/* Do nothing, because the span contains the attribute itself already. */
|
||||
}
|
||||
};
|
||||
|
||||
template<typename StructT,
|
||||
typename ElemT,
|
||||
ElemT (*GetFunc)(const StructT &),
|
||||
void (*SetFunc)(StructT &, const ElemT &)>
|
||||
class DerivedArrayWriteAttribute final : public WriteAttribute {
|
||||
private:
|
||||
MutableSpan<StructT> data_;
|
||||
|
||||
public:
|
||||
DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
|
||||
: WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
|
||||
{
|
||||
}
|
||||
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
const StructT &struct_value = data_[index];
|
||||
const ElemT value = GetFunc(struct_value);
|
||||
new (r_value) ElemT(value);
|
||||
}
|
||||
|
||||
void set_internal(const int64_t index, const void *value) override
|
||||
{
|
||||
StructT &struct_value = data_[index];
|
||||
const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
|
||||
SetFunc(struct_value, typed_value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility to group together multiple functions that are used to access custom data on geometry
|
||||
@@ -86,11 +244,10 @@ class BuiltinAttributeProvider {
|
||||
{
|
||||
}
|
||||
|
||||
virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0;
|
||||
virtual GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const = 0;
|
||||
virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
|
||||
virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
|
||||
virtual bool try_delete(GeometryComponent &component) const = 0;
|
||||
virtual bool try_create(GeometryComponent &UNUSED(component),
|
||||
const AttributeInit &UNUSED(initializer)) const = 0;
|
||||
virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
|
||||
virtual bool exists(const GeometryComponent &component) const = 0;
|
||||
|
||||
StringRefNull name() const
|
||||
@@ -115,16 +272,15 @@ class BuiltinAttributeProvider {
|
||||
*/
|
||||
class DynamicAttributesProvider {
|
||||
public:
|
||||
virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const = 0;
|
||||
virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const = 0;
|
||||
virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const = 0;
|
||||
virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const = 0;
|
||||
virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
|
||||
virtual bool try_create(GeometryComponent &UNUSED(component),
|
||||
const StringRef UNUSED(attribute_name),
|
||||
const AttributeDomain UNUSED(domain),
|
||||
const CustomDataType UNUSED(data_type),
|
||||
const AttributeInit &UNUSED(initializer)) const
|
||||
const CustomDataType UNUSED(data_type)) const
|
||||
{
|
||||
/* Some providers should not create new attributes. */
|
||||
return false;
|
||||
@@ -153,19 +309,18 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
||||
{
|
||||
}
|
||||
|
||||
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
ReadAttributePtr try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
|
||||
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
WriteAttributePtr try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
|
||||
|
||||
bool try_create(GeometryComponent &component,
|
||||
const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer) const final;
|
||||
const CustomDataType data_type) const final;
|
||||
|
||||
bool foreach_attribute(const GeometryComponent &component,
|
||||
const AttributeForeachCallback callback) const final;
|
||||
@@ -177,21 +332,18 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
ReadAttributeLookup layer_to_read_attribute(const CustomDataLayer &layer,
|
||||
const int domain_size) const
|
||||
ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
|
||||
const int domain_size) const
|
||||
{
|
||||
return {std::make_unique<fn::GVArray_For_Span<T>>(
|
||||
Span(static_cast<const T *>(layer.data), domain_size)),
|
||||
domain_};
|
||||
return std::make_unique<ArrayReadAttribute<T>>(
|
||||
domain_, Span(static_cast<const T *>(layer.data), domain_size));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WriteAttributeLookup layer_to_write_attribute(CustomDataLayer &layer,
|
||||
const int domain_size) const
|
||||
WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
|
||||
{
|
||||
return {std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
|
||||
MutableSpan(static_cast<T *>(layer.data), domain_size)),
|
||||
domain_};
|
||||
return std::make_unique<ArrayWriteAttribute<T>>(
|
||||
domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
|
||||
}
|
||||
|
||||
bool type_is_supported(CustomDataType data_type) const
|
||||
@@ -205,8 +357,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
||||
*/
|
||||
class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
|
||||
private:
|
||||
using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
|
||||
using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
|
||||
using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
|
||||
using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
|
||||
const AttributeDomain domain_;
|
||||
const CustomDataType attribute_type_;
|
||||
const CustomDataType stored_type_;
|
||||
@@ -230,10 +382,10 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
|
||||
{
|
||||
}
|
||||
|
||||
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
ReadAttributePtr try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
WriteAttributePtr try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
|
||||
bool foreach_attribute(const GeometryComponent &component,
|
||||
const AttributeForeachCallback callback) const final;
|
||||
@@ -246,8 +398,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
|
||||
* the #MVert struct, but is exposed as float3 attribute.
|
||||
*/
|
||||
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
|
||||
using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
|
||||
using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
|
||||
using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
|
||||
using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
|
||||
using UpdateOnRead = void (*)(const GeometryComponent &component);
|
||||
using UpdateOnWrite = void (*)(GeometryComponent &component);
|
||||
const CustomDataType stored_type_;
|
||||
@@ -278,10 +430,10 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
|
||||
{
|
||||
}
|
||||
|
||||
GVArrayPtr try_get_for_read(const GeometryComponent &component) const final;
|
||||
GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final;
|
||||
ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final;
|
||||
WriteAttributePtr try_get_for_write(GeometryComponent &component) const final;
|
||||
bool try_delete(GeometryComponent &component) const final;
|
||||
bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final;
|
||||
bool try_create(GeometryComponent &component) const final;
|
||||
bool exists(const GeometryComponent &component) const final;
|
||||
};
|
||||
|
||||
|
@@ -132,7 +132,7 @@ static void blender_version_init(void)
|
||||
|
||||
BLI_snprintf(blender_version_string,
|
||||
ARRAY_SIZE(blender_version_string),
|
||||
"%d.%01d.%d%s",
|
||||
"%d.%02d.%d%s",
|
||||
BLENDER_VERSION / 100,
|
||||
BLENDER_VERSION % 100,
|
||||
BLENDER_VERSION_PATCH,
|
||||
|
@@ -1555,10 +1555,6 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
|
||||
bvh_cache_type,
|
||||
bvh_cache_p,
|
||||
mesh_eval_mutex);
|
||||
|
||||
if (looptri_mask != NULL) {
|
||||
MEM_freeN(looptri_mask);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Setup BVHTreeFromMesh */
|
||||
|
@@ -1302,50 +1302,41 @@ static void collection_missing_parents_remove(Collection *collection)
|
||||
*
|
||||
* \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
|
||||
*
|
||||
* \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
|
||||
* in which case whole \a bmain database of collections is checked.
|
||||
* \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
|
||||
* \param collection: may be \a NULL,
|
||||
* in which case whole \a bmain database of collections is checked.
|
||||
*/
|
||||
void BKE_collections_child_remove_nulls(Main *bmain,
|
||||
Collection *parent_collection,
|
||||
Collection *child_collection)
|
||||
void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
|
||||
{
|
||||
if (child_collection == NULL) {
|
||||
if (parent_collection != NULL) {
|
||||
collection_null_children_remove(parent_collection);
|
||||
if (collection == NULL) {
|
||||
/* We need to do the checks in two steps when more than one collection may be involved,
|
||||
* otherwise we can miss some cases...
|
||||
* Also, master collections are not in bmain, so we also need to loop over scenes.
|
||||
*/
|
||||
for (collection = bmain->collections.first; collection != NULL;
|
||||
collection = collection->id.next) {
|
||||
collection_null_children_remove(collection);
|
||||
}
|
||||
else {
|
||||
/* We need to do the checks in two steps when more than one collection may be involved,
|
||||
* otherwise we can miss some cases...
|
||||
* Also, master collections are not in bmain, so we also need to loop over scenes.
|
||||
*/
|
||||
for (child_collection = bmain->collections.first; child_collection != NULL;
|
||||
child_collection = child_collection->id.next) {
|
||||
collection_null_children_remove(child_collection);
|
||||
}
|
||||
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
|
||||
collection_null_children_remove(scene->master_collection);
|
||||
}
|
||||
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
|
||||
collection_null_children_remove(scene->master_collection);
|
||||
}
|
||||
|
||||
for (child_collection = bmain->collections.first; child_collection != NULL;
|
||||
child_collection = child_collection->id.next) {
|
||||
collection_missing_parents_remove(child_collection);
|
||||
for (collection = bmain->collections.first; collection != NULL;
|
||||
collection = collection->id.next) {
|
||||
collection_missing_parents_remove(collection);
|
||||
}
|
||||
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
|
||||
collection_missing_parents_remove(scene->master_collection);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (CollectionParent *parent = child_collection->parents.first, *parent_next; parent;
|
||||
for (CollectionParent *parent = collection->parents.first, *parent_next; parent;
|
||||
parent = parent_next) {
|
||||
parent_next = parent->next;
|
||||
|
||||
collection_null_children_remove(parent->collection);
|
||||
|
||||
if (!collection_find_child(parent->collection, child_collection)) {
|
||||
BLI_freelinkN(&child_collection->parents, parent);
|
||||
if (!collection_find_child(parent->collection, collection)) {
|
||||
BLI_freelinkN(&collection->parents, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -80,17 +80,7 @@ struct bContext {
|
||||
struct ARegion *menu;
|
||||
struct wmGizmoGroup *gizmo_group;
|
||||
struct bContextStore *store;
|
||||
|
||||
/* Operator poll. */
|
||||
/**
|
||||
* Store the reason the poll function fails (static string, not allocated).
|
||||
* For more advanced formatting use `operator_poll_msg_dyn_params`.
|
||||
*/
|
||||
const char *operator_poll_msg;
|
||||
/**
|
||||
* Store values to dynamically to create the string (called when a tool-tip is shown).
|
||||
*/
|
||||
struct bContextPollMsgDyn_Params operator_poll_msg_dyn_params;
|
||||
const char *operator_poll_msg; /* reason for poll failing */
|
||||
} wm;
|
||||
|
||||
/* data context */
|
||||
@@ -123,16 +113,11 @@ bContext *CTX_copy(const bContext *C)
|
||||
{
|
||||
bContext *newC = MEM_dupallocN((void *)C);
|
||||
|
||||
memset(&newC->wm.operator_poll_msg_dyn_params, 0, sizeof(newC->wm.operator_poll_msg_dyn_params));
|
||||
|
||||
return newC;
|
||||
}
|
||||
|
||||
void CTX_free(bContext *C)
|
||||
{
|
||||
/* This may contain a dynamically allocated message, free. */
|
||||
CTX_wm_operator_poll_msg_clear(C);
|
||||
|
||||
MEM_freeN(C);
|
||||
}
|
||||
|
||||
@@ -1018,45 +1003,13 @@ void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
|
||||
C->wm.gizmo_group = gzgroup;
|
||||
}
|
||||
|
||||
void CTX_wm_operator_poll_msg_clear(bContext *C)
|
||||
{
|
||||
struct bContextPollMsgDyn_Params *params = &C->wm.operator_poll_msg_dyn_params;
|
||||
if (params->free_fn != NULL) {
|
||||
params->free_fn(C, params->user_data);
|
||||
}
|
||||
params->get_fn = NULL;
|
||||
params->free_fn = NULL;
|
||||
params->user_data = NULL;
|
||||
|
||||
C->wm.operator_poll_msg = NULL;
|
||||
}
|
||||
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
|
||||
{
|
||||
CTX_wm_operator_poll_msg_clear(C);
|
||||
|
||||
C->wm.operator_poll_msg = msg;
|
||||
}
|
||||
|
||||
void CTX_wm_operator_poll_msg_set_dynamic(bContext *C,
|
||||
const struct bContextPollMsgDyn_Params *params)
|
||||
const char *CTX_wm_operator_poll_msg_get(bContext *C)
|
||||
{
|
||||
CTX_wm_operator_poll_msg_clear(C);
|
||||
|
||||
C->wm.operator_poll_msg_dyn_params = *params;
|
||||
}
|
||||
|
||||
const char *CTX_wm_operator_poll_msg_get(bContext *C, bool *r_free)
|
||||
{
|
||||
struct bContextPollMsgDyn_Params *params = &C->wm.operator_poll_msg_dyn_params;
|
||||
if (params->get_fn != NULL) {
|
||||
char *msg = params->get_fn(C, params->user_data);
|
||||
if (msg != NULL) {
|
||||
*r_free = true;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
*r_free = false;
|
||||
return IFACE_(C->wm.operator_poll_msg);
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,7 @@
|
||||
/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
|
||||
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
|
||||
|
||||
using blender::fn::GVArray;
|
||||
using blender::bke::ReadAttributePtr;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Component Implementation
|
||||
@@ -201,14 +201,14 @@ namespace blender::bke {
|
||||
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const TypedReadAttribute<T> &attribute,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totvert);
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
for (const int loop_index : IndexRange(mesh.totloop)) {
|
||||
const T value = old_values[loop_index];
|
||||
const T value = attribute[loop_index];
|
||||
const MLoop &loop = mesh.mloop[loop_index];
|
||||
const int point_index = loop.v;
|
||||
mixer.mix_in(point_index, value);
|
||||
@@ -216,40 +216,43 @@ static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
/* We compute all interpolated values at once, because for this interpolation, one has to
|
||||
* iterate over all loops anyway. */
|
||||
Array<T> values(mesh.totvert);
|
||||
adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const TypedReadAttribute<T> &attribute,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totloop);
|
||||
|
||||
for (const int loop_index : IndexRange(mesh.totloop)) {
|
||||
const int vertex_index = mesh.mloop[loop_index].v;
|
||||
r_values[loop_index] = old_values[vertex_index];
|
||||
r_values[loop_index] = attribute[vertex_index];
|
||||
}
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
/* It is not strictly necessary to compute the value for all corners here. Instead one could
|
||||
@@ -257,10 +260,11 @@ static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr
|
||||
* when an algorithm only accesses very few of the corner values. However, for the algorithms
|
||||
* we currently have, precomputing the array is fine. Also, it is easier to implement. */
|
||||
Array<T> values(mesh.totloop);
|
||||
adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
|
||||
std::move(values));
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,7 +274,7 @@ static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr
|
||||
*/
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totpoly);
|
||||
@@ -287,24 +291,26 @@ static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totpoly);
|
||||
adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totedge);
|
||||
@@ -326,24 +332,26 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totedge);
|
||||
adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totvert);
|
||||
@@ -362,24 +370,26 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totvert);
|
||||
adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totloop);
|
||||
@@ -391,24 +401,26 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
|
||||
}
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totloop);
|
||||
adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totedge);
|
||||
@@ -425,19 +437,21 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totedge);
|
||||
adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,7 +461,7 @@ static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr va
|
||||
*/
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totpoly);
|
||||
@@ -464,19 +478,21 @@ static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totpoly);
|
||||
adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,7 +502,7 @@ static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr v
|
||||
*/
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totedge);
|
||||
@@ -501,24 +517,26 @@ static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totedge);
|
||||
adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totloop);
|
||||
@@ -529,7 +547,7 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
|
||||
|
||||
/* For every corner, mix the values from the adjacent edges on the face. */
|
||||
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
|
||||
const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
|
||||
const int loop_index_prev = (loop_index - 1) % poly.totloop;
|
||||
const MLoop &loop = mesh.mloop[loop_index];
|
||||
const MLoop &loop_prev = mesh.mloop[loop_index_prev];
|
||||
mixer.mix_in(loop_index, old_values[loop.e]);
|
||||
@@ -540,24 +558,26 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totloop);
|
||||
adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totvert);
|
||||
@@ -573,19 +593,21 @@ static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totvert);
|
||||
adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,7 +617,7 @@ static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr v
|
||||
*/
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
|
||||
const VArray<T> &old_values,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totpoly);
|
||||
@@ -612,86 +634,87 @@ static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray)
|
||||
static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
GVArrayPtr new_varray;
|
||||
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totpoly);
|
||||
adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values);
|
||||
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
|
||||
adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_varray;
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
|
||||
blender::fn::GVArrayPtr varray,
|
||||
const AttributeDomain from_domain,
|
||||
const AttributeDomain to_domain) const
|
||||
ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
|
||||
const AttributeDomain new_domain) const
|
||||
{
|
||||
if (!varray) {
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
if (varray->size() == 0) {
|
||||
if (attribute->size() == 0) {
|
||||
return {};
|
||||
}
|
||||
if (from_domain == to_domain) {
|
||||
return varray;
|
||||
const AttributeDomain old_domain = attribute->domain();
|
||||
if (old_domain == new_domain) {
|
||||
return attribute;
|
||||
}
|
||||
|
||||
switch (from_domain) {
|
||||
switch (old_domain) {
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
switch (to_domain) {
|
||||
switch (new_domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_FACE:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
switch (to_domain) {
|
||||
switch (new_domain) {
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_FACE:
|
||||
return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
switch (to_domain) {
|
||||
switch (new_domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
switch (to_domain) {
|
||||
switch (new_domain) {
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_FACE:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray));
|
||||
return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -720,21 +743,25 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
|
||||
static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size)
|
||||
template<typename StructT,
|
||||
typename ElemT,
|
||||
ElemT (*GetFunc)(const StructT &),
|
||||
AttributeDomain Domain>
|
||||
static ReadAttributePtr make_derived_read_attribute(const void *data, const int domain_size)
|
||||
{
|
||||
return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
|
||||
Span<StructT>((const StructT *)data, domain_size));
|
||||
return std::make_unique<DerivedArrayReadAttribute<StructT, ElemT, GetFunc>>(
|
||||
Domain, Span<StructT>((const StructT *)data, domain_size));
|
||||
}
|
||||
|
||||
template<typename StructT,
|
||||
typename ElemT,
|
||||
ElemT (*GetFunc)(const StructT &),
|
||||
void (*SetFunc)(StructT &, ElemT)>
|
||||
static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size)
|
||||
void (*SetFunc)(StructT &, const ElemT &),
|
||||
AttributeDomain Domain>
|
||||
static WriteAttributePtr make_derived_write_attribute(void *data, const int domain_size)
|
||||
{
|
||||
return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(
|
||||
MutableSpan<StructT>((StructT *)data, domain_size));
|
||||
return std::make_unique<DerivedArrayWriteAttribute<StructT, ElemT, GetFunc, SetFunc>>(
|
||||
Domain, MutableSpan<StructT>((StructT *)data, domain_size));
|
||||
}
|
||||
|
||||
static float3 get_vertex_position(const MVert &vert)
|
||||
@@ -742,7 +769,7 @@ static float3 get_vertex_position(const MVert &vert)
|
||||
return float3(vert.co);
|
||||
}
|
||||
|
||||
static void set_vertex_position(MVert &vert, float3 position)
|
||||
static void set_vertex_position(MVert &vert, const float3 &position)
|
||||
{
|
||||
copy_v3_v3(vert.co, position);
|
||||
}
|
||||
@@ -760,7 +787,7 @@ static int get_material_index(const MPoly &mpoly)
|
||||
return static_cast<int>(mpoly.mat_nr);
|
||||
}
|
||||
|
||||
static void set_material_index(MPoly &mpoly, int index)
|
||||
static void set_material_index(MPoly &mpoly, const int &index)
|
||||
{
|
||||
mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
|
||||
}
|
||||
@@ -770,7 +797,7 @@ static bool get_shade_smooth(const MPoly &mpoly)
|
||||
return mpoly.flag & ME_SMOOTH;
|
||||
}
|
||||
|
||||
static void set_shade_smooth(MPoly &mpoly, bool value)
|
||||
static void set_shade_smooth(MPoly &mpoly, const bool &value)
|
||||
{
|
||||
SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
|
||||
}
|
||||
@@ -780,7 +807,7 @@ static float2 get_loop_uv(const MLoopUV &uv)
|
||||
return float2(uv.uv);
|
||||
}
|
||||
|
||||
static void set_loop_uv(MLoopUV &uv, float2 co)
|
||||
static void set_loop_uv(MLoopUV &uv, const float2 &co)
|
||||
{
|
||||
copy_v2_v2(uv.uv, co);
|
||||
}
|
||||
@@ -794,7 +821,7 @@ static Color4f get_loop_color(const MLoopCol &col)
|
||||
return linear_color;
|
||||
}
|
||||
|
||||
static void set_loop_color(MLoopCol &col, Color4f linear_color)
|
||||
static void set_loop_color(MLoopCol &col, const Color4f &linear_color)
|
||||
{
|
||||
linearrgb_to_srgb_uchar4(&col.r, linear_color);
|
||||
}
|
||||
@@ -804,62 +831,71 @@ static float get_crease(const MEdge &edge)
|
||||
return edge.crease / 255.0f;
|
||||
}
|
||||
|
||||
static void set_crease(MEdge &edge, float value)
|
||||
static void set_crease(MEdge &edge, const float &value)
|
||||
{
|
||||
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
|
||||
}
|
||||
|
||||
class VMutableArray_For_VertexWeights final : public VMutableArray<float> {
|
||||
class VertexWeightWriteAttribute final : public WriteAttribute {
|
||||
private:
|
||||
MDeformVert *dverts_;
|
||||
const int dvert_index_;
|
||||
|
||||
public:
|
||||
VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
|
||||
: VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
|
||||
VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
|
||||
: WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
|
||||
dverts_(dverts),
|
||||
dvert_index_(dvert_index)
|
||||
{
|
||||
}
|
||||
|
||||
float get_impl(const int64_t index) const override
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
return get_internal(dverts_, dvert_index_, index);
|
||||
get_internal(dverts_, dvert_index_, index, r_value);
|
||||
}
|
||||
|
||||
void set_impl(const int64_t index, const float value) override
|
||||
void set_internal(const int64_t index, const void *value) override
|
||||
{
|
||||
MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
|
||||
weight->weight = value;
|
||||
weight->weight = *reinterpret_cast<const float *>(value);
|
||||
}
|
||||
|
||||
static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index)
|
||||
static void get_internal(const MDeformVert *dverts,
|
||||
const int dvert_index,
|
||||
const int64_t index,
|
||||
void *r_value)
|
||||
{
|
||||
if (dverts == nullptr) {
|
||||
return 0.0f;
|
||||
*(float *)r_value = 0.0f;
|
||||
return;
|
||||
}
|
||||
const MDeformVert &dvert = dverts[index];
|
||||
for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
|
||||
if (weight.def_nr == dvert_index) {
|
||||
return weight.weight;
|
||||
*(float *)r_value = weight.weight;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
*(float *)r_value = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
class VArray_For_VertexWeights final : public VArray<float> {
|
||||
class VertexWeightReadAttribute final : public ReadAttribute {
|
||||
private:
|
||||
const MDeformVert *dverts_;
|
||||
const int dvert_index_;
|
||||
|
||||
public:
|
||||
VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index)
|
||||
: VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
|
||||
VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
|
||||
: ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
|
||||
dverts_(dverts),
|
||||
dvert_index_(dvert_index)
|
||||
{
|
||||
}
|
||||
|
||||
float get_impl(const int64_t index) const override
|
||||
void get_internal(const int64_t index, void *r_value) const override
|
||||
{
|
||||
return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index);
|
||||
VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -868,8 +904,8 @@ class VArray_For_VertexWeights final : public VArray<float> {
|
||||
*/
|
||||
class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
||||
public:
|
||||
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
ReadAttributePtr try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
{
|
||||
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
@@ -881,17 +917,15 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
||||
}
|
||||
if (mesh == nullptr || mesh->dvert == nullptr) {
|
||||
static const float default_value = 0.0f;
|
||||
return {std::make_unique<fn::GVArray_For_SingleValueRef>(
|
||||
CPPType::get<float>(), mesh->totvert, &default_value),
|
||||
ATTR_DOMAIN_POINT};
|
||||
return std::make_unique<ConstantReadAttribute>(
|
||||
ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
|
||||
}
|
||||
return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>(
|
||||
mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
|
||||
ATTR_DOMAIN_POINT};
|
||||
return std::make_unique<VertexWeightReadAttribute>(
|
||||
mesh->dvert, mesh->totvert, vertex_group_index);
|
||||
}
|
||||
|
||||
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
WriteAttributePtr try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
{
|
||||
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
|
||||
MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
|
||||
@@ -912,11 +946,8 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
||||
mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
|
||||
&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
|
||||
}
|
||||
return {
|
||||
std::make_unique<
|
||||
fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>(
|
||||
mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
|
||||
ATTR_DOMAIN_POINT};
|
||||
return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
|
||||
mesh->dvert, mesh->totvert, vertex_group_index);
|
||||
}
|
||||
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
|
||||
@@ -978,7 +1009,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
|
||||
{
|
||||
}
|
||||
|
||||
GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
|
||||
ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
|
||||
{
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
@@ -991,8 +1022,8 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
|
||||
CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
|
||||
const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
|
||||
|
||||
return std::make_unique<fn::GVArray_For_Span<float3>>(
|
||||
Span<float3>((const float3 *)data, mesh->totpoly));
|
||||
return std::make_unique<ArrayReadAttribute<float3>>(
|
||||
ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly));
|
||||
}
|
||||
|
||||
Array<float3> normals(mesh->totpoly);
|
||||
@@ -1001,10 +1032,10 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
|
||||
BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
|
||||
}
|
||||
|
||||
return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
|
||||
return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals));
|
||||
}
|
||||
|
||||
GVMutableArrayPtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
|
||||
WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -1014,8 +1045,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_create(GeometryComponent &UNUSED(component),
|
||||
const AttributeInit &UNUSED(initializer)) const final
|
||||
bool try_create(GeometryComponent &UNUSED(component)) const final
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1075,8 +1105,12 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
point_access,
|
||||
make_derived_read_attribute<MVert, float3, get_vertex_position>,
|
||||
make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>,
|
||||
make_derived_read_attribute<MVert, float3, get_vertex_position, ATTR_DOMAIN_POINT>,
|
||||
make_derived_write_attribute<MVert,
|
||||
float3,
|
||||
get_vertex_position,
|
||||
set_vertex_position,
|
||||
ATTR_DOMAIN_POINT>,
|
||||
tag_normals_dirty_when_writing_position);
|
||||
|
||||
static NormalAttributeProvider normal;
|
||||
@@ -1090,8 +1124,12 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
face_access,
|
||||
make_derived_read_attribute<MPoly, int, get_material_index>,
|
||||
make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>,
|
||||
make_derived_read_attribute<MPoly, int, get_material_index, ATTR_DOMAIN_FACE>,
|
||||
make_derived_write_attribute<MPoly,
|
||||
int,
|
||||
get_material_index,
|
||||
set_material_index,
|
||||
ATTR_DOMAIN_FACE>,
|
||||
nullptr);
|
||||
|
||||
static BuiltinCustomDataLayerProvider shade_smooth(
|
||||
@@ -1103,8 +1141,12 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
face_access,
|
||||
make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
|
||||
make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
|
||||
make_derived_read_attribute<MPoly, bool, get_shade_smooth, ATTR_DOMAIN_FACE>,
|
||||
make_derived_write_attribute<MPoly,
|
||||
bool,
|
||||
get_shade_smooth,
|
||||
set_shade_smooth,
|
||||
ATTR_DOMAIN_FACE>,
|
||||
nullptr);
|
||||
|
||||
static BuiltinCustomDataLayerProvider crease(
|
||||
@@ -1116,8 +1158,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
edge_access,
|
||||
make_derived_read_attribute<MEdge, float, get_crease>,
|
||||
make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
|
||||
make_derived_read_attribute<MEdge, float, get_crease, ATTR_DOMAIN_EDGE>,
|
||||
make_derived_write_attribute<MEdge, float, get_crease, set_crease, ATTR_DOMAIN_EDGE>,
|
||||
nullptr);
|
||||
|
||||
static NamedLegacyCustomDataProvider uvs(
|
||||
@@ -1125,16 +1167,20 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
||||
CD_PROP_FLOAT2,
|
||||
CD_MLOOPUV,
|
||||
corner_access,
|
||||
make_derived_read_attribute<MLoopUV, float2, get_loop_uv>,
|
||||
make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv>);
|
||||
make_derived_read_attribute<MLoopUV, float2, get_loop_uv, ATTR_DOMAIN_CORNER>,
|
||||
make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv, ATTR_DOMAIN_CORNER>);
|
||||
|
||||
static NamedLegacyCustomDataProvider vertex_colors(
|
||||
ATTR_DOMAIN_CORNER,
|
||||
CD_PROP_COLOR,
|
||||
CD_MLOOPCOL,
|
||||
corner_access,
|
||||
make_derived_read_attribute<MLoopCol, Color4f, get_loop_color>,
|
||||
make_derived_write_attribute<MLoopCol, Color4f, get_loop_color, set_loop_color>);
|
||||
make_derived_read_attribute<MLoopCol, Color4f, get_loop_color, ATTR_DOMAIN_CORNER>,
|
||||
make_derived_write_attribute<MLoopCol,
|
||||
Color4f,
|
||||
get_loop_color,
|
||||
set_loop_color,
|
||||
ATTR_DOMAIN_CORNER>);
|
||||
|
||||
static VertexGroupsAttributeProvider vertex_groups;
|
||||
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
|
||||
|
@@ -140,17 +140,16 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
template<typename T>
|
||||
static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size)
|
||||
template<typename T, AttributeDomain Domain>
|
||||
static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
|
||||
{
|
||||
return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size));
|
||||
return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size)
|
||||
template<typename T, AttributeDomain Domain>
|
||||
static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
|
||||
{
|
||||
return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
|
||||
MutableSpan<T>((T *)data, domain_size));
|
||||
return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,28 +179,30 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
|
||||
},
|
||||
update_custom_data_pointers};
|
||||
|
||||
static BuiltinCustomDataLayerProvider position("position",
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_FLOAT3,
|
||||
CD_PROP_FLOAT3,
|
||||
BuiltinAttributeProvider::NonCreatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float3>,
|
||||
make_array_write_attribute<float3>,
|
||||
nullptr);
|
||||
static BuiltinCustomDataLayerProvider radius("radius",
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_FLOAT,
|
||||
CD_PROP_FLOAT,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float>,
|
||||
make_array_write_attribute<float>,
|
||||
nullptr);
|
||||
static BuiltinCustomDataLayerProvider position(
|
||||
"position",
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_FLOAT3,
|
||||
CD_PROP_FLOAT3,
|
||||
BuiltinAttributeProvider::NonCreatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
|
||||
make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
|
||||
nullptr);
|
||||
static BuiltinCustomDataLayerProvider radius(
|
||||
"radius",
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_FLOAT,
|
||||
CD_PROP_FLOAT,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
|
||||
make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
|
||||
nullptr);
|
||||
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
|
||||
return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
|
||||
}
|
||||
|
@@ -36,42 +36,30 @@ static void geometry_set_collect_recursive_collection(const Collection &collecti
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets);
|
||||
|
||||
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
|
||||
{
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(&const_cast<Object &>(object),
|
||||
false);
|
||||
|
||||
if (mesh != nullptr) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
||||
mesh_component.copy_vertex_group_names_from_object(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
|
||||
*/
|
||||
static GeometrySet object_get_geometry_set_for_read(const Object &object)
|
||||
{
|
||||
if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
|
||||
GeometrySet geometry_set;
|
||||
if (object.runtime.geometry_set_eval != nullptr) {
|
||||
/* `geometry_set_eval` only contains non-mesh components, see `editbmesh_build_data`. */
|
||||
geometry_set = *object.runtime.geometry_set_eval;
|
||||
}
|
||||
add_final_mesh_as_geometry_component(object, geometry_set);
|
||||
return geometry_set;
|
||||
}
|
||||
/* Objects evaluated with a nodes modifier will have a geometry set already. */
|
||||
if (object.runtime.geometry_set_eval != nullptr) {
|
||||
return *object.runtime.geometry_set_eval;
|
||||
}
|
||||
|
||||
/* Otherwise, construct a new geometry set with the component based on the object type. */
|
||||
GeometrySet geometry_set;
|
||||
GeometrySet new_geometry_set;
|
||||
|
||||
if (object.type == OB_MESH) {
|
||||
add_final_mesh_as_geometry_component(object, geometry_set);
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(
|
||||
&const_cast<Object &>(object), false);
|
||||
|
||||
if (mesh != nullptr) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
|
||||
MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
||||
mesh_component.copy_vertex_group_names_from_object(object);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
|
||||
@@ -80,7 +68,7 @@ static GeometrySet object_get_geometry_set_for_read(const Object &object)
|
||||
/* TODO: Add volume support. */
|
||||
|
||||
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
|
||||
return geometry_set;
|
||||
return new_geometry_set;
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive_collection_instance(
|
||||
@@ -449,15 +437,13 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
|
||||
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
|
||||
result.attribute_try_create(
|
||||
entry.key, domain_output, data_type_output, AttributeInitDefault());
|
||||
WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name);
|
||||
if (!write_attribute || &write_attribute.varray->type() != cpp_type ||
|
||||
write_attribute.domain != domain_output) {
|
||||
result.attribute_try_create(entry.key, domain_output, data_type_output);
|
||||
WriteAttributePtr write_attribute = result.attribute_try_get_for_write(name);
|
||||
if (!write_attribute || &write_attribute->cpp_type() != cpp_type ||
|
||||
write_attribute->domain() != domain_output) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fn::GVMutableArray_GSpan dst_span{*write_attribute.varray};
|
||||
fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
|
||||
|
||||
int offset = 0;
|
||||
for (const GeometryInstanceGroup &set_group : set_groups) {
|
||||
@@ -469,11 +455,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
|
||||
if (domain_size == 0) {
|
||||
continue; /* Domain size is 0, so no need to increment the offset. */
|
||||
}
|
||||
GVArrayPtr source_attribute = component.attribute_try_get_for_read(
|
||||
ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
|
||||
name, domain_output, data_type_output);
|
||||
|
||||
if (source_attribute) {
|
||||
fn::GVArray_GSpan src_span{*source_attribute};
|
||||
fn::GSpan src_span = source_attribute->get_span();
|
||||
const void *src_buffer = src_span.data();
|
||||
for (const int UNUSED(i) : set_group.transforms.index_range()) {
|
||||
void *dst_buffer = dst_span[offset];
|
||||
@@ -488,7 +474,7 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
|
||||
}
|
||||
}
|
||||
|
||||
dst_span.save();
|
||||
write_attribute->apply_span();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -303,7 +303,6 @@ static void libblock_remap_data_postprocess_object_update(Main *bmain,
|
||||
/* Can be called with both old_collection and new_collection being NULL,
|
||||
* this means we have to check whole Main database then. */
|
||||
static void libblock_remap_data_postprocess_collection_update(Main *bmain,
|
||||
Collection *owner_collection,
|
||||
Collection *UNUSED(old_collection),
|
||||
Collection *new_collection)
|
||||
{
|
||||
@@ -312,7 +311,7 @@ static void libblock_remap_data_postprocess_collection_update(Main *bmain,
|
||||
* and BKE_main_collection_sync_remap() does not tolerate any of those, so for now always check
|
||||
* whole existing collections for NULL pointers.
|
||||
* I'd consider optimizing that whole collection remapping process a TODO for later. */
|
||||
BKE_collections_child_remove_nulls(bmain, owner_collection, NULL /*old_collection*/);
|
||||
BKE_collections_child_remove_nulls(bmain, NULL /*old_collection*/);
|
||||
}
|
||||
else {
|
||||
/* Temp safe fix, but a "tad" brute force... We should probably be able to use parents from
|
||||
@@ -524,7 +523,7 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
|
||||
break;
|
||||
case ID_GR:
|
||||
libblock_remap_data_postprocess_collection_update(
|
||||
bmain, NULL, (Collection *)old_id, (Collection *)new_id);
|
||||
bmain, (Collection *)old_id, (Collection *)new_id);
|
||||
break;
|
||||
case ID_ME:
|
||||
case ID_CU:
|
||||
@@ -629,12 +628,6 @@ void BKE_libblock_relink_ex(
|
||||
switch (GS(id->name)) {
|
||||
case ID_SCE:
|
||||
case ID_GR: {
|
||||
/* Note: here we know which collection we have affected, so at lest for NULL children
|
||||
* detection we can only process that one.
|
||||
* This is also a required fix in case `id` would not be in Main anymore, which can happen
|
||||
* e.g. when called from `id_delete`. */
|
||||
Collection *owner_collection = (GS(id->name) == ID_GR) ? (Collection *)id :
|
||||
((Scene *)id)->master_collection;
|
||||
if (old_id) {
|
||||
switch (GS(old_id->name)) {
|
||||
case ID_OB:
|
||||
@@ -643,7 +636,7 @@ void BKE_libblock_relink_ex(
|
||||
break;
|
||||
case ID_GR:
|
||||
libblock_remap_data_postprocess_collection_update(
|
||||
bmain, owner_collection, (Collection *)old_id, (Collection *)new_id);
|
||||
bmain, (Collection *)old_id, (Collection *)new_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -651,7 +644,7 @@ void BKE_libblock_relink_ex(
|
||||
}
|
||||
else {
|
||||
/* No choice but to check whole objects/collections. */
|
||||
libblock_remap_data_postprocess_collection_update(bmain, owner_collection, NULL, NULL);
|
||||
libblock_remap_data_postprocess_collection_update(bmain, NULL, NULL);
|
||||
libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
|
||||
}
|
||||
break;
|
||||
|
@@ -1065,7 +1065,6 @@ static void curve_to_mesh_eval_ensure(Object *object)
|
||||
Curve *curve = (Curve *)object->data;
|
||||
Curve remapped_curve = *curve;
|
||||
Object remapped_object = *object;
|
||||
remapped_object.runtime.bb = NULL;
|
||||
remapped_object.data = &remapped_curve;
|
||||
|
||||
/* Clear all modifiers for the bevel object.
|
||||
@@ -1078,7 +1077,6 @@ static void curve_to_mesh_eval_ensure(Object *object)
|
||||
Object bevel_object = {{NULL}};
|
||||
if (remapped_curve.bevobj != NULL) {
|
||||
bevel_object = *remapped_curve.bevobj;
|
||||
bevel_object.runtime.bb = NULL;
|
||||
BLI_listbase_clear(&bevel_object.modifiers);
|
||||
remapped_curve.bevobj = &bevel_object;
|
||||
}
|
||||
@@ -1087,7 +1085,6 @@ static void curve_to_mesh_eval_ensure(Object *object)
|
||||
Object taper_object = {{NULL}};
|
||||
if (remapped_curve.taperobj != NULL) {
|
||||
taper_object = *remapped_curve.taperobj;
|
||||
taper_object.runtime.bb = NULL;
|
||||
BLI_listbase_clear(&taper_object.modifiers);
|
||||
remapped_curve.taperobj = &taper_object;
|
||||
}
|
||||
@@ -1110,10 +1107,6 @@ static void curve_to_mesh_eval_ensure(Object *object)
|
||||
BKE_object_eval_assign_data(&remapped_object, &mesh_eval->id, true);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(remapped_object.runtime.bb);
|
||||
MEM_SAFE_FREE(taper_object.runtime.bb);
|
||||
MEM_SAFE_FREE(bevel_object.runtime.bb);
|
||||
|
||||
BKE_object_free_curve_cache(&bevel_object);
|
||||
BKE_object_free_curve_cache(&taper_object);
|
||||
}
|
||||
@@ -1542,7 +1535,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
|
||||
* check whether it is still true with Mesh */
|
||||
Mesh tmp = *mesh_dst;
|
||||
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
|
||||
bool did_shapekeys = false;
|
||||
int did_shapekeys = 0;
|
||||
eCDAllocType alloctype = CD_DUPLICATE;
|
||||
|
||||
if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
|
||||
@@ -1597,7 +1590,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
|
||||
}
|
||||
|
||||
shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
|
||||
did_shapekeys = true;
|
||||
did_shapekeys = 1;
|
||||
}
|
||||
|
||||
/* copy texture space */
|
||||
@@ -1626,18 +1619,13 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
|
||||
totedge);
|
||||
}
|
||||
if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
|
||||
CustomData_add_layer(&tmp.ldata,
|
||||
CD_MLOOP,
|
||||
CD_ASSIGN,
|
||||
(alloctype == CD_ASSIGN) ? mesh_src->mloop :
|
||||
MEM_dupallocN(mesh_src->mloop),
|
||||
tmp.totloop);
|
||||
CustomData_add_layer(&tmp.pdata,
|
||||
CD_MPOLY,
|
||||
CD_ASSIGN,
|
||||
(alloctype == CD_ASSIGN) ? mesh_src->mpoly :
|
||||
MEM_dupallocN(mesh_src->mpoly),
|
||||
tmp.totpoly);
|
||||
/* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the
|
||||
* BKE_mesh_update_customdata_pointers() call below. */
|
||||
tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
|
||||
tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
|
||||
|
||||
CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
|
||||
CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
|
||||
}
|
||||
|
||||
/* object had got displacement layer, should copy this layer to save sculpted data */
|
||||
@@ -1646,16 +1634,15 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
|
||||
if (totloop == mesh_dst->totloop) {
|
||||
MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
|
||||
CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
|
||||
if (alloctype == CD_ASSIGN) {
|
||||
/* Assign NULL to prevent double-free. */
|
||||
CustomData_set_layer(&mesh_dst->ldata, CD_MDISPS, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* yes, must be before _and_ after tessellate */
|
||||
BKE_mesh_update_customdata_pointers(&tmp, false);
|
||||
|
||||
/* since 2.65 caller must do! */
|
||||
// BKE_mesh_tessface_calc(&tmp);
|
||||
|
||||
CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
|
||||
CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
|
||||
CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
|
||||
|
@@ -51,7 +51,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm
|
||||
(axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
|
||||
(axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
|
||||
|
||||
const float bisect_distance = mmd->bisect_threshold;
|
||||
const float bisect_distance = 0.001f;
|
||||
|
||||
Mesh *result;
|
||||
BMesh *bm;
|
||||
|
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_mesh_sample.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
namespace blender::bke::mesh_surface_sample {
|
||||
|
||||
static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
|
||||
{
|
||||
/* This only updates a cache and can be considered to be logically const. */
|
||||
const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
|
||||
const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
|
||||
return {looptris, looptris_len};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
|
||||
const Span<int> looptri_indices,
|
||||
const Span<float3> bary_coords,
|
||||
const VArray<T> &data_in,
|
||||
const MutableSpan<T> data_out)
|
||||
{
|
||||
const Span<MLoopTri> looptris = get_mesh_looptris(mesh);
|
||||
|
||||
for (const int i : bary_coords.index_range()) {
|
||||
const int looptri_index = looptri_indices[i];
|
||||
const MLoopTri &looptri = looptris[looptri_index];
|
||||
const float3 &bary_coord = bary_coords[i];
|
||||
|
||||
const int v0_index = mesh.mloop[looptri.tri[0]].v;
|
||||
const int v1_index = mesh.mloop[looptri.tri[1]].v;
|
||||
const int v2_index = mesh.mloop[looptri.tri[2]].v;
|
||||
|
||||
const T v0 = data_in[v0_index];
|
||||
const T v1 = data_in[v1_index];
|
||||
const T v2 = data_in[v2_index];
|
||||
|
||||
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
|
||||
data_out[i] = interpolated_value;
|
||||
}
|
||||
}
|
||||
|
||||
void sample_point_attribute(const Mesh &mesh,
|
||||
const Span<int> looptri_indices,
|
||||
const Span<float3> bary_coords,
|
||||
const GVArray &data_in,
|
||||
const GMutableSpan data_out)
|
||||
{
|
||||
BLI_assert(data_out.size() == looptri_indices.size());
|
||||
BLI_assert(data_out.size() == bary_coords.size());
|
||||
BLI_assert(data_in.size() == mesh.totvert);
|
||||
BLI_assert(data_in.type() == data_out.type());
|
||||
|
||||
const CPPType &type = data_in.type();
|
||||
attribute_math::convert_to_static_type(type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
sample_point_attribute<T>(
|
||||
mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
|
||||
const Span<int> looptri_indices,
|
||||
const Span<float3> bary_coords,
|
||||
const VArray<T> &data_in,
|
||||
const MutableSpan<T> data_out)
|
||||
{
|
||||
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
|
||||
|
||||
for (const int i : bary_coords.index_range()) {
|
||||
const int looptri_index = looptri_indices[i];
|
||||
const MLoopTri &looptri = looptris[looptri_index];
|
||||
const float3 &bary_coord = bary_coords[i];
|
||||
|
||||
const int loop_index_0 = looptri.tri[0];
|
||||
const int loop_index_1 = looptri.tri[1];
|
||||
const int loop_index_2 = looptri.tri[2];
|
||||
|
||||
const T v0 = data_in[loop_index_0];
|
||||
const T v1 = data_in[loop_index_1];
|
||||
const T v2 = data_in[loop_index_2];
|
||||
|
||||
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
|
||||
data_out[i] = interpolated_value;
|
||||
}
|
||||
}
|
||||
|
||||
void sample_corner_attribute(const Mesh &mesh,
|
||||
const Span<int> looptri_indices,
|
||||
const Span<float3> bary_coords,
|
||||
const GVArray &data_in,
|
||||
const GMutableSpan data_out)
|
||||
{
|
||||
BLI_assert(data_out.size() == looptri_indices.size());
|
||||
BLI_assert(data_out.size() == bary_coords.size());
|
||||
BLI_assert(data_in.size() == mesh.totloop);
|
||||
BLI_assert(data_in.type() == data_out.type());
|
||||
|
||||
const CPPType &type = data_in.type();
|
||||
attribute_math::convert_to_static_type(type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
sample_corner_attribute<T>(
|
||||
mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void sample_face_attribute(const Mesh &mesh,
|
||||
const Span<int> looptri_indices,
|
||||
const VArray<T> &data_in,
|
||||
const MutableSpan<T> data_out)
|
||||
{
|
||||
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
|
||||
|
||||
for (const int i : data_out.index_range()) {
|
||||
const int looptri_index = looptri_indices[i];
|
||||
const MLoopTri &looptri = looptris[looptri_index];
|
||||
const int poly_index = looptri.poly;
|
||||
data_out[i] = data_in[poly_index];
|
||||
}
|
||||
}
|
||||
|
||||
void sample_face_attribute(const Mesh &mesh,
|
||||
const Span<int> looptri_indices,
|
||||
const GVArray &data_in,
|
||||
const GMutableSpan data_out)
|
||||
{
|
||||
BLI_assert(data_out.size() == looptri_indices.size());
|
||||
BLI_assert(data_in.size() == mesh.totpoly);
|
||||
BLI_assert(data_in.type() == data_out.type());
|
||||
|
||||
const CPPType &type = data_in.type();
|
||||
attribute_math::convert_to_static_type(type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), data_out.typed<T>());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace blender::bke::mesh_surface_sample
|
@@ -4968,7 +4968,6 @@ static void registerGeometryNodes()
|
||||
register_node_type_geo_sample_texture();
|
||||
register_node_type_geo_subdivide();
|
||||
register_node_type_geo_subdivision_surface();
|
||||
register_node_type_geo_switch();
|
||||
register_node_type_geo_transform();
|
||||
register_node_type_geo_triangulate();
|
||||
register_node_type_geo_volume_to_mesh();
|
||||
|
@@ -1336,7 +1336,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
|
||||
return (mti->modifyGeometrySet != NULL);
|
||||
}
|
||||
if (ob->type == OB_VOLUME) {
|
||||
return (mti->modifyVolume != NULL) || (mti->modifyGeometrySet != NULL);
|
||||
return (mti->modifyVolume != NULL);
|
||||
}
|
||||
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
|
||||
if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) {
|
||||
@@ -4135,7 +4135,7 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
|
||||
const bool use_hidden)
|
||||
{
|
||||
bool ok = false;
|
||||
if ((ob->transflag & OB_DUPLI) == 0 && ob->runtime.geometry_set_eval == NULL) {
|
||||
if ((ob->transflag & OB_DUPLI) == 0) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@@ -176,13 +176,6 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
|
||||
|
||||
CustomData_MeshMasks cddata_masks = scene->customdata_mask;
|
||||
CustomData_MeshMasks_update(&cddata_masks, &CD_MASK_BAREMESH);
|
||||
/* Custom attributes should not be removed automatically. They might be used by the render
|
||||
* engine or scripts. They can still be removed explicitly using geometry nodes. */
|
||||
cddata_masks.vmask |= CD_MASK_PROP_ALL;
|
||||
cddata_masks.emask |= CD_MASK_PROP_ALL;
|
||||
cddata_masks.fmask |= CD_MASK_PROP_ALL;
|
||||
cddata_masks.pmask |= CD_MASK_PROP_ALL;
|
||||
cddata_masks.lmask |= CD_MASK_PROP_ALL;
|
||||
/* Make sure Freestyle edge/face marks appear in DM for render (see T40315).
|
||||
* Due to Line Art implementation, edge marks should also be shown in viewport. */
|
||||
#ifdef WITH_FREESTYLE
|
||||
|
@@ -2636,7 +2636,6 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
|
||||
|
||||
Scene *scene = DEG_get_input_scene(depsgraph);
|
||||
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
|
||||
bool used_multiple_passes = false;
|
||||
|
||||
bool run_callbacks = DEG_id_type_any_updated(depsgraph);
|
||||
if (run_callbacks) {
|
||||
@@ -2673,6 +2672,8 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
|
||||
* If there are no relations changed by the callback this call will do nothing. */
|
||||
DEG_graph_relations_update(depsgraph);
|
||||
}
|
||||
/* Inform editors about possible changes. */
|
||||
DEG_editors_update(bmain, depsgraph, scene, view_layer, false);
|
||||
|
||||
/* If user callback did not tag anything for update we can skip second iteration.
|
||||
* Otherwise we update scene once again, but without running callbacks to bring
|
||||
@@ -2681,22 +2682,8 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear recalc flags for second pass, but back them up for editors update. */
|
||||
const bool backup = true;
|
||||
DEG_ids_clear_recalc(depsgraph, backup);
|
||||
used_multiple_passes = true;
|
||||
run_callbacks = false;
|
||||
}
|
||||
|
||||
/* Inform editors about changes, using recalc flags from both passes. */
|
||||
if (used_multiple_passes) {
|
||||
DEG_ids_restore_recalc(depsgraph);
|
||||
}
|
||||
const bool is_time_update = false;
|
||||
DEG_editors_update(depsgraph, is_time_update);
|
||||
|
||||
const bool backup = false;
|
||||
DEG_ids_clear_recalc(depsgraph, backup);
|
||||
}
|
||||
|
||||
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
|
||||
@@ -2710,11 +2697,11 @@ void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
|
||||
}
|
||||
|
||||
/* applies changes right away, does all sets too */
|
||||
void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool clear_recalc)
|
||||
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
|
||||
{
|
||||
Scene *scene = DEG_get_input_scene(depsgraph);
|
||||
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
|
||||
Main *bmain = DEG_get_bmain(depsgraph);
|
||||
bool used_multiple_passes = false;
|
||||
|
||||
/* Keep this first. */
|
||||
BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_PRE);
|
||||
@@ -2751,38 +2738,16 @@ void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool cle
|
||||
DEG_graph_relations_update(depsgraph);
|
||||
}
|
||||
|
||||
/* Inform editors about possible changes. */
|
||||
DEG_editors_update(bmain, depsgraph, scene, view_layer, true);
|
||||
|
||||
/* If user callback did not tag anything for update we can skip second iteration.
|
||||
* Otherwise we update scene once again, but without running callbacks to bring
|
||||
* scene to a fully evaluated state with user modifications taken into account. */
|
||||
if (DEG_is_fully_evaluated(depsgraph)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear recalc flags for second pass, but back them up for editors update. */
|
||||
const bool backup = true;
|
||||
DEG_ids_clear_recalc(depsgraph, backup);
|
||||
used_multiple_passes = true;
|
||||
}
|
||||
|
||||
/* Inform editors about changes, using recalc flags from both passes. */
|
||||
if (used_multiple_passes) {
|
||||
DEG_ids_restore_recalc(depsgraph);
|
||||
}
|
||||
|
||||
const bool is_time_update = true;
|
||||
DEG_editors_update(depsgraph, is_time_update);
|
||||
|
||||
/* Clear recalc flags, can be skipped for e.g. renderers that will read these
|
||||
* and clear the flags later. */
|
||||
if (clear_recalc) {
|
||||
const bool backup = false;
|
||||
DEG_ids_clear_recalc(depsgraph, backup);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
|
||||
{
|
||||
BKE_scene_graph_update_for_newframe_ex(depsgraph, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3542,8 +3507,8 @@ GHash *BKE_scene_undo_depsgraphs_extract(Main *bmain)
|
||||
|
||||
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
|
||||
if (scene->depsgraph_hash == NULL) {
|
||||
/* In some cases, e.g. when undo has to perform multiple steps at once, no depsgraph will
|
||||
* be built so this pointer may be NULL. */
|
||||
/* In some cases, e.g. when undo has to perform multiple steps at once, no depsgraph will be
|
||||
* built so this pointer may be NULL. */
|
||||
continue;
|
||||
}
|
||||
for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL;
|
||||
|
@@ -39,7 +39,6 @@
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_anim_data.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_lib_id.h"
|
||||
@@ -1004,12 +1003,13 @@ static void volume_update_simplify_level(Volume *volume, const Depsgraph *depsgr
|
||||
#endif
|
||||
}
|
||||
|
||||
static void volume_evaluate_modifiers(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
Object *object,
|
||||
Volume *volume_input,
|
||||
GeometrySet &geometry_set)
|
||||
static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
Object *object,
|
||||
Volume *volume_input)
|
||||
{
|
||||
Volume *volume = volume_input;
|
||||
|
||||
/* Modifier evaluation modes. */
|
||||
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
|
||||
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
|
||||
@@ -1030,22 +1030,25 @@ static void volume_evaluate_modifiers(struct Depsgraph *depsgraph,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mti->modifyGeometrySet) {
|
||||
mti->modifyGeometrySet(md, &mectx, &geometry_set);
|
||||
}
|
||||
else if (mti->modifyVolume) {
|
||||
VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
|
||||
Volume *volume_old = volume_component.get_for_write();
|
||||
if (volume_old == nullptr) {
|
||||
volume_old = BKE_volume_new_for_eval(volume_input);
|
||||
volume_component.replace(volume_old);
|
||||
if (mti->modifyVolume) {
|
||||
/* Ensure we are not modifying the input. */
|
||||
if (volume == volume_input) {
|
||||
volume = BKE_volume_copy_for_eval(volume, true);
|
||||
}
|
||||
Volume *volume_new = mti->modifyVolume(md, &mectx, volume_old);
|
||||
if (volume_new != volume_old) {
|
||||
volume_component.replace(volume_new);
|
||||
|
||||
Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
|
||||
|
||||
if (volume_next && volume_next != volume) {
|
||||
/* If the modifier returned a new volume, release the old one. */
|
||||
if (volume != volume_input) {
|
||||
BKE_id_free(nullptr, volume);
|
||||
}
|
||||
volume = volume_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
|
||||
@@ -1069,24 +1072,6 @@ void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
|
||||
}
|
||||
}
|
||||
|
||||
static Volume *take_volume_ownership_from_geometry_set(GeometrySet &geometry_set)
|
||||
{
|
||||
if (!geometry_set.has<VolumeComponent>()) {
|
||||
return nullptr;
|
||||
}
|
||||
VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
|
||||
Volume *volume = volume_component.release();
|
||||
if (volume != nullptr) {
|
||||
/* Add back, but only as read-only non-owning component. */
|
||||
volume_component.replace(volume, GeometryOwnershipType::ReadOnly);
|
||||
}
|
||||
else {
|
||||
/* The component was empty, we can remove it. */
|
||||
geometry_set.remove<VolumeComponent>();
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
|
||||
{
|
||||
/* Free any evaluated data and restore original data. */
|
||||
@@ -1094,22 +1079,11 @@ void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Ob
|
||||
|
||||
/* Evaluate modifiers. */
|
||||
Volume *volume = (Volume *)object->data;
|
||||
GeometrySet geometry_set;
|
||||
VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
|
||||
volume_component.replace(volume, GeometryOwnershipType::ReadOnly);
|
||||
volume_evaluate_modifiers(depsgraph, scene, object, volume, geometry_set);
|
||||
|
||||
Volume *volume_eval = take_volume_ownership_from_geometry_set(geometry_set);
|
||||
|
||||
/* If the geometry set did not contain a volume, we still create an empty one. */
|
||||
if (volume_eval == nullptr) {
|
||||
volume_eval = BKE_volume_new_for_eval(volume);
|
||||
}
|
||||
Volume *volume_eval = volume_evaluate_modifiers(depsgraph, scene, object, volume);
|
||||
|
||||
/* Assign evaluated object. */
|
||||
const bool eval_is_owned = (volume != volume_eval);
|
||||
BKE_object_eval_assign_data(object, &volume_eval->id, eval_is_owned);
|
||||
object->runtime.geometry_set_eval = new GeometrySet(std::move(geometry_set));
|
||||
const bool is_owned = (volume != volume_eval);
|
||||
BKE_object_eval_assign_data(object, &volume_eval->id, is_owned);
|
||||
}
|
||||
|
||||
void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, const char *filepath)
|
||||
|
@@ -98,10 +98,3 @@
|
||||
#else
|
||||
# define ATTR_ALIGN(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
/* Alignment directive */
|
||||
#ifdef _WIN64
|
||||
# define ALIGN_STRUCT __declspec(align(64))
|
||||
#else
|
||||
# define ALIGN_STRUCT
|
||||
#endif
|
||||
|
@@ -247,11 +247,11 @@ class Map {
|
||||
{
|
||||
this->add_new_as(std::move(key), std::move(value));
|
||||
}
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
void add_new_as(ForwardKey &&key, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
void add_new_as(ForwardKey &&key, ForwardValue &&value)
|
||||
{
|
||||
this->add_new__impl(
|
||||
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
|
||||
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,11 +277,11 @@ class Map {
|
||||
{
|
||||
return this->add_as(std::move(key), std::move(value));
|
||||
}
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
bool add_as(ForwardKey &&key, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
bool add_as(ForwardKey &&key, ForwardValue &&value)
|
||||
{
|
||||
return this->add__impl(
|
||||
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
|
||||
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,11 +307,11 @@ class Map {
|
||||
{
|
||||
return this->add_overwrite_as(std::move(key), std::move(value));
|
||||
}
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&value)
|
||||
{
|
||||
return this->add_overwrite__impl(
|
||||
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
|
||||
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -413,12 +413,12 @@ class Map {
|
||||
{
|
||||
return this->pop_default_as(key, std::move(default_value));
|
||||
}
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
Value pop_default_as(const ForwardKey &key, ForwardValue &&... default_value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
Value pop_default_as(const ForwardKey &key, ForwardValue &&default_value)
|
||||
{
|
||||
Slot *slot = this->lookup_slot_ptr(key, hash_(key));
|
||||
if (slot == nullptr) {
|
||||
return Value(std::forward<ForwardValue>(default_value)...);
|
||||
return std::forward<ForwardValue>(default_value);
|
||||
}
|
||||
Value value = std::move(*slot->value());
|
||||
slot->remove();
|
||||
@@ -525,15 +525,15 @@ class Map {
|
||||
{
|
||||
return this->lookup_default_as(key, default_value);
|
||||
}
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
Value lookup_default_as(const ForwardKey &key, ForwardValue &&... default_value) const
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
Value lookup_default_as(const ForwardKey &key, ForwardValue &&default_value) const
|
||||
{
|
||||
const Value *ptr = this->lookup_ptr_as(key);
|
||||
if (ptr != nullptr) {
|
||||
return *ptr;
|
||||
}
|
||||
else {
|
||||
return Value(std::forward<ForwardValue>(default_value)...);
|
||||
return std::forward<ForwardValue>(default_value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,11 +557,11 @@ class Map {
|
||||
{
|
||||
return this->lookup_or_add_as(std::move(key), std::move(value));
|
||||
}
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&value)
|
||||
{
|
||||
return this->lookup_or_add__impl(
|
||||
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
|
||||
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -982,7 +982,7 @@ class Map {
|
||||
SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
|
||||
Slot &slot = new_slots[slot_index];
|
||||
if (slot.is_empty()) {
|
||||
slot.occupy(std::move(*old_slot.key()), hash, std::move(*old_slot.value()));
|
||||
slot.occupy(std::move(*old_slot.key()), std::move(*old_slot.value()), hash);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -996,8 +996,8 @@ class Map {
|
||||
new (this) Map(NoExceptConstructor(), allocator);
|
||||
}
|
||||
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
void add_new__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
void add_new__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
|
||||
{
|
||||
BLI_assert(!this->contains_as(key));
|
||||
|
||||
@@ -1005,7 +1005,7 @@ class Map {
|
||||
|
||||
MAP_SLOT_PROBING_BEGIN (hash, slot) {
|
||||
if (slot.is_empty()) {
|
||||
slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
|
||||
slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
|
||||
occupied_and_removed_slots_++;
|
||||
return;
|
||||
}
|
||||
@@ -1013,14 +1013,14 @@ class Map {
|
||||
MAP_SLOT_PROBING_END();
|
||||
}
|
||||
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
bool add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
bool add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
|
||||
{
|
||||
this->ensure_can_add();
|
||||
|
||||
MAP_SLOT_PROBING_BEGIN (hash, slot) {
|
||||
if (slot.is_empty()) {
|
||||
slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
|
||||
slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
|
||||
occupied_and_removed_slots_++;
|
||||
return true;
|
||||
}
|
||||
@@ -1075,7 +1075,7 @@ class Map {
|
||||
|
||||
MAP_SLOT_PROBING_BEGIN (hash, slot) {
|
||||
if (slot.is_empty()) {
|
||||
slot.occupy(std::forward<ForwardKey>(key), hash, create_value());
|
||||
slot.occupy(std::forward<ForwardKey>(key), create_value(), hash);
|
||||
occupied_and_removed_slots_++;
|
||||
return *slot.value();
|
||||
}
|
||||
@@ -1086,14 +1086,14 @@ class Map {
|
||||
MAP_SLOT_PROBING_END();
|
||||
}
|
||||
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
Value &lookup_or_add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
Value &lookup_or_add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
|
||||
{
|
||||
this->ensure_can_add();
|
||||
|
||||
MAP_SLOT_PROBING_BEGIN (hash, slot) {
|
||||
if (slot.is_empty()) {
|
||||
slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
|
||||
slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
|
||||
occupied_and_removed_slots_++;
|
||||
return *slot.value();
|
||||
}
|
||||
@@ -1104,15 +1104,15 @@ class Map {
|
||||
MAP_SLOT_PROBING_END();
|
||||
}
|
||||
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
bool add_overwrite__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
bool add_overwrite__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
|
||||
{
|
||||
auto create_func = [&](Value *ptr) {
|
||||
new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value)...);
|
||||
new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value));
|
||||
return true;
|
||||
};
|
||||
auto modify_func = [&](Value *ptr) {
|
||||
*ptr = Value(std::forward<ForwardValue>(value)...);
|
||||
*ptr = std::forward<ForwardValue>(value);
|
||||
return false;
|
||||
};
|
||||
return this->add_or_modify__impl(
|
||||
@@ -1221,18 +1221,16 @@ template<typename Key, typename Value> class StdUnorderedMapWrapper {
|
||||
map_.reserve(n);
|
||||
}
|
||||
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
void add_new(ForwardKey &&key, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
void add_new(ForwardKey &&key, ForwardValue &&value)
|
||||
{
|
||||
map_.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)});
|
||||
map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)});
|
||||
}
|
||||
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
bool add(ForwardKey &&key, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
bool add(ForwardKey &&key, ForwardValue &&value)
|
||||
{
|
||||
return map_
|
||||
.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)})
|
||||
.second;
|
||||
return map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)}).second;
|
||||
}
|
||||
|
||||
bool contains(const Key &key) const
|
||||
|
@@ -195,11 +195,11 @@ template<typename Key, typename Value> class SimpleMapSlot {
|
||||
* Change the state of this slot from empty/removed to occupied. The key/value has to be
|
||||
* constructed by calling the constructor with the given key/value as parameter.
|
||||
*/
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
|
||||
{
|
||||
BLI_assert(!this->is_occupied());
|
||||
new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
|
||||
new (&value_buffer_) Value(std::forward<ForwardValue>(value));
|
||||
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
|
||||
state_ = Occupied;
|
||||
}
|
||||
@@ -315,12 +315,12 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
|
||||
return is_equal(key, key_);
|
||||
}
|
||||
|
||||
template<typename ForwardKey, typename... ForwardValue>
|
||||
void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
|
||||
template<typename ForwardKey, typename ForwardValue>
|
||||
void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
|
||||
{
|
||||
BLI_assert(!this->is_occupied());
|
||||
BLI_assert(KeyInfo::is_not_empty_or_removed(key));
|
||||
new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
|
||||
new (&value_buffer_) Value(std::forward<ForwardValue>(value));
|
||||
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
|
||||
}
|
||||
|
||||
|
@@ -94,7 +94,7 @@ template<typename T> class Span {
|
||||
using iterator = const T *;
|
||||
using size_type = int64_t;
|
||||
|
||||
protected:
|
||||
private:
|
||||
const T *data_ = nullptr;
|
||||
int64_t size_ = 0;
|
||||
|
||||
@@ -477,7 +477,7 @@ template<typename T> class MutableSpan {
|
||||
using iterator = T *;
|
||||
using size_type = int64_t;
|
||||
|
||||
protected:
|
||||
private:
|
||||
T *data_;
|
||||
int64_t size_;
|
||||
|
||||
|
@@ -232,14 +232,13 @@ class Stack {
|
||||
{
|
||||
this->push_as(std::move(value));
|
||||
}
|
||||
/* This is similar to `std::stack::emplace`. */
|
||||
template<typename... ForwardT> void push_as(ForwardT &&... value)
|
||||
template<typename ForwardT> void push_as(ForwardT &&value)
|
||||
{
|
||||
if (top_ == top_chunk_->capacity_end) {
|
||||
this->activate_next_chunk(1);
|
||||
}
|
||||
try {
|
||||
new (top_) T(std::forward<ForwardT>(value)...);
|
||||
new (top_) T(std::forward<ForwardT>(value));
|
||||
top_++;
|
||||
size_++;
|
||||
}
|
||||
|
@@ -68,11 +68,6 @@ char *BLI_str_replaceN(const char *__restrict str,
|
||||
|
||||
void BLI_str_replace_char(char *string, char src, char dst) ATTR_NONNULL();
|
||||
|
||||
bool BLI_str_replace_table_exact(char *string,
|
||||
const size_t string_len,
|
||||
const char *replace_table[][2],
|
||||
int replace_table_len);
|
||||
|
||||
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
|
||||
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
|
||||
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
|
||||
|
@@ -437,17 +437,13 @@ class Vector {
|
||||
*/
|
||||
void append(const T &value)
|
||||
{
|
||||
this->append_as(value);
|
||||
this->ensure_space_for_one();
|
||||
this->append_unchecked(value);
|
||||
}
|
||||
void append(T &&value)
|
||||
{
|
||||
this->append_as(std::move(value));
|
||||
}
|
||||
/* This is similar to `std::vector::emplace_back`. */
|
||||
template<typename... ForwardValue> void append_as(ForwardValue &&... value)
|
||||
{
|
||||
this->ensure_space_for_one();
|
||||
this->append_unchecked_as(std::forward<ForwardValue>(value)...);
|
||||
this->append_unchecked(std::move(value));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -478,18 +474,10 @@ class Vector {
|
||||
* behavior when not enough capacity has been reserved beforehand. Only use this in performance
|
||||
* critical code.
|
||||
*/
|
||||
void append_unchecked(const T &value)
|
||||
{
|
||||
this->append_unchecked_as(value);
|
||||
}
|
||||
void append_unchecked(T &&value)
|
||||
{
|
||||
this->append_unchecked_as(std::move(value));
|
||||
}
|
||||
template<typename... ForwardT> void append_unchecked_as(ForwardT &&... value)
|
||||
template<typename ForwardT> void append_unchecked(ForwardT &&value)
|
||||
{
|
||||
BLI_assert(end_ < capacity_end_);
|
||||
new (end_) T(std::forward<ForwardT>(value)...);
|
||||
new (end_) T(std::forward<ForwardT>(value));
|
||||
end_++;
|
||||
UPDATE_VECTOR_SIZE(this);
|
||||
}
|
||||
|
@@ -37,7 +37,6 @@
|
||||
* see of the increased compile time and binary size is worth it.
|
||||
*/
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
namespace blender {
|
||||
@@ -72,11 +71,6 @@ template<typename T> class VArray {
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
IndexRange index_range() const
|
||||
{
|
||||
return IndexRange(size_);
|
||||
}
|
||||
|
||||
/* Returns true when the virtual array is stored as a span internally. */
|
||||
bool is_span() const
|
||||
{
|
||||
@@ -88,13 +82,13 @@ template<typename T> class VArray {
|
||||
|
||||
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
|
||||
* virtual array is not stored as a span internally. */
|
||||
Span<T> get_internal_span() const
|
||||
Span<T> get_span() const
|
||||
{
|
||||
BLI_assert(this->is_span());
|
||||
if (size_ == 0) {
|
||||
return {};
|
||||
}
|
||||
return this->get_internal_span_impl();
|
||||
return this->get_span_impl();
|
||||
}
|
||||
|
||||
/* Returns true when the virtual array returns the same value for every index. */
|
||||
@@ -108,35 +102,20 @@ template<typename T> class VArray {
|
||||
|
||||
/* Returns the value that is returned for every index. This invokes undefined behavior if the
|
||||
* virtual array would not return the same value for every index. */
|
||||
T get_internal_single() const
|
||||
T get_single() const
|
||||
{
|
||||
BLI_assert(this->is_single());
|
||||
if (size_ == 1) {
|
||||
return this->get(0);
|
||||
}
|
||||
return this->get_internal_single_impl();
|
||||
return this->get_single_impl();
|
||||
}
|
||||
|
||||
/* Get the element at a specific index. Note that this operator cannot be used to assign values
|
||||
* to an index, because the return value is not a reference. */
|
||||
T operator[](const int64_t index) const
|
||||
{
|
||||
return this->get(index);
|
||||
}
|
||||
|
||||
/* Copy the entire virtual array into a span. */
|
||||
void materialize(MutableSpan<T> r_span) const
|
||||
{
|
||||
BLI_assert(size_ == r_span.size());
|
||||
this->materialize_impl(r_span);
|
||||
}
|
||||
|
||||
void materialize_to_uninitialized(MutableSpan<T> r_span) const
|
||||
{
|
||||
BLI_assert(size_ == r_span.size());
|
||||
this->materialize_to_uninitialized_impl(r_span);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual T get_impl(const int64_t index) const = 0;
|
||||
|
||||
@@ -145,7 +124,7 @@ template<typename T> class VArray {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Span<T> get_internal_span_impl() const
|
||||
virtual Span<T> get_span_impl() const
|
||||
{
|
||||
BLI_assert_unreachable();
|
||||
return {};
|
||||
@@ -156,201 +135,56 @@ template<typename T> class VArray {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual T get_internal_single_impl() const
|
||||
virtual T get_single_impl() const
|
||||
{
|
||||
/* Provide a default implementation, so that subclasses don't have to provide it. This method
|
||||
* should never be called because `is_single_impl` returns false by default. */
|
||||
BLI_assert_unreachable();
|
||||
return T();
|
||||
}
|
||||
|
||||
virtual void materialize_impl(MutableSpan<T> r_span) const
|
||||
{
|
||||
if (this->is_span()) {
|
||||
const Span<T> span = this->get_internal_span();
|
||||
initialized_copy_n(span.data(), size_, r_span.data());
|
||||
}
|
||||
else if (this->is_single()) {
|
||||
const T single = this->get_internal_single();
|
||||
initialized_fill_n(r_span.data(), size_, single);
|
||||
}
|
||||
else {
|
||||
const int64_t size = size_;
|
||||
for (int64_t i = 0; i < size; i++) {
|
||||
r_span[i] = this->get(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void materialize_to_uninitialized_impl(MutableSpan<T> r_span) const
|
||||
{
|
||||
if (this->is_span()) {
|
||||
const Span<T> span = this->get_internal_span();
|
||||
uninitialized_copy_n(span.data(), size_, r_span.data());
|
||||
}
|
||||
else if (this->is_single()) {
|
||||
const T single = this->get_internal_single();
|
||||
uninitialized_fill_n(r_span.data(), size_, single);
|
||||
}
|
||||
else {
|
||||
const int64_t size = size_;
|
||||
T *dst = r_span.data();
|
||||
for (int64_t i = 0; i < size; i++) {
|
||||
new (dst + i) T(this->get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Similar to VArray, but the elements are mutable. */
|
||||
template<typename T> class VMutableArray : public VArray<T> {
|
||||
public:
|
||||
VMutableArray(const int64_t size) : VArray<T>(size)
|
||||
{
|
||||
}
|
||||
|
||||
void set(const int64_t index, T value)
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
BLI_assert(index < this->size_);
|
||||
this->set_impl(index, std::move(value));
|
||||
}
|
||||
|
||||
/* Copy the values from the source span to all elements in the virtual array. */
|
||||
void set_all(Span<T> src)
|
||||
{
|
||||
BLI_assert(src.size() == this->size_);
|
||||
this->set_all_impl(src);
|
||||
}
|
||||
|
||||
MutableSpan<T> get_internal_span()
|
||||
{
|
||||
BLI_assert(this->is_span());
|
||||
Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span();
|
||||
return MutableSpan<T>(const_cast<T *>(span.data()), span.size());
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void set_impl(const int64_t index, T value) = 0;
|
||||
|
||||
virtual void set_all_impl(Span<T> src)
|
||||
{
|
||||
if (this->is_span()) {
|
||||
const MutableSpan<T> span = this->get_internal_span();
|
||||
initialized_copy_n(src.data(), this->size_, span.data());
|
||||
}
|
||||
else {
|
||||
const int64_t size = this->size_;
|
||||
for (int64_t i = 0; i < size; i++) {
|
||||
this->set(i, src[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>;
|
||||
template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>;
|
||||
|
||||
/**
|
||||
* A virtual array implementation for a span. Methods in this class are final so that it can be
|
||||
* devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used).
|
||||
* A virtual array implementation for a span. This class is final so that it can be devirtualized
|
||||
* by the compiler in some cases (e.g. when #devirtualize_varray is used).
|
||||
*/
|
||||
template<typename T> class VArray_For_Span : public VArray<T> {
|
||||
protected:
|
||||
const T *data_ = nullptr;
|
||||
template<typename T> class VArrayForSpan final : public VArray<T> {
|
||||
private:
|
||||
const T *data_;
|
||||
|
||||
public:
|
||||
VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
|
||||
VArrayForSpan(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
VArray_For_Span(const int64_t size) : VArray<T>(size)
|
||||
{
|
||||
}
|
||||
|
||||
T get_impl(const int64_t index) const final
|
||||
T get_impl(const int64_t index) const override
|
||||
{
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
bool is_span_impl() const final
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Span<T> get_internal_span_impl() const final
|
||||
{
|
||||
return Span<T>(data_, this->size_);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> {
|
||||
protected:
|
||||
T *data_ = nullptr;
|
||||
|
||||
public:
|
||||
VMutableArray_For_MutableSpan(const MutableSpan<T> data)
|
||||
: VMutableArray<T>(data.size()), data_(data.data())
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size)
|
||||
{
|
||||
}
|
||||
|
||||
T get_impl(const int64_t index) const final
|
||||
{
|
||||
return data_[index];
|
||||
}
|
||||
|
||||
void set_impl(const int64_t index, T value) final
|
||||
{
|
||||
data_[index] = value;
|
||||
}
|
||||
|
||||
bool is_span_impl() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Span<T> get_internal_span_impl() const override
|
||||
Span<T> get_span_impl() const override
|
||||
{
|
||||
return Span<T>(data_, this->size_);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A variant of `VArray_For_Span` that owns the underlying data.
|
||||
* The `Container` type has to implement a `size()` and `data()` method.
|
||||
* The `data()` method has to return a pointer to the first element in the continuous array of
|
||||
* elements.
|
||||
*/
|
||||
template<typename Container, typename T = typename Container::value_type>
|
||||
class VArray_For_ArrayContainer : public VArray_For_Span<T> {
|
||||
private:
|
||||
Container container_;
|
||||
|
||||
public:
|
||||
VArray_For_ArrayContainer(Container container)
|
||||
: VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container))
|
||||
{
|
||||
this->data_ = container_.data();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A virtual array implementation that returns the same value for every index. This class is final
|
||||
* so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is
|
||||
* used).
|
||||
*/
|
||||
template<typename T> class VArray_For_Single final : public VArray<T> {
|
||||
template<typename T> class VArrayForSingle final : public VArray<T> {
|
||||
private:
|
||||
T value_;
|
||||
|
||||
public:
|
||||
VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
|
||||
VArrayForSingle(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -365,7 +199,7 @@ template<typename T> class VArray_For_Single final : public VArray<T> {
|
||||
return this->size_ == 1;
|
||||
}
|
||||
|
||||
Span<T> get_internal_span_impl() const override
|
||||
Span<T> get_span_impl() const override
|
||||
{
|
||||
return Span<T>(&value_, 1);
|
||||
}
|
||||
@@ -375,170 +209,12 @@ template<typename T> class VArray_For_Single final : public VArray<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
T get_internal_single_impl() const override
|
||||
T get_single_impl() const override
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* In many cases a virtual array is a span internally. In those cases, access to individual could
|
||||
* be much more efficient than calling a virtual method. When the underlying virtual array is not a
|
||||
* span, this class allocates a new array and copies the values over.
|
||||
*
|
||||
* This should be used in those cases:
|
||||
* - All elements in the virtual array are accessed multiple times.
|
||||
* - In most cases, the underlying virtual array is a span, so no copy is necessary to benefit
|
||||
* from faster access.
|
||||
* - An API is called, that does not accept virtual arrays, but only spans.
|
||||
*/
|
||||
template<typename T> class VArray_Span final : public Span<T> {
|
||||
private:
|
||||
const VArray<T> &varray_;
|
||||
Array<T> owned_data_;
|
||||
|
||||
public:
|
||||
VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray)
|
||||
{
|
||||
this->size_ = varray_.size();
|
||||
if (varray_.is_span()) {
|
||||
this->data_ = varray_.get_internal_span().data();
|
||||
}
|
||||
else {
|
||||
owned_data_.~Array();
|
||||
new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
|
||||
varray_.materialize_to_uninitialized(owned_data_);
|
||||
this->data_ = owned_data_.data();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as VArray_Span, but for a mutable span.
|
||||
* The important thing to note is that when changing this span, the results might not be
|
||||
* immediately reflected in the underlying virtual array (only when the virtual array is a span
|
||||
* internally). The #save method can be used to write all changes to the underlying virtual array,
|
||||
* if necessary.
|
||||
*/
|
||||
template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
|
||||
private:
|
||||
VMutableArray<T> &varray_;
|
||||
Array<T> owned_data_;
|
||||
bool save_has_been_called_ = false;
|
||||
bool show_not_saved_warning_ = true;
|
||||
|
||||
public:
|
||||
/* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If
|
||||
* not, a new array has to be allocated as a wrapper for the underlying virtual array. */
|
||||
VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true)
|
||||
: MutableSpan<T>(), varray_(varray)
|
||||
{
|
||||
this->size_ = varray_.size();
|
||||
if (varray_.is_span()) {
|
||||
this->data_ = varray_.get_internal_span().data();
|
||||
}
|
||||
else {
|
||||
if (copy_values_to_span) {
|
||||
owned_data_.~Array();
|
||||
new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
|
||||
varray_.materialize_to_uninitialized(owned_data_);
|
||||
}
|
||||
else {
|
||||
owned_data_.reinitialize(varray_.size());
|
||||
}
|
||||
this->data_ = owned_data_.data();
|
||||
}
|
||||
}
|
||||
|
||||
~VMutableArray_Span()
|
||||
{
|
||||
if (show_not_saved_warning_) {
|
||||
if (!save_has_been_called_) {
|
||||
std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Write back all values from a temporary allocated array to the underlying virtual array. */
|
||||
void save()
|
||||
{
|
||||
save_has_been_called_ = true;
|
||||
if (this->data_ != owned_data_.data()) {
|
||||
return;
|
||||
}
|
||||
varray_.set_all(owned_data_);
|
||||
}
|
||||
|
||||
void disable_not_applied_warning()
|
||||
{
|
||||
show_not_saved_warning_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class makes it easy to create a virtual array for an existing function or lambda. The
|
||||
* `GetFunc` should take a single `index` argument and return the value at that index.
|
||||
*/
|
||||
template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> {
|
||||
private:
|
||||
GetFunc get_func_;
|
||||
|
||||
public:
|
||||
VArray_For_Func(const int64_t size, GetFunc get_func)
|
||||
: VArray<T>(size), get_func_(std::move(get_func))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
T get_impl(const int64_t index) const override
|
||||
{
|
||||
return get_func_(index);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
|
||||
class VArray_For_DerivedSpan : public VArray<ElemT> {
|
||||
private:
|
||||
const StructT *data_;
|
||||
|
||||
public:
|
||||
VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data())
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
ElemT get_impl(const int64_t index) const override
|
||||
{
|
||||
return GetFunc(data_[index]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename StructT,
|
||||
typename ElemT,
|
||||
ElemT (*GetFunc)(const StructT &),
|
||||
void (*SetFunc)(StructT &, ElemT)>
|
||||
class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> {
|
||||
private:
|
||||
StructT *data_;
|
||||
|
||||
public:
|
||||
VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
|
||||
: VMutableArray<ElemT>(data.size()), data_(data.data())
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
ElemT get_impl(const int64_t index) const override
|
||||
{
|
||||
return GetFunc(data_[index]);
|
||||
}
|
||||
|
||||
void set_impl(const int64_t index, ElemT value) override
|
||||
{
|
||||
SetFunc(data_[index], std::move(value));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate multiple versions of the given function optimized for different virtual arrays.
|
||||
* One has to be careful with nesting multiple devirtualizations, because that results in an
|
||||
@@ -553,14 +229,14 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool
|
||||
/* Support disabling the devirtualization to simplify benchmarking. */
|
||||
if (enable) {
|
||||
if (varray.is_single()) {
|
||||
/* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */
|
||||
const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()};
|
||||
/* `VArrayForSingle` can be used for devirtualization, because it is declared `final`. */
|
||||
const VArrayForSingle<T> varray_single{varray.get_single(), varray.size()};
|
||||
func(varray_single);
|
||||
return;
|
||||
}
|
||||
if (varray.is_span()) {
|
||||
/* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */
|
||||
const VArray_For_Span<T> varray_span{varray.get_internal_span()};
|
||||
/* `VArrayForSpan` can be used for devirtualization, because it is declared `final`. */
|
||||
const VArrayForSpan<T> varray_span{varray.get_span()};
|
||||
func(varray_span);
|
||||
return;
|
||||
}
|
||||
@@ -586,26 +262,26 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
|
||||
const bool is_single1 = varray1.is_single();
|
||||
const bool is_single2 = varray2.is_single();
|
||||
if (is_span1 && is_span2) {
|
||||
const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
|
||||
const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
|
||||
const VArrayForSpan<T1> varray1_span{varray1.get_span()};
|
||||
const VArrayForSpan<T2> varray2_span{varray2.get_span()};
|
||||
func(varray1_span, varray2_span);
|
||||
return;
|
||||
}
|
||||
if (is_span1 && is_single2) {
|
||||
const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
|
||||
const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
|
||||
const VArrayForSpan<T1> varray1_span{varray1.get_span()};
|
||||
const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
|
||||
func(varray1_span, varray2_single);
|
||||
return;
|
||||
}
|
||||
if (is_single1 && is_span2) {
|
||||
const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
|
||||
const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
|
||||
const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
|
||||
const VArrayForSpan<T2> varray2_span{varray2.get_span()};
|
||||
func(varray1_single, varray2_span);
|
||||
return;
|
||||
}
|
||||
if (is_single1 && is_single2) {
|
||||
const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
|
||||
const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
|
||||
const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
|
||||
const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
|
||||
func(varray1_single, varray2_single);
|
||||
return;
|
||||
}
|
||||
|
@@ -2684,12 +2684,6 @@ static IMesh raycast_patches_boolean(const IMesh &tm,
|
||||
return ans;
|
||||
}
|
||||
|
||||
# ifdef fast_triangulate
|
||||
/* This code uses Blenlib's BLI_polyfill_calc to do triangulation, and is therefore quite fast.
|
||||
* Unfortunately, it can product degenerate triangles that mesh_intersect will remove, leaving
|
||||
* the mesh non-PWN.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tessellate face f into triangles and return an array of `const Face *`
|
||||
* giving that triangulation. Intended to be used when f has > 4 vertices.
|
||||
@@ -2751,98 +2745,6 @@ static Array<Face *> triangulate_poly(Face *f, IMeshArena *arena)
|
||||
|
||||
return ans;
|
||||
}
|
||||
# else
|
||||
/**
|
||||
* Which CDT output edge index is for an edge between output verts
|
||||
* v1 and v2 (in either order)?
|
||||
* \return -1 if none.
|
||||
*/
|
||||
static int find_cdt_edge(const CDT_result<mpq_class> &cdt_out, int v1, int v2)
|
||||
{
|
||||
for (int e : cdt_out.edge.index_range()) {
|
||||
const std::pair<int, int> &edge = cdt_out.edge[e];
|
||||
if ((edge.first == v1 && edge.second == v2) || (edge.first == v2 && edge.second == v1)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tessellate face f into triangles and return an array of `const Face *`
|
||||
* giving that triangulation.
|
||||
* Care is taken so that the original edge index associated with
|
||||
* each edge in the output triangles either matches the original edge
|
||||
* for the (identical) edge of f, or else is -1. So diagonals added
|
||||
* for triangulation can later be identified by having #NO_INDEX for original.
|
||||
*/
|
||||
static Array<Face *> triangulate_poly(Face *f, IMeshArena *arena)
|
||||
{
|
||||
int flen = f->size();
|
||||
CDT_input<mpq_class> cdt_in;
|
||||
cdt_in.vert = Array<mpq2>(flen);
|
||||
cdt_in.face = Array<Vector<int>>(1);
|
||||
cdt_in.face[0].reserve(flen);
|
||||
for (int i : f->index_range()) {
|
||||
cdt_in.face[0].append(i);
|
||||
}
|
||||
/* Project poly along dominant axis of normal to get 2d coords. */
|
||||
if (!f->plane_populated()) {
|
||||
f->populate_plane(false);
|
||||
}
|
||||
const double3 &poly_normal = f->plane->norm;
|
||||
int axis = double3::dominant_axis(poly_normal);
|
||||
/* If project down y axis as opposed to x or z, the orientation
|
||||
* of the polygon will be reversed.
|
||||
* Yet another reversal happens if the poly normal in the dominant
|
||||
* direction is opposite that of the positive dominant axis. */
|
||||
bool rev1 = (axis == 1);
|
||||
bool rev2 = poly_normal[axis] < 0;
|
||||
bool rev = rev1 ^ rev2;
|
||||
for (int i = 0; i < flen; ++i) {
|
||||
int ii = rev ? flen - i - 1 : i;
|
||||
mpq2 &p2d = cdt_in.vert[ii];
|
||||
int k = 0;
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
if (j != axis) {
|
||||
p2d[k++] = (*f)[ii]->co_exact[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
CDT_result<mpq_class> cdt_out = delaunay_2d_calc(cdt_in, CDT_INSIDE);
|
||||
int n_tris = cdt_out.face.size();
|
||||
Array<Face *> ans(n_tris);
|
||||
for (int t = 0; t < n_tris; ++t) {
|
||||
int i_v_out[3];
|
||||
const Vert *v[3];
|
||||
int eo[3];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
i_v_out[i] = cdt_out.face[t][i];
|
||||
v[i] = (*f)[cdt_out.vert_orig[i_v_out[i]][0]];
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int e_out = find_cdt_edge(cdt_out, i_v_out[i], i_v_out[(i + 1) % 3]);
|
||||
BLI_assert(e_out != -1);
|
||||
eo[i] = NO_INDEX;
|
||||
for (int orig : cdt_out.edge_orig[e_out]) {
|
||||
if (orig != NO_INDEX) {
|
||||
eo[i] = orig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rev) {
|
||||
ans[t] = arena->add_face(
|
||||
{v[0], v[2], v[1]}, f->orig, {eo[2], eo[1], eo[0]}, {false, false, false});
|
||||
}
|
||||
else {
|
||||
ans[t] = arena->add_face(
|
||||
{v[0], v[1], v[2]}, f->orig, {eo[0], eo[1], eo[2]}, {false, false, false});
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
# endif
|
||||
|
||||
/**
|
||||
* Return an #IMesh that is a triangulation of a mesh with general
|
||||
|
@@ -539,29 +539,6 @@ void BLI_str_replace_char(char *str, char src, char dst)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple exact-match string replacement.
|
||||
*
|
||||
* \param replace_table: Array of source, destination pairs.
|
||||
*
|
||||
* \note Larger tables should use a hash table.
|
||||
*/
|
||||
bool BLI_str_replace_table_exact(char *string,
|
||||
const size_t string_len,
|
||||
const char *replace_table[][2],
|
||||
int replace_table_len)
|
||||
{
|
||||
for (int i = 0; i < replace_table_len; i++) {
|
||||
if (STREQ(string, replace_table[i][0])) {
|
||||
BLI_strncpy(string, replace_table[i][1], string_len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/**
|
||||
* Compare two strings without regard to case.
|
||||
*
|
||||
|
@@ -604,15 +604,6 @@ TEST(map, GenericAlgorithms)
|
||||
EXPECT_EQ(std::count(map.keys().begin(), map.keys().end(), 7), 1);
|
||||
}
|
||||
|
||||
TEST(map, AddAsVariadic)
|
||||
{
|
||||
Map<int, StringRef> map;
|
||||
map.add_as(3, "hello", 2);
|
||||
map.add_as(2, "test", 1);
|
||||
EXPECT_EQ(map.lookup(3), "he");
|
||||
EXPECT_EQ(map.lookup(2), "t");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
|
||||
*/
|
||||
|
@@ -93,15 +93,6 @@ TEST(stack, Push)
|
||||
EXPECT_EQ(stack.size(), 2);
|
||||
}
|
||||
|
||||
TEST(stack, PushAs)
|
||||
{
|
||||
Stack<StringRef> stack;
|
||||
stack.push_as("hello", 3);
|
||||
stack.push_as("world", 1);
|
||||
EXPECT_EQ(stack.pop(), "w");
|
||||
EXPECT_EQ(stack.pop(), "hel");
|
||||
}
|
||||
|
||||
TEST(stack, PushMultiple)
|
||||
{
|
||||
Stack<int> stack;
|
||||
|
@@ -248,15 +248,6 @@ TEST(vector, Append)
|
||||
EXPECT_EQ(vec[2], 7);
|
||||
}
|
||||
|
||||
TEST(vector, AppendAs)
|
||||
{
|
||||
Vector<StringRef> vec;
|
||||
vec.append_as("hello", 2);
|
||||
vec.append_as("world", 3);
|
||||
EXPECT_EQ(vec[0], "he");
|
||||
EXPECT_EQ(vec[1], "wor");
|
||||
}
|
||||
|
||||
TEST(vector, AppendAndGetIndex)
|
||||
{
|
||||
Vector<int> vec;
|
||||
|
@@ -1,29 +1,26 @@
|
||||
/* Apache License, Version 2.0 */
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_strict_flags.h"
|
||||
#include "BLI_vector.hh"
|
||||
#include "BLI_vector_set.hh"
|
||||
#include "BLI_virtual_array.hh"
|
||||
#include "testing/testing.h"
|
||||
|
||||
namespace blender::tests {
|
||||
|
||||
TEST(virtual_array, Span)
|
||||
TEST(virtual_array, ForSpan)
|
||||
{
|
||||
std::array<int, 5> data = {3, 4, 5, 6, 7};
|
||||
VArray_For_Span<int> varray{data};
|
||||
VArrayForSpan<int> varray{data};
|
||||
EXPECT_EQ(varray.size(), 5);
|
||||
EXPECT_EQ(varray.get(0), 3);
|
||||
EXPECT_EQ(varray.get(4), 7);
|
||||
EXPECT_TRUE(varray.is_span());
|
||||
EXPECT_FALSE(varray.is_single());
|
||||
EXPECT_EQ(varray.get_internal_span().data(), data.data());
|
||||
EXPECT_EQ(varray.get_span().data(), data.data());
|
||||
}
|
||||
|
||||
TEST(virtual_array, Single)
|
||||
TEST(virtual_array, ForSingle)
|
||||
{
|
||||
VArray_For_Single<int> varray{10, 4};
|
||||
VArrayForSingle<int> varray{10, 4};
|
||||
EXPECT_EQ(varray.size(), 4);
|
||||
EXPECT_EQ(varray.get(0), 10);
|
||||
EXPECT_EQ(varray.get(3), 10);
|
||||
@@ -31,124 +28,4 @@ TEST(virtual_array, Single)
|
||||
EXPECT_TRUE(varray.is_single());
|
||||
}
|
||||
|
||||
TEST(virtual_array, Array)
|
||||
{
|
||||
Array<int> array = {1, 2, 3, 5, 8};
|
||||
{
|
||||
VArray_For_ArrayContainer varray{array};
|
||||
EXPECT_EQ(varray.size(), 5);
|
||||
EXPECT_EQ(varray[0], 1);
|
||||
EXPECT_EQ(varray[2], 3);
|
||||
EXPECT_EQ(varray[3], 5);
|
||||
EXPECT_TRUE(varray.is_span());
|
||||
}
|
||||
{
|
||||
VArray_For_ArrayContainer varray{std::move(array)};
|
||||
EXPECT_EQ(varray.size(), 5);
|
||||
EXPECT_EQ(varray[0], 1);
|
||||
EXPECT_EQ(varray[2], 3);
|
||||
EXPECT_EQ(varray[3], 5);
|
||||
EXPECT_TRUE(varray.is_span());
|
||||
}
|
||||
{
|
||||
VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */
|
||||
EXPECT_TRUE(varray.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(virtual_array, Vector)
|
||||
{
|
||||
Vector<int> vector = {9, 8, 7, 6};
|
||||
VArray_For_ArrayContainer varray{std::move(vector)};
|
||||
EXPECT_EQ(varray.size(), 4);
|
||||
EXPECT_EQ(varray[0], 9);
|
||||
EXPECT_EQ(varray[3], 6);
|
||||
}
|
||||
|
||||
TEST(virtual_array, StdVector)
|
||||
{
|
||||
std::vector<int> vector = {5, 6, 7, 8};
|
||||
VArray_For_ArrayContainer varray{std::move(vector)};
|
||||
EXPECT_EQ(varray.size(), 4);
|
||||
EXPECT_EQ(varray[0], 5);
|
||||
EXPECT_EQ(varray[1], 6);
|
||||
}
|
||||
|
||||
TEST(virtual_array, StdArray)
|
||||
{
|
||||
std::array<int, 4> array = {2, 3, 4, 5};
|
||||
VArray_For_ArrayContainer varray{array};
|
||||
EXPECT_EQ(varray.size(), 4);
|
||||
EXPECT_EQ(varray[0], 2);
|
||||
EXPECT_EQ(varray[1], 3);
|
||||
}
|
||||
|
||||
TEST(virtual_array, VectorSet)
|
||||
{
|
||||
VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1};
|
||||
VArray_For_ArrayContainer varray{std::move(vector_set)};
|
||||
EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */
|
||||
EXPECT_EQ(varray.size(), 4);
|
||||
EXPECT_EQ(varray[0], 5);
|
||||
EXPECT_EQ(varray[1], 3);
|
||||
EXPECT_EQ(varray[2], 7);
|
||||
EXPECT_EQ(varray[3], 1);
|
||||
}
|
||||
|
||||
TEST(virtual_array, Func)
|
||||
{
|
||||
auto func = [](int64_t index) { return (int)(index * index); };
|
||||
VArray_For_Func<int, decltype(func)> varray{10, func};
|
||||
EXPECT_EQ(varray.size(), 10);
|
||||
EXPECT_EQ(varray[0], 0);
|
||||
EXPECT_EQ(varray[3], 9);
|
||||
EXPECT_EQ(varray[9], 81);
|
||||
}
|
||||
|
||||
TEST(virtual_array, AsSpan)
|
||||
{
|
||||
auto func = [](int64_t index) { return (int)(10 * index); };
|
||||
VArray_For_Func<int, decltype(func)> func_varray{10, func};
|
||||
VArray_Span span_varray{func_varray};
|
||||
EXPECT_EQ(span_varray.size(), 10);
|
||||
Span<int> span = span_varray;
|
||||
EXPECT_EQ(span.size(), 10);
|
||||
EXPECT_EQ(span[0], 0);
|
||||
EXPECT_EQ(span[3], 30);
|
||||
EXPECT_EQ(span[6], 60);
|
||||
}
|
||||
|
||||
static int get_x(const std::array<int, 3> &item)
|
||||
{
|
||||
return item[0];
|
||||
}
|
||||
|
||||
static void set_x(std::array<int, 3> &item, int value)
|
||||
{
|
||||
item[0] = value;
|
||||
}
|
||||
|
||||
TEST(virtual_array, DerivedSpan)
|
||||
{
|
||||
Vector<std::array<int, 3>> vector;
|
||||
vector.append({3, 4, 5});
|
||||
vector.append({1, 1, 1});
|
||||
{
|
||||
VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector};
|
||||
EXPECT_EQ(varray.size(), 2);
|
||||
EXPECT_EQ(varray[0], 3);
|
||||
EXPECT_EQ(varray[1], 1);
|
||||
}
|
||||
{
|
||||
VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector};
|
||||
EXPECT_EQ(varray.size(), 2);
|
||||
EXPECT_EQ(varray[0], 3);
|
||||
EXPECT_EQ(varray[1], 1);
|
||||
varray.set(0, 10);
|
||||
varray.set(1, 20);
|
||||
EXPECT_EQ(vector[0][0], 10);
|
||||
EXPECT_EQ(vector[1][0], 20);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
@@ -226,10 +226,7 @@ int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64
|
||||
* Struct for temporarily loading datablocks from a blend file.
|
||||
*/
|
||||
typedef struct TempLibraryContext {
|
||||
/** Temporary main used for library data. */
|
||||
struct Main *bmain_lib;
|
||||
/** Temporary main used to load data into (currently initialized from `real_main`). */
|
||||
struct Main *bmain_base;
|
||||
struct Main *temp_main;
|
||||
struct BlendHandle *blendhandle;
|
||||
struct LibraryLink_Params liblink_params;
|
||||
struct Library *lib;
|
||||
|
@@ -57,7 +57,6 @@ set(SRC
|
||||
intern/versioning_270.c
|
||||
intern/versioning_280.c
|
||||
intern/versioning_290.c
|
||||
intern/versioning_300.c
|
||||
intern/versioning_cycles.c
|
||||
intern/versioning_defaults.c
|
||||
intern/versioning_dna.c
|
||||
|
@@ -3868,7 +3868,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
|
||||
blo_do_versions_270(fd, lib, main);
|
||||
blo_do_versions_280(fd, lib, main);
|
||||
blo_do_versions_290(fd, lib, main);
|
||||
blo_do_versions_300(fd, lib, main);
|
||||
blo_do_versions_cycles(fd, lib, main);
|
||||
|
||||
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
|
||||
@@ -3892,7 +3891,6 @@ static void do_versions_after_linking(Main *main, ReportList *reports)
|
||||
do_versions_after_linking_270(main);
|
||||
do_versions_after_linking_280(main, reports);
|
||||
do_versions_after_linking_290(main, reports);
|
||||
do_versions_after_linking_300(main, reports);
|
||||
do_versions_after_linking_cycles(main);
|
||||
|
||||
main->is_locked_for_linking = false;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user