1
1

Compare commits

..

1 Commits

Author SHA1 Message Date
Christoph Lendenfeld
60d1d13046 Pose Sliding tools improvements
### Executive Summary

This patch improves pose sliding tools: Breakdowner, Push, and Relax.

The problems with the old tools:
- **No UI**. Even though it's clear how the tool works when you move the mouse, there is no visual indication as to the actual scale of the movement required.
- **No mouse wrapping**. This means that you have to carefully plan the initial position of the mouse when using the tools, because that impacts which values are available. This makes it hard to use it from the menu, as that forces the mouse to be in a certain position.
- **No precision mode** by pressing shift.
- **No overshoot protection**, so it's very easy to go below 0% or above 100%.

These problems are **all solved in this patch**.

##### Demo video

Here {key Shift E} is used to start the Pose Breakdowner.

{F9929705}

### Original description

**Problem**
The existing Push, Relax and Breakdowner tools are great, but the fact that they use the whole area range is less than ideal.
In theory, the tools support going beyond 0% and 100% to create an overshoot, but since they use the whole are, you might be blocked by the edges of the screen.

**Solution**
Set a pixel value as defined distance from 0% to 100% (scales with gui)
To indicate that, draw a UI under the cursor.
The percentage is now calculated accumulative to enable precision support when holding SHIFT

Info about new modifier keys is printed to the workspace status
{F9891261}

Update 2020_10_12: All lines have outlines now and handle is orange for better readability on white.
Update 2021_01_18: Static indicators moved to bottom. tick spacing now every 10%
Update 2021_03_14: Remove the slider and replace with a simple percentage indicator. (Cursor not visible in screenshot)
Update 2021_04_11: Brought the slider back. Spawns centered at the bottom of the screen
{F9929709}

By default the percentage is clamped to 0-1. But by pressing E you can enable overshoot.
Update 2020_10_12: slider range in overshoot mode is now 150% to better indicate that it can go further
Update 2021_03_14: Since the slider was removed, the percentage amount is simply displayed under the cursor
Update 2021_04_11: Overshoot now scrolls in place
{F9929712}

**Limitations and future improvements**
As mentioned in the comments below it would be a good idea to write a more general version of the slider to be used in various areas of Blender.

**Build**
[[ https://blender.community/c/graphicall/dqbbbc/ | Windows build on graphicall ]]

**Edit**
Split off the operator into it's own patch D9137

Reviewed By: zeddb, brecht, Severin, looch

Maniphest Tasks: T81836

Differential Revision: https://developer.blender.org/D9054
2021-04-15 10:59:52 +02:00
282 changed files with 4524 additions and 8003 deletions

View File

@@ -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()

View File

@@ -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}"
)

View File

@@ -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"

View File

@@ -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}

View File

@@ -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")

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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"),

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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"

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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-* \

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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. */

View File

@@ -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;

View File

@@ -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 |

View File

@@ -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) {

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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";
}

View File

@@ -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.

View File

@@ -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)
# ------

View File

@@ -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:

View File

@@ -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()

View File

@@ -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:

View File

@@ -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"

View File

@@ -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):

View File

@@ -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")

View File

@@ -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,

View File

@@ -550,7 +550,6 @@ geometry_node_categories = [
NodeItem("ShaderNodeMath"),
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeFloatCompare"),
NodeItem("GeometryNodeSwitch"),
]),
GeometryNodeCategory("GEO_VECTOR", "Vector", items=[
NodeItem("ShaderNodeSeparateXYZ"),

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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

View 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. */

View File

@@ -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
*

View File

@@ -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;

View File

@@ -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 \

View File

@@ -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

View File

@@ -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
/** \} */

View File

@@ -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,

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();
}
/** \} */

View File

@@ -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;
};

View File

@@ -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,

View File

@@ -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 */

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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});
}

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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_;

View File

@@ -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_++;
}

View File

@@ -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, ...)

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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.
*/

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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