diff options
author | Falk David <falkdavid@gmx.de> | 2020-08-14 16:07:07 +0300 |
---|---|---|
committer | Falk David <falkdavid@gmx.de> | 2020-08-14 16:07:07 +0300 |
commit | b221d8d0a32a74d912cc0fa204565410eee95dcf (patch) | |
tree | 61f46d393ead7a2a492d40b3b958e105d9b1d8c1 | |
parent | a0152042b846887412c31df8ad4f779a2c400c1c (diff) | |
parent | 735c717a63c8870d2ef4a910d82a2648cbaaa5e1 (diff) |
Merge branch 'greasepencil-edit-curve' into soc-2020-greasepencil-curve
274 files changed, 6241 insertions, 4500 deletions
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index c26b90637c3..6415d270773 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -57,7 +57,6 @@ include(cmake/zlib.cmake) include(cmake/openal.cmake) include(cmake/png.cmake) include(cmake/jpeg.cmake) -include(cmake/boost.cmake) include(cmake/blosc.cmake) include(cmake/pthreads.cmake) include(cmake/openexr.cmake) @@ -89,6 +88,8 @@ include(cmake/python_site_packages.cmake) include(cmake/package_python.cmake) include(cmake/numpy.cmake) include(cmake/usd.cmake) +# Boost needs to be included after python.cmake due to the PYTHON_BINARY variable being needed. +include(cmake/boost.cmake) if(UNIX) # Rely on PugiXML compiled with OpenImageIO else() diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake index 6e7ee8c66b1..22b5f33e690 100644 --- a/build_files/build_environment/cmake/boost.cmake +++ b/build_files/build_environment/cmake/boost.cmake @@ -19,17 +19,6 @@ set(BOOST_ADDRESS_MODEL 64) if(WIN32) - if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - set(PYTHON_ARCH x64) - set(PYTHON_ARCH2 win-AMD64) - set(PYTHON_OUTPUTDIR ${BUILD_DIR}/python/src/external_python/pcbuild/amd64/) - else() - set(PYTHON_ARCH x86) - set(PYTHON_ARCH2 win32) - set(PYTHON_OUTPUTDIR ${BUILD_DIR}/python/src/external_python/pcbuild/win32/) - set(BOOST_ADDRESS_MODEL 32) - endif() - set(BOOST_TOOLSET toolset=msvc-14.1) set(BOOST_COMPILER_STRING -vc141) @@ -60,6 +49,15 @@ else() endif() endif() +if(WITH_BOOST_PYTHON) + set(JAM_FILE ${BUILD_DIR}/boost.user-config.jam) + configure_file(${PATCH_DIR}/boost.user.jam.in ${JAM_FILE}) + set(BOOST_PYTHON_OPTIONS + --with-python + --user-config=${JAM_FILE} + ) +endif() + set(BOOST_OPTIONS --with-filesystem --with-locale @@ -76,6 +74,7 @@ set(BOOST_OPTIONS -sNO_LZMA=1 -sNO_ZSTD=1 ${BOOST_TOOLSET} + ${BOOST_PYTHON_OPTIONS} ) string(TOLOWER ${BUILD_MODE} BOOST_BUILD_TYPE) @@ -92,3 +91,11 @@ ExternalProject_Add(external_boost BUILD_IN_SOURCE 1 INSTALL_COMMAND "${BOOST_HARVEST_CMD}" ) + +if(WITH_BOOST_PYTHON) + add_dependencies( + external_boost + external_python + external_numpy + ) +endif() diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake index fe2f1fa34e5..29e2ffc7ed8 100644 --- a/build_files/build_environment/cmake/options.cmake +++ b/build_files/build_environment/cmake/options.cmake @@ -20,6 +20,7 @@ if(WIN32) option(ENABLE_MINGW64 "Enable building of ffmpeg/iconv/libsndfile/fftw3 by installing mingw64" ON) endif() option(WITH_WEBP "Enable building of oiio with webp support" OFF) +option(WITH_BOOST_PYTHON "Enable building of boost with python support" OFF) set(MAKE_THREADS 1 CACHE STRING "Number of threads to run make with") if(NOT BUILD_MODE) @@ -195,18 +196,6 @@ set(DEFAULT_CMAKE_FLAGS ) if(WIN32) - # We need both flavors to build the thumbnail dlls - if(MSVC12) - set(GENERATOR_32 "Visual Studio 12 2013") - set(GENERATOR_64 "Visual Studio 12 2013 Win64") - elseif(MSVC14) - set(GENERATOR_32 "Visual Studio 14 2015") - set(GENERATOR_64 "Visual Studio 14 2015 Win64") - endif() -endif() - - -if(WIN32) if(BUILD_MODE STREQUAL Debug) set(ZLIB_LIBRARY zlibstaticd${LIBEXT}) else() diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake index 9cd56423941..bfb318f9939 100644 --- a/build_files/build_environment/cmake/python.cmake +++ b/build_files/build_environment/cmake/python.cmake @@ -42,7 +42,7 @@ if(WIN32) URL_HASH MD5=${PYTHON_HASH} PREFIX ${BUILD_DIR}/python CONFIGURE_COMMAND "" - BUILD_COMMAND cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && call build.bat -e -p ${PYTHON_ARCH} -c ${BUILD_MODE} + BUILD_COMMAND cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && call build.bat -e -p x64 -c ${BUILD_MODE} INSTALL_COMMAND ${PYTHON_BINARY_INTERNAL} ${PYTHON_SRC}/PC/layout/main.py -b ${PYTHON_SRC}/PCbuild/amd64 -s ${PYTHON_SRC} -t ${PYTHON_SRC}/tmp/ --include-underpth --include-stable --include-pip --include-dev --include-launchers --include-venv --include-symbols ${PYTHON_EXTRA_INSTLAL_FLAGS} --copy ${LIBDIR}/python ) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 4c7c7652d29..130173d7f01 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -374,71 +374,96 @@ NO_BUILD=false NO_CONFIRM=false USE_CXX11=true +# Note about versions: Min is inclusive, Max is exclusive (i.e. XXX_VERSION_MIN <= ACTUAL_VERSION < XXX_VERSION_MAX) +# XXX_VERSION is officially supported/used version in official builds. +# XXX_VERSION_SHORT is used for various things, like preferred version (when distribution provides several of them), +# and to name shortcuts to built libraries' installation directories... + CLANG_FORMAT_VERSION_MIN="6.0" +CLANG_FORMAT_VERSION_MAX="10.0" PYTHON_VERSION="3.7.7" +PYTHON_VERSION_SHORT="3.7" PYTHON_VERSION_MIN="3.7" +PYTHON_VERSION_MAX="3.9" PYTHON_VERSION_INSTALLED=$PYTHON_VERSION_MIN PYTHON_FORCE_BUILD=false PYTHON_FORCE_REBUILD=false PYTHON_SKIP=false -NUMPY_VERSION="1.17.0" +NUMPY_VERSION="1.17.5" +NUMPY_VERSION_SHORT="1.17" NUMPY_VERSION_MIN="1.8" +NUMPY_VERSION_MAX="2.0" NUMPY_FORCE_BUILD=false NUMPY_FORCE_REBUILD=false NUMPY_SKIP=false BOOST_VERSION="1.70.0" +BOOST_VERSION_SHORT="1.70" BOOST_VERSION_MIN="1.49" +BOOST_VERSION_MAX="2.0" BOOST_FORCE_BUILD=false BOOST_FORCE_REBUILD=false BOOST_SKIP=false TBB_VERSION="2019" +TBB_VERSION_SHORT="2019" TBB_VERSION_UPDATE="_U9" # Used for source packages... TBB_VERSION_MIN="2018" +TBB_VERSION_MAX="2021" TBB_FORCE_BUILD=false TBB_FORCE_REBUILD=false TBB_SKIP=false -OCIO_VERSION="1.1.0" +OCIO_VERSION="1.1.1" +OCIO_VERSION_SHORT="1.1" OCIO_VERSION_MIN="1.0" +OCIO_VERSION_MAX="1.2" OCIO_FORCE_BUILD=false OCIO_FORCE_REBUILD=false OCIO_SKIP=false OPENEXR_VERSION="2.4.0" +OPENEXR_VERSION_SHORT="2.4" OPENEXR_VERSION_MIN="2.3" +OPENEXR_VERSION_MAX="3.0" OPENEXR_FORCE_BUILD=false OPENEXR_FORCE_REBUILD=false OPENEXR_SKIP=false _with_built_openexr=false -OIIO_VERSION="1.8.13" -OIIO_VERSION_MIN="1.8.13" -OIIO_VERSION_MAX="99.99.0" # UNKNOWN currently # Not supported by current OSL... +OIIO_VERSION="2.1.15.0" +OIIO_VERSION_SHORT="2.1" +OIIO_VERSION_MIN="1.8" +OIIO_VERSION_MAX="3.0" OIIO_FORCE_BUILD=false OIIO_FORCE_REBUILD=false OIIO_SKIP=false LLVM_VERSION="9.0.1" +LLVM_VERSION_SHORT="9.0" LLVM_VERSION_MIN="6.0" +LLVM_VERSION_MAX="11.0" LLVM_VERSION_FOUND="" LLVM_FORCE_BUILD=false LLVM_FORCE_REBUILD=false LLVM_SKIP=false # OSL needs to be compiled for now! -OSL_VERSION="1.10.9" -OSL_VERSION_MIN=$OSL_VERSION +OSL_VERSION="1.10.10" +OSL_VERSION_SHORT="1.10" +OSL_VERSION_MIN="1.10" +OSL_VERSION_MAX="2.0" OSL_FORCE_BUILD=false OSL_FORCE_REBUILD=false OSL_SKIP=false # OpenSubdiv needs to be compiled for now OSD_VERSION="3.4.3" -OSD_VERSION_MIN=$OSD_VERSION +OSD_VERSION_SHORT="3.4" +OSD_VERSION_MIN="3.4" +OSD_VERSION_MAX="4.0" OSD_FORCE_BUILD=false OSD_FORCE_REBUILD=false OSD_SKIP=false @@ -447,46 +472,69 @@ OSD_SKIP=false OPENVDB_BLOSC_VERSION="1.5.0" OPENVDB_VERSION="7.0.0" -OPENVDB_VERSION_MIN=$OPENVDB_VERSION +OPENVDB_VERSION_SHORT="7.0" +OPENVDB_VERSION_MIN="7.0" +OPENVDB_VERSION_MAX="8.0" OPENVDB_FORCE_BUILD=false OPENVDB_FORCE_REBUILD=false OPENVDB_SKIP=false # Alembic needs to be compiled for now ALEMBIC_VERSION="1.7.12" -ALEMBIC_VERSION_MIN=$ALEMBIC_VERSION +ALEMBIC_VERSION_SHORT="1.7" +ALEMBIC_VERSION_MIN="1.7" +ALEMBIC_VERSION_MAX="2.0" ALEMBIC_FORCE_BUILD=false ALEMBIC_FORCE_REBUILD=false ALEMBIC_SKIP=false USD_VERSION="20.05" +USD_VERSION_SHORT="20.05" +USD_VERSION_MIN="20.05" +USD_VERSION_MAX="20.06" USD_FORCE_BUILD=false USD_FORCE_REBUILD=false USD_SKIP=false OPENCOLLADA_VERSION="1.6.68" +OPENCOLLADA_VERSION_SHORT="1.6" +OPENCOLLADA_VERSION_MIN="1.6.68" +OPENCOLLADA_VERSION_MAX="1.7" OPENCOLLADA_FORCE_BUILD=false OPENCOLLADA_FORCE_REBUILD=false OPENCOLLADA_SKIP=false EMBREE_VERSION="3.10.0" +EMBREE_VERSION_SHORT="3.10" +EMBREE_VERSION_MIN="3.10" +EMBREE_VERSION_MAX="4.0" EMBREE_FORCE_BUILD=false EMBREE_FORCE_REBUILD=false EMBREE_SKIP=false -OIDN_VERSION="1.0.0" +OIDN_VERSION="1.2.1" +OIDN_VERSION_SHORT="1.2" +OIDN_VERSION_MIN="1.2.0" +OIDN_VERSION_MAX="1.3" OIDN_FORCE_BUILD=false OIDN_FORCE_REBUILD=false OIDN_SKIP=false +ISPC_VERSION="1.14.0" + FFMPEG_VERSION="4.2.3" -FFMPEG_VERSION_MIN="2.8.4" +FFMPEG_VERSION_SHORT="4.2" +FFMPEG_VERSION_MIN="3.0" +FFMPEG_VERSION_MAX="5.0" FFMPEG_FORCE_BUILD=false FFMPEG_FORCE_REBUILD=false FFMPEG_SKIP=false _ffmpeg_list_sep=";" XR_OPENXR_VERSION="1.0.8" +XR_OPENXR_VERSION_SHORT="1.0" +XR_OPENXR_VERSION_MIN="1.0.8" +XR_OPENXR_VERSION_MAX="2.0" XR_OPENXR_FORCE_BUILD=false XR_OPENXR_FORCE_REBUILD=false XR_OPENXR_SKIP=false @@ -634,36 +682,43 @@ while true; do --ver-ocio) OCIO_VERSION="$2" OCIO_VERSION_MIN=$OCIO_VERSION + OCIO_VERSION_SHORT=$OCIO_VERSION shift; shift; continue ;; --ver-oiio) OIIO_VERSION="$2" OIIO_VERSION_MIN=$OIIO_VERSION + OIIO_VERSION_SHORT=$OIIO_VERSION shift; shift; continue ;; --ver-llvm) LLVM_VERSION="$2" LLVM_VERSION_MIN=$LLVM_VERSION + LLVM_VERSION_SHORT=$LLVM_VERSION shift; shift; continue ;; --ver-osl) OSL_VERSION="$2" OSL_VERSION_MIN=$OSL_VERSION + OSL_VERSION_SHORT=$OSL_VERSION shift; shift; continue ;; --ver-osd) OSD_VERSION="$2" OSD_VERSION_MIN=$OSD_VERSION + OSD_VERSION_SHORT=$OSD_VERSION shift; shift; continue ;; --ver-openvdb) OPENVDB_VERSION="$2" OPENVDB_VERSION_MIN=$OPENVDB_VERSION + OPENVDB_VERSION_SHORT=$OPENVDB_VERSION shift; shift; continue ;; --ver-xr-openxr) XR_OPENXR_VERSION="$2" XR_OPENXR_VERSION_MIN=$XR_OPENXR_VERSION + XR_OPENXR_VERSION_SHORT=$XR_OPENXR_VERSION shift; shift; continue ;; --build-all) @@ -1005,6 +1060,8 @@ OIDN_SOURCE=( "https://github.com/OpenImageDenoise/oidn/releases/download/v${OID #~ OIDN_REPO_UID="dabfd9c80101edae9d25a710160d12d6d963c591" #~ OIDN_REPO_BRANCH="master" +ISPC_BINARY=( "https://github.com/ispc/ispc/releases/download/v${ISPC_VERSION}/ispc-v${ISPC_VERSION}-linux.tar.gz" ) + FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" ) XR_OPENXR_USE_REPO=false @@ -1270,7 +1327,7 @@ _init_python() { _src=$SRC/Python-$PYTHON_VERSION _git=false _inst=$INST/python-$PYTHON_VERSION - _inst_shortcut=$INST/python-$PYTHON_VERSION_MIN + _inst_shortcut=$INST/python-$PYTHON_VERSION_SHORT } _update_deps_python() { @@ -1345,7 +1402,7 @@ compile_Python() { INFO "If you want to force rebuild of this lib, use the --force-python option." fi - run_ldconfig "python-$PYTHON_VERSION_MIN" + run_ldconfig "python-$PYTHON_VERSION_SHORT" } # ---------------------------------------------------------------------------- @@ -1355,8 +1412,8 @@ _init_numpy() { _src=$SRC/numpy-$NUMPY_VERSION _git=false _inst=$INST/numpy-$NUMPY_VERSION - _python=$INST/python-$PYTHON_VERSION - _site=lib/python$PYTHON_VERSION_MIN/site-packages + _python=$INST/python-$PYTHON_VERSION_SHORT + _site=lib/python$PYTHON_VERSION_SHORT/site-packages _inst_shortcut=$_python/$_site/numpy } @@ -1435,7 +1492,7 @@ compile_Numpy() { _init_boost() { _src=$SRC/boost-$BOOST_VERSION _git=false - _inst=$INST/boost-$BOOST_VERSION + _inst=$INST/boost-$BOOST_VERSION_SHORT _inst_shortcut=$INST/boost } @@ -1528,7 +1585,7 @@ compile_Boost() { _init_tbb() { _src=$SRC/TBB-$TBB_VERSION _git=false - _inst=$INST/tbb-$TBB_VERSION + _inst=$INST/tbb-$TBB_VERSION_SHORT _inst_shortcut=$INST/tbb } @@ -1656,7 +1713,7 @@ _init_ocio() { else _git=false fi - _inst=$INST/ocio-$OCIO_VERSION + _inst=$INST/ocio-$OCIO_VERSION_SHORT _inst_shortcut=$INST/ocio } @@ -1781,7 +1838,7 @@ compile_OCIO() { _init_openexr() { _src=$SRC/OpenEXR-$OPENEXR_VERSION _git=false - _inst=$INST/openexr-$OPENEXR_VERSION + _inst=$INST/openexr-$OPENEXR_VERSION_SHORT _inst_shortcut=$INST/openexr } @@ -1911,7 +1968,7 @@ compile_OPENEXR() { _init_oiio() { _src=$SRC/OpenImageIO-$OIIO_VERSION _git=true - _inst=$INST/oiio-$OIIO_VERSION + _inst=$INST/oiio-$OIIO_VERSION_SHORT _inst_shortcut=$INST/oiio } @@ -2066,7 +2123,7 @@ _init_llvm() { _src=$SRC/LLVM-$LLVM_VERSION _src_clang=$SRC/CLANG-$LLVM_VERSION _git=false - _inst=$INST/llvm-$LLVM_VERSION + _inst=$INST/llvm-$LLVM_VERSION_SHORT _inst_shortcut=$INST/llvm } @@ -2178,7 +2235,7 @@ compile_LLVM() { _init_osl() { _src=$SRC/OpenShadingLanguage-$OSL_VERSION _git=true - _inst=$INST/osl-$OSL_VERSION + _inst=$INST/osl-$OSL_VERSION_SHORT _inst_shortcut=$INST/osl } @@ -2323,7 +2380,7 @@ compile_OSL() { _init_osd() { _src=$SRC/OpenSubdiv-$OSD_VERSION _git=true - _inst=$INST/osd-$OSD_VERSION + _inst=$INST/osd-$OSD_VERSION_SHORT _inst_shortcut=$INST/osd } @@ -2537,7 +2594,7 @@ compile_BLOSC() { _init_openvdb() { _src=$SRC/openvdb-$OPENVDB_VERSION _git=false - _inst=$INST/openvdb-$OPENVDB_VERSION + _inst=$INST/openvdb-$OPENVDB_VERSION_SHORT _inst_shortcut=$INST/openvdb } @@ -2655,7 +2712,7 @@ compile_OPENVDB() { _init_alembic() { _src=$SRC/alembic-$ALEMBIC_VERSION _git=false - _inst=$INST/alembic-$ALEMBIC_VERSION + _inst=$INST/alembic-$ALEMBIC_VERSION_SHORT _inst_shortcut=$INST/alembic } @@ -2760,7 +2817,7 @@ compile_ALEMBIC() { _init_usd() { _src=$SRC/USD-$USD_VERSION _git=false - _inst=$INST/usd-$USD_VERSION + _inst=$INST/usd-$USD_VERSION_SHORT _inst_shortcut=$INST/usd } @@ -2859,7 +2916,7 @@ compile_USD() { _init_opencollada() { _src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION _git=true - _inst=$INST/opencollada-$OPENCOLLADA_VERSION + _inst=$INST/opencollada-$OPENCOLLADA_VERSION_SHORT _inst_shortcut=$INST/opencollada } @@ -2965,7 +3022,7 @@ compile_OpenCOLLADA() { _init_embree() { _src=$SRC/embree-$EMBREE_VERSION _git=true - _inst=$INST/embree-$EMBREE_VERSION + _inst=$INST/embree-$EMBREE_VERSION_SHORT _inst_shortcut=$INST/embree } @@ -3075,10 +3132,83 @@ compile_Embree() { # ---------------------------------------------------------------------------- # Build OpenImageDenoise +_init_ispc() { + _src=$SRC/ispc-v$ISPC_VERSION + _inst=$INST/ispc-v$ISPC_VERSION + _inst_shortcut=$INST/ispc +} + +_update_deps_ispc() { + OIDN_FORCE_REBUILD=true + if [ "$_is_building" = true ]; then + OIDN_FORCE_BUILD=true + fi +} + +clean_ispc() { + _init_ispc + if [ -d $_inst ]; then + _update_deps_ispc + fi + _clean +} + +install_ISPC() { + # To be changed each time we make edits that would modify the compiled results! + ispc_magic=0 + _init_ispc + + # Clean install if needed! + magic_compile_check ispc-$ISPC_VERSION $ispc_magic + if [ $? -eq 1 ]; then + clean_ispc + fi + + if [ ! -d $_inst ]; then + INFO "Installing Implicit SPMD Program Compiler v$ISPC_VERSION" + _is_building=true + + # Rebuild dependencies as well! + _update_deps_ispc + + prepare_opt + + if [ ! -d $_src ]; then + mkdir -p $SRC + download ISPC_BINARY[@] "$_src.tar.gz" + INFO "Unpacking ISPC-v$ISPC_VERSION" + tar -C $SRC --transform "s,(.*/?)ispc-v$ISPC_VERSION-linux[^/]*(.*),\1ispc-v$ISPC_VERSION\2,x" \ + -xf $_src.tar.gz + fi + + mkdir -p $_inst + cp -r $_src/bin $_inst/bin + + if [ -d $_inst ]; then + _create_inst_shortcut + else + ERROR "ISPC-v$ISPC_VERSION failed to install, exiting" + exit 1 + fi + + magic_compile_set ispc-$ISPC_VERSION $ispc_magic + + cd $CWD + INFO "Done compiling ISPC-v$ISPC_VERSION!" + _is_building=false + else + INFO "Own ISPC-v$ISPC_VERSION is up to date, nothing to do!" + fi + + _ispc_path_bin=$_inst/bin + run_ldconfig "ispc" +} + + _init_oidn() { _src=$SRC/oidn-$OIDN_VERSION _git=true - _inst=$INST/oidn-$OIDN_VERSION + _inst=$INST/oidn-$OIDN_VERSION_SHORT _inst_shortcut=$INST/oidn } @@ -3100,6 +3230,9 @@ compile_OIDN() { return fi + # Latest OIDN requires ISPC compiler tool... + install_ISPC + # To be changed each time we make edits that would modify the compiled results! oidn_magic=9 _init_oidn @@ -3152,6 +3285,7 @@ compile_OIDN() { cmake_d="$cmake_d -D WITH_EXAMPLE=OFF" cmake_d="$cmake_d -D WITH_TEST=OFF" cmake_d="$cmake_d -D OIDN_STATIC_LIB=ON" + cmake_d="$cmake_d -D ISPC_DIR_HINT=$_ispc_path_bin" if [ -d $INST/tbb ]; then make_d="$make_d TBB_ROOT=$INST/tbb" @@ -3187,7 +3321,7 @@ compile_OIDN() { _init_ffmpeg() { _src=$SRC/ffmpeg-$FFMPEG_VERSION - _inst=$INST/ffmpeg-$FFMPEG_VERSION + _inst=$INST/ffmpeg-$FFMPEG_VERSION_SHORT _inst_shortcut=$INST/ffmpeg } @@ -3316,7 +3450,7 @@ compile_FFmpeg() { _init_xr_openxr_sdk() { _src=$SRC/XR-OpenXR-SDK-$XR_OPENXR_VERSION _git=true - _inst=$INST/xr-openxr-sdk-$XR_OPENXR_VERSION + _inst=$INST/xr-openxr-sdk-$XR_OPENXR_VERSION_SHORT _inst_shortcut=$INST/xr-openxr-sdk } @@ -3555,13 +3689,18 @@ install_DEB() { PRINT "" CLANG_FORMAT="clang-format" - check_package_version_ge_DEB $CLANG_FORMAT $CLANG_FORMAT_VERSION_MIN + check_package_version_ge_DEB $CLANG_FORMAT $CLANG_FORMAT_VERSION if [ $? -eq 0 ]; then _packages="$_packages $CLANG_FORMAT" else - PRINT "" - WARNING "clang-format $CLANG_FORMAT_VERSION_MIN or higher not found, this is NOT needed to get Blender compiling..." - PRINT "" + check_package_version_ge_DEB $CLANG_FORMAT $CLANG_FORMAT_VERSION_MIN + if [ $? -eq 0 ]; then + _packages="$_packages $CLANG_FORMAT" + else + PRINT "" + WARNING "clang-format $CLANG_FORMAT_VERSION_MIN or higher not found, this is NOT needed to get Blender compiling..." + PRINT "" + fi fi if [ "$WITH_JACK" = true ]; then @@ -3676,7 +3815,7 @@ install_DEB() { INFO "Forced Python/NumPy building, as requested..." _do_compile_python=true else - check_package_version_ge_DEB python3-dev $PYTHON_VERSION_MIN + check_package_version_ge_lt_DEB python3-dev $PYTHON_VERSION_MIN $PYTHON_VERSION_MAX if [ $? -eq 0 ]; then PYTHON_VERSION_INSTALLED=$(echo `get_package_version_DEB python3-dev` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/') @@ -3718,7 +3857,7 @@ install_DEB() { INFO "Forced Boost building, as requested..." compile_Boost else - check_package_version_ge_DEB libboost-dev $BOOST_VERSION_MIN + check_package_version_ge_lt_DEB libboost-dev $BOOST_VERSION_MIN $BOOST_VERSION_MAX if [ $? -eq 0 ]; then install_packages_DEB libboost-dev @@ -3739,7 +3878,7 @@ install_DEB() { INFO "Forced TBB building, as requested..." compile_TBB else - check_package_version_ge_DEB libtbb-dev $TBB_VERSION_MIN + check_package_version_ge_lt_DEB libtbb-dev $TBB_VERSION_MIN $TBB_VERSION_MAX if [ $? -eq 0 ]; then install_packages_DEB libtbb-dev clean_TBB @@ -3756,14 +3895,13 @@ install_DEB() { INFO "Forced OpenColorIO building, as requested..." compile_OCIO else - # XXX Always force build of own OCIO, until linux distro guys update their package to default libyaml-cpp ver (0.5)! - #check_package_version_ge_DEB libopencolorio-dev $OCIO_VERSION_MIN - #if [ $? -eq 0 ]; then - #install_packages_DEB libopencolorio-dev - #clean_OCIO - #else + check_package_version_ge_lt_DEB libopencolorio-dev $OCIO_VERSION_MIN $OCIO_VERSION_MAX + if [ $? -eq 0 ]; then + install_packages_DEB libopencolorio-dev + clean_OCIO + else compile_OCIO - #fi + fi fi @@ -3774,7 +3912,7 @@ install_DEB() { INFO "Forced ILMBase/OpenEXR building, as requested..." compile_OPENEXR else - check_package_version_ge_DEB libopenexr-dev $OPENEXR_VERSION_MIN + check_package_version_ge_lt_DEB libopenexr-dev $OPENEXR_VERSION_MIN $OPENEXR_VERSION_MAX if [ $? -eq 0 ]; then install_packages_DEB libopenexr-dev OPENEXR_VERSION=`get_package_version_DEB libopenexr-dev` @@ -3793,14 +3931,13 @@ install_DEB() { INFO "Forced OpenImageIO building, as requested..." compile_OIIO else - # XXX Debian Testing / Ubuntu 16.04 pulls in WAY too many deps (gtk2/opencv ?!) incl. OCIO build against libyaml-cpp0.3 so build for now... - #check_package_version_ge_lt_DEB libopenimageio-dev $OIIO_VERSION_MIN $OIIO_VERSION_MAX - #if [ $? -eq 0 -a "$_with_built_openexr" = false ]; then - # install_packages_DEB libopenimageio-dev - # clean_OIIO - #else + check_package_version_ge_lt_DEB libopenimageio-dev $OIIO_VERSION_MIN $OIIO_VERSION_MAX + if [ $? -eq 0 -a "$_with_built_openexr" = false ]; then + install_packages_DEB libopenimageio-dev + clean_OIIO + else compile_OIIO - #fi + fi fi @@ -3814,11 +3951,12 @@ install_DEB() { INFO "Forced LLVM building, as requested..." _do_compile_llvm=true else - check_package_DEB clang-$LLVM_VERSION_MIN + check_package_version_ge_lt_DEB llvm-dev $LLVM_VERSION_MIN $LLVM_VERSION_MAX if [ $? -eq 0 ]; then - install_packages_DEB llvm-$LLVM_VERSION_MIN-dev clang-$LLVM_VERSION_MIN + install_packages_DEB llvm-dev clang have_llvm=true - LLVM_VERSION_FOUND=$LLVM_VERSION_MIN + LLVM_VERSION=`get_package_version_DEB llvm-dev` + LLVM_VERSION_FOUND=$LLVM_VERSION clean_LLVM else _do_compile_llvm=true @@ -3844,8 +3982,13 @@ install_DEB() { INFO "Forced OpenShadingLanguage building, as requested..." _do_compile_osl=true else - # No package currently! - _do_compile_osl=true + check_package_version_ge_lt_DEB libopenshadinglanguage-dev $OSL_VERSION_MIN $OSL_VERSION_MAX + if [ $? -eq 0 ]; then + install_packages_DEB libopenshadinglanguage-dev + clean_OSL + else + _do_compile_osl=true + fi fi if [ "$_do_compile_osl" = true ]; then @@ -3877,7 +4020,7 @@ install_DEB() { INFO "Forced OpenVDB building, as requested..." compile_OPENVDB else - check_package_version_ge_DEB libopenvdb-dev $OPENVDB_VERSION_MIN + check_package_version_ge_lt_DEB libopenvdb-dev $OPENVDB_VERSION_MIN $OPENVDB_VERSION_MAX if [ $? -eq 0 ]; then install_packages_DEB libopenvdb-dev libblosc-dev clean_OPENVDB @@ -3938,8 +4081,14 @@ install_DEB() { INFO "Forced Embree building, as requested..." _do_compile_embree=true else - # No package currently! - _do_compile_embree=true + # There is a package, but it does not provide everything that Blender needs... + #~ check_package_version_ge_lt_DEB libembree-dev $EMBREE_VERSION_MIN $EMBREE_VERSION_MAX + #~ if [ $? -eq 0 ]; then + #~ install_packages_DEB libembree-dev + #~ clean_Embree + #~ else + _do_compile_embree=true + #~ fi fi if [ "$_do_compile_embree" = true ]; then @@ -3975,7 +4124,7 @@ install_DEB() { # XXX Debian Testing / Ubuntu 16.04 finally includes FFmpeg, so check as usual check_package_DEB ffmpeg if [ $? -eq 0 ]; then - check_package_version_ge_DEB ffmpeg $FFMPEG_VERSION_MIN + check_package_version_ge_lt_DEB ffmpeg $FFMPEG_VERSION_MIN $FFMPEG_VERSION_MAX if [ $? -eq 0 ]; then install_packages_DEB libavdevice-dev clean_FFmpeg @@ -4299,7 +4448,7 @@ install_RPM() { INFO "Forced Python/NumPy building, as requested..." _do_compile_python=true else - check_package_version_ge_RPM python3-devel $PYTHON_VERSION_MIN + check_package_version_ge_lt_RPM python3-devel $PYTHON_VERSION_MIN $PYTHON_VERSION_MAX if [ $? -eq 0 ]; then PYTHON_VERSION_INSTALLED=$(echo `get_package_version_RPM python3-devel` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/') @@ -4309,7 +4458,7 @@ install_RPM() { if [ "$NUMPY_SKIP" = true ]; then WARNING "Skipping NumPy installation, as requested..." else - check_package_version_ge_RPM python3-numpy $NUMPY_VERSION_MIN + check_package_version_ge_lt_RPM python3-numpy $NUMPY_VERSION_MIN $NUMPY_VERSION_MAX if [ $? -eq 0 ]; then install_packages_RPM python3-numpy else @@ -4342,7 +4491,7 @@ install_RPM() { INFO "Forced Boost building, as requested..." _do_compile_boost=true else - check_package_version_ge_RPM boost-devel $BOOST_VERSION_MIN + check_package_version_ge_lt_RPM boost-devel $BOOST_VERSION_MIN $BOOST_VERSION_MAX if [ $? -eq 0 ]; then install_packages_RPM boost-devel clean_Boost @@ -4369,7 +4518,7 @@ install_RPM() { INFO "Forced TBB building, as requested..." compile_TBB else - check_package_version_ge_RPM tbb-devel $TBB_VERSION_MIN + check_package_version_ge_lt_RPM tbb-devel $TBB_VERSION_MIN $TBB_VERSION_MAX if [ $? -eq 0 ]; then install_packages_RPM tbb-devel clean_TBB @@ -4387,7 +4536,7 @@ install_RPM() { compile_OCIO else if [ "$RPM" = "SUSE" ]; then - check_package_version_ge_RPM OpenColorIO-devel $OCIO_VERSION_MIN + check_package_version_ge_lt_RPM OpenColorIO-devel $OCIO_VERSION_MIN $OCIO_VERSION_MAX if [ $? -eq 0 ]; then install_packages_RPM OpenColorIO-devel clean_OCIO @@ -4407,7 +4556,7 @@ install_RPM() { INFO "Forced ILMBase/OpenEXR building, as requested..." compile_OPENEXR else - check_package_version_ge_RPM openexr-devel $OPENEXR_VERSION_MIN + check_package_version_ge_lt_RPM openexr-devel $OPENEXR_VERSION_MIN $OPENEXR_VERSION_MAX if [ $? -eq 0 ]; then install_packages_RPM openexr-devel OPENEXR_VERSION=`get_package_version_RPM openexr-devel` @@ -4425,7 +4574,6 @@ install_RPM() { INFO "Forced OpenImageIO building, as requested..." compile_OIIO else - # XXX RPM distros pulls in too much and depends on old libs, so better to build for now... #check_package_version_ge_lt_RPM OpenImageIO-devel $OIIO_VERSION_MIN $OIIO_VERSION_MAX #if [ $? -eq 0 -a $_with_built_openexr == false ]; then # install_packages_RPM OpenImageIO-devel @@ -4451,10 +4599,11 @@ install_RPM() { else CLANG_DEV="clang-devel" fi - check_package_version_match_RPM $CLANG_DEV $LLVM_VERSION + check_package_version_ge_lt_RPM llvm-devel $LLVM_VERSION_MIN $LLVM_VERSION_MAX if [ $? -eq 0 ]; then install_packages_RPM llvm-devel $CLANG_DEV have_llvm=true + LLVM_VERSION=`get_package_version_RPM llvm-devel` LLVM_VERSION_FOUND=$LLVM_VERSION clean_LLVM else @@ -4481,8 +4630,18 @@ install_RPM() { INFO "Forced OpenShadingLanguage building, as requested..." _do_compile_osl=true else - # No package currently! - _do_compile_osl=true + if [ "$RPM" = "SUSE" ]; then + OSL_DEV="OpenShadingLanguage-devel" + else + OSL_DEV="openshadinglanguage-devel" + fi + check_package_version_ge_lt_RPM $OSL_DEV $OSL_VERSION_MIN $OSL_VERSION_MAX + if [ $? -eq 0 ]; then + install_packages_RPM $OSL_DEV + clean_OSL + else + _do_compile_osl=true + fi fi if [ "$_do_compile_osl" = true ]; then @@ -4570,8 +4729,14 @@ install_RPM() { INFO "Forced Embree building, as requested..." _do_compile_embree=true else - # No package... - _do_compile_embree=true + # There is a package, but it does not provide everything that Blender needs... + #~ check_package_version_ge_lt_RPM embree-devel $EMBREE_VERSION_MIN $EMBREE_VERSION_MAX + #~ if [ $? -eq 0 ]; then + #~ install_packages_RPM embree-devel + #~ clean_Embree + #~ else + _do_compile_embree=true + #~ fi fi if [ "$_do_compile_embree" = true ]; then @@ -4604,7 +4769,7 @@ install_RPM() { INFO "Forced FFMpeg building, as requested..." compile_FFmpeg else - check_package_version_ge_RPM ffmpeg-devel $FFMPEG_VERSION_MIN + check_package_version_ge_lt_RPM ffmpeg-devel $FFMPEG_VERSION_MIN $FFMPEG_VERSION_MAX if [ $? -eq 0 ]; then install_packages_RPM ffmpeg ffmpeg-devel clean_FFmpeg @@ -4824,7 +4989,7 @@ install_ARCH() { INFO "Forced Python/NumPy building, as requested..." _do_compile_python=true else - check_package_version_ge_ARCH python $PYTHON_VERSION_MIN + check_package_version_ge_lt_ARCH python $PYTHON_VERSION_MIN $PYTHON_VERSION_MAX if [ $? -eq 0 ]; then PYTHON_VERSION_INSTALLED=$(echo `get_package_version_ARCH python` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/') @@ -4834,7 +4999,7 @@ install_ARCH() { if [ "$NUMPY_SKIP" = true ]; then WARNING "Skipping NumPy installation, as requested..." else - check_package_version_ge_ARCH python-numpy $NUMPY_VERSION_MIN + check_package_version_ge_ARCH python-numpy $NUMPY_VERSION_MIN $NUMPY_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH python-numpy else @@ -4866,7 +5031,7 @@ install_ARCH() { INFO "Forced Boost building, as requested..." compile_Boost else - check_package_version_ge_ARCH boost $BOOST_VERSION_MIN + check_package_version_ge_lt_ARCH boost $BOOST_VERSION_MIN $BOOST_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH boost clean_Boost @@ -4883,7 +5048,7 @@ install_ARCH() { INFO "Forced TBB building, as requested..." compile_TBB else - check_package_version_ge_ARCH intel-tbb $TBB_VERSION_MIN + check_package_version_ge_lt_ARCH intel-tbb $TBB_VERSION_MIN $TBB_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH intel-tbb clean_TBB @@ -4900,7 +5065,7 @@ install_ARCH() { INFO "Forced OpenColorIO building, as requested..." compile_OCIO else - check_package_version_ge_ARCH opencolorio $OCIO_VERSION_MIN + check_package_version_ge_lt_ARCH opencolorio $OCIO_VERSION_MIN $OCIO_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH opencolorio clean_OCIO @@ -4917,7 +5082,7 @@ install_ARCH() { INFO "Forced ILMBase/OpenEXR building, as requested..." compile_OPENEXR else - check_package_version_ge_ARCH openexr $OPENEXR_VERSION_MIN + check_package_version_ge_lt_ARCH openexr $OPENEXR_VERSION_MIN $OPENEXR_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH openexr OPENEXR_VERSION=`get_package_version_ARCH openexr` @@ -4956,7 +5121,7 @@ install_ARCH() { INFO "Forced LLVM building, as requested..." _do_compile_llvm=true else - check_package_version_match_ARCH llvm $LLVM_VERSION_MIN + check_package_version_ge_lt_ARCH llvm $LLVM_VERSION_MIN $LLVM_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH llvm clang have_llvm=true @@ -4987,14 +5152,13 @@ install_ARCH() { INFO "Forced OpenShadingLanguage building, as requested..." _do_compile_osl=true else - # XXX Compile for now due to requirement of LLVM 3.4 ... - #check_package_version_ge_ARCH openshadinglanguage $OSL_VERSION_MIN - #if [ $? -eq 0 ]; then - # install_packages_ARCH openshadinglanguage - # clean_OSL - #else + check_package_version_ge_lt_ARCH openshadinglanguage $OSL_VERSION_MIN $OSL_VERSION_MAX + if [ $? -eq 0 ]; then + install_packages_ARCH openshadinglanguage + clean_OSL + else _do_compile_osl=true - #fi + fi fi if [ "$_do_compile_osl" = true ]; then @@ -5014,7 +5178,7 @@ install_ARCH() { INFO "Forced OpenSubdiv building, as requested..." compile_OSD else - check_package_version_ge_ARCH opensubdiv $OSD_VERSION_MIN + check_package_version_ge_lt_ARCH opensubdiv $OSD_VERSION_MIN $OSD_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH opensubdiv clean_OSD @@ -5031,7 +5195,7 @@ install_ARCH() { INFO "Forced OpenVDB building, as requested..." compile_OPENVDB else - check_package_version_ge_ARCH openvdb $OPENVDB_VERSION_MIN + check_package_version_ge_lt_ARCH openvdb $OPENVDB_VERSION_MIN $OPENVDB_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH openvdb clean_OPENVDB @@ -5096,13 +5260,14 @@ install_ARCH() { INFO "Forced Embree building, as requested..." _do_compile_embree=true else - check_package_ARCH embree - if [ $? -eq 0 ]; then - install_packages_ARCH embree - clean_Embree - else + # There is a package, but it does not provide everything that Blender needs... + #~ check_package_version_ge_lt_ARCH embree $EMBREE_VERSION_MIN $EMBREE_VERSION_MAX + #~ if [ $? -eq 0 ]; then + #~ install_packages_ARCH embree + #~ clean_Embree + #~ else _do_compile_embree=true - fi + #~ fi fi if [ "$_do_compile_embree" = true ]; then @@ -5135,7 +5300,7 @@ install_ARCH() { INFO "Forced FFMpeg building, as requested..." compile_FFmpeg else - check_package_version_ge_ARCH ffmpeg $FFMPEG_VERSION_MIN + check_package_version_ge_lt_ARCH ffmpeg $FFMPEG_VERSION_MIN $FFMPEG_VERSION_MAX if [ $? -eq 0 ]; then install_packages_ARCH ffmpeg clean_FFmpeg @@ -5413,6 +5578,7 @@ print_info() { _buildargs="-U *SNDFILE* -U PYTHON* -U *BOOST* -U *Boost* -U *TBB*" _buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*" _buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC* -U *USD*" + _buildargs="$_buildargs -U *EMBREE* -U *OPENIMAGEDENOISE* -U *OPENXR*" _1="-D WITH_CODEC_SNDFILE=ON" PRINT " $_1" diff --git a/build_files/build_environment/patches/boost.user.jam.in b/build_files/build_environment/patches/boost.user.jam.in new file mode 100644 index 00000000000..b615b0cafad --- /dev/null +++ b/build_files/build_environment/patches/boost.user.jam.in @@ -0,0 +1,4 @@ +using python : @PYTHON_SHORT_VERSION@ : @PYTHON_BINARY@ + : @LIBDIR@/python/include @LIBDIR@/python/include/python@PYTHON_SHORT_VERSION@m/ + : @LIBDIR@/python/libs +;
\ No newline at end of file diff --git a/build_files/cmake/Modules/FindAlembic.cmake b/build_files/cmake/Modules/FindAlembic.cmake index 45cda7ae2c5..aba91bb565d 100644 --- a/build_files/cmake/Modules/FindAlembic.cmake +++ b/build_files/cmake/Modules/FindAlembic.cmake @@ -12,12 +12,8 @@ #============================================================================= # Copyright 2016 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If ALEMBIC_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindAudaspace.cmake b/build_files/cmake/Modules/FindAudaspace.cmake index eeef49af60f..9bf15e05272 100644 --- a/build_files/cmake/Modules/FindAudaspace.cmake +++ b/build_files/cmake/Modules/FindAudaspace.cmake @@ -11,6 +11,13 @@ # AUDASPACE_PY_INCLUDE_DIRS - the audaspace's python binding include directories # AUDASPACE_PY_LIBRARIES - link these to use audaspace's python binding +#============================================================================= +# Copyright 2014 Blender Foundation. +# +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. +#============================================================================= + IF(NOT AUDASPACE_ROOT_DIR AND NOT $ENV{AUDASPACE_ROOT_DIR} STREQUAL "") SET(AUDASPACE_ROOT_DIR $ENV{AUDASPACE_ROOT_DIR}) ENDIF() diff --git a/build_files/cmake/Modules/FindBlosc.cmake b/build_files/cmake/Modules/FindBlosc.cmake index e0baa2d3382..d1ac3002c59 100644 --- a/build_files/cmake/Modules/FindBlosc.cmake +++ b/build_files/cmake/Modules/FindBlosc.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2018 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If BLOSC_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindClangTidy.cmake b/build_files/cmake/Modules/FindClangTidy.cmake index f556d05a0b9..d576ad8f100 100644 --- a/build_files/cmake/Modules/FindClangTidy.cmake +++ b/build_files/cmake/Modules/FindClangTidy.cmake @@ -17,12 +17,8 @@ #============================================================================= # Copyright 2020 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If CLANG_TIDY_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindEigen3.cmake b/build_files/cmake/Modules/FindEigen3.cmake index 82261294df2..735f44a04db 100644 --- a/build_files/cmake/Modules/FindEigen3.cmake +++ b/build_files/cmake/Modules/FindEigen3.cmake @@ -10,12 +10,8 @@ #============================================================================= # Copyright 2015 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If EIGEN3_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindEmbree.cmake b/build_files/cmake/Modules/FindEmbree.cmake index 90cf23d3e13..ccd0d6cd40a 100644 --- a/build_files/cmake/Modules/FindEmbree.cmake +++ b/build_files/cmake/Modules/FindEmbree.cmake @@ -11,12 +11,8 @@ #============================================================================= # Copyright 2018 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If EMBREE_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindFftw3.cmake b/build_files/cmake/Modules/FindFftw3.cmake index 3da19290b0d..df69c0c2ed4 100644 --- a/build_files/cmake/Modules/FindFftw3.cmake +++ b/build_files/cmake/Modules/FindFftw3.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If FFTW3_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindGLEW.cmake b/build_files/cmake/Modules/FindGLEW.cmake index 390e3878d6a..059b1da005d 100644 --- a/build_files/cmake/Modules/FindGLEW.cmake +++ b/build_files/cmake/Modules/FindGLEW.cmake @@ -13,12 +13,8 @@ #============================================================================= # Copyright 2014 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If GLEW_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindGMP.cmake b/build_files/cmake/Modules/FindGMP.cmake index 4469f32c785..e1795984985 100644 --- a/build_files/cmake/Modules/FindGMP.cmake +++ b/build_files/cmake/Modules/FindGMP.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If GMP_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindIcuLinux.cmake b/build_files/cmake/Modules/FindIcuLinux.cmake index 9a467fa0115..e1aaa434533 100644 --- a/build_files/cmake/Modules/FindIcuLinux.cmake +++ b/build_files/cmake/Modules/FindIcuLinux.cmake @@ -12,12 +12,8 @@ #============================================================================= # Copyright 2012 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If ICU_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindJack.cmake b/build_files/cmake/Modules/FindJack.cmake index 7643e586cad..a790c127c09 100644 --- a/build_files/cmake/Modules/FindJack.cmake +++ b/build_files/cmake/Modules/FindJack.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If JACK_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindJeMalloc.cmake b/build_files/cmake/Modules/FindJeMalloc.cmake index e042e7fe43e..72a0bed6f22 100644 --- a/build_files/cmake/Modules/FindJeMalloc.cmake +++ b/build_files/cmake/Modules/FindJeMalloc.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If JEMALLOC_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindLLVM.cmake b/build_files/cmake/Modules/FindLLVM.cmake index 141a91c0508..d7269a4281f 100644 --- a/build_files/cmake/Modules/FindLLVM.cmake +++ b/build_files/cmake/Modules/FindLLVM.cmake @@ -13,12 +13,8 @@ #============================================================================= # Copyright 2015 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= if(LLVM_ROOT_DIR) diff --git a/build_files/cmake/Modules/FindLZO.cmake b/build_files/cmake/Modules/FindLZO.cmake index 4db5d0f5441..81f8792a803 100644 --- a/build_files/cmake/Modules/FindLZO.cmake +++ b/build_files/cmake/Modules/FindLZO.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2015 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If LZO_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOSL.cmake b/build_files/cmake/Modules/FindOSL.cmake index 07ed2c86e19..f22fe32c994 100644 --- a/build_files/cmake/Modules/FindOSL.cmake +++ b/build_files/cmake/Modules/FindOSL.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2014 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OSL_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOpenCOLLADA.cmake b/build_files/cmake/Modules/FindOpenCOLLADA.cmake index 239d46499b9..cc940b76382 100644 --- a/build_files/cmake/Modules/FindOpenCOLLADA.cmake +++ b/build_files/cmake/Modules/FindOpenCOLLADA.cmake @@ -11,12 +11,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # note about include paths, there are 2 ways includes are set diff --git a/build_files/cmake/Modules/FindOpenColorIO.cmake b/build_files/cmake/Modules/FindOpenColorIO.cmake index 090032e06ec..559ccaba865 100644 --- a/build_files/cmake/Modules/FindOpenColorIO.cmake +++ b/build_files/cmake/Modules/FindOpenColorIO.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2012 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPENCOLORIO_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOpenEXR.cmake b/build_files/cmake/Modules/FindOpenEXR.cmake index 3cf559a5da1..090f80b8df7 100644 --- a/build_files/cmake/Modules/FindOpenEXR.cmake +++ b/build_files/cmake/Modules/FindOpenEXR.cmake @@ -21,12 +21,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPENEXR_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOpenGLES.cmake b/build_files/cmake/Modules/FindOpenGLES.cmake index daf6db61050..d01d32b71bc 100644 --- a/build_files/cmake/Modules/FindOpenGLES.cmake +++ b/build_files/cmake/Modules/FindOpenGLES.cmake @@ -10,6 +10,13 @@ # OPENGLES_LIBRARIES - all libraries needed for OpenGLES # OPENGLES_INCLUDES - all includes needed for OpenGLES +#============================================================================= +# Copyright 2014 Blender Foundation. +# +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. +#============================================================================= + # If OPENGLES_ROOT_DIR was defined in the environment, use it. IF(NOT OPENGLES_ROOT_DIR AND NOT $ENV{OPENGLES_ROOT_DIR} STREQUAL "") SET(OPENGLES_ROOT_DIR $ENV{OPENGLES_ROOT_DIR}) diff --git a/build_files/cmake/Modules/FindOpenImageDenoise.cmake b/build_files/cmake/Modules/FindOpenImageDenoise.cmake index c7215d30e8a..3facadbb9be 100644 --- a/build_files/cmake/Modules/FindOpenImageDenoise.cmake +++ b/build_files/cmake/Modules/FindOpenImageDenoise.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2019 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPENIMAGEDENOISE_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOpenImageIO.cmake b/build_files/cmake/Modules/FindOpenImageIO.cmake index 3570c982961..aac5b5ce0a8 100644 --- a/build_files/cmake/Modules/FindOpenImageIO.cmake +++ b/build_files/cmake/Modules/FindOpenImageIO.cmake @@ -16,12 +16,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPENIMAGEIO_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOpenJPEG.cmake b/build_files/cmake/Modules/FindOpenJPEG.cmake index 5774ac2182a..ddd98237dd0 100644 --- a/build_files/cmake/Modules/FindOpenJPEG.cmake +++ b/build_files/cmake/Modules/FindOpenJPEG.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPENJPEG_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOpenSubdiv.cmake b/build_files/cmake/Modules/FindOpenSubdiv.cmake index 2c9fbf0ba60..312540645dc 100644 --- a/build_files/cmake/Modules/FindOpenSubdiv.cmake +++ b/build_files/cmake/Modules/FindOpenSubdiv.cmake @@ -11,12 +11,8 @@ #============================================================================= # Copyright 2013 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPENSUBDIV_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOpenVDB.cmake b/build_files/cmake/Modules/FindOpenVDB.cmake index 5f24231fcf4..1c7d955d1d4 100644 --- a/build_files/cmake/Modules/FindOpenVDB.cmake +++ b/build_files/cmake/Modules/FindOpenVDB.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2015 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPENVDB_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindOptiX.cmake b/build_files/cmake/Modules/FindOptiX.cmake index 5b606afea27..2cb1ce09e46 100644 --- a/build_files/cmake/Modules/FindOptiX.cmake +++ b/build_files/cmake/Modules/FindOptiX.cmake @@ -10,12 +10,8 @@ #============================================================================= # Copyright 2019 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If OPTIX_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindPCRE.cmake b/build_files/cmake/Modules/FindPCRE.cmake index dfe721920fd..678826e4ab1 100644 --- a/build_files/cmake/Modules/FindPCRE.cmake +++ b/build_files/cmake/Modules/FindPCRE.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If PCRE_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindPugiXML.cmake b/build_files/cmake/Modules/FindPugiXML.cmake index 73d7b9ef92c..5dced1c6df8 100644 --- a/build_files/cmake/Modules/FindPugiXML.cmake +++ b/build_files/cmake/Modules/FindPugiXML.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2014 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If PUGIXML_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindPythonLibsUnix.cmake b/build_files/cmake/Modules/FindPythonLibsUnix.cmake index 0e3ecac14f0..5b3f2e52256 100644 --- a/build_files/cmake/Modules/FindPythonLibsUnix.cmake +++ b/build_files/cmake/Modules/FindPythonLibsUnix.cmake @@ -25,12 +25,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If PYTHON_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindSDL2.cmake b/build_files/cmake/Modules/FindSDL2.cmake index ba89a6e3fce..7ef9a84dab0 100644 --- a/build_files/cmake/Modules/FindSDL2.cmake +++ b/build_files/cmake/Modules/FindSDL2.cmake @@ -13,12 +13,8 @@ #============================================================================= # Copyright 2015 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If SDL2_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindSndFile.cmake b/build_files/cmake/Modules/FindSndFile.cmake index 0d66b4785e2..aae5b692228 100644 --- a/build_files/cmake/Modules/FindSndFile.cmake +++ b/build_files/cmake/Modules/FindSndFile.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If LIBSNDFILE_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindSpacenav.cmake b/build_files/cmake/Modules/FindSpacenav.cmake index 353b05f90b5..b7c8c01dc32 100644 --- a/build_files/cmake/Modules/FindSpacenav.cmake +++ b/build_files/cmake/Modules/FindSpacenav.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If SPACENAV_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindTBB.cmake b/build_files/cmake/Modules/FindTBB.cmake index de7db09ddb5..5a0d5a7d42d 100644 --- a/build_files/cmake/Modules/FindTBB.cmake +++ b/build_files/cmake/Modules/FindTBB.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2016 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If TBB_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindUSD.cmake b/build_files/cmake/Modules/FindUSD.cmake index 043a10ffa98..d0e772038a7 100644 --- a/build_files/cmake/Modules/FindUSD.cmake +++ b/build_files/cmake/Modules/FindUSD.cmake @@ -12,12 +12,8 @@ #============================================================================= # Copyright 2019 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If USD_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindXML2.cmake b/build_files/cmake/Modules/FindXML2.cmake index c16ab4468cc..d313150f7a0 100644 --- a/build_files/cmake/Modules/FindXML2.cmake +++ b/build_files/cmake/Modules/FindXML2.cmake @@ -14,12 +14,8 @@ #============================================================================= # Copyright 2011 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If XML2_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/FindXR_OpenXR_SDK.cmake b/build_files/cmake/Modules/FindXR_OpenXR_SDK.cmake index 567a0101b4a..3e9cebdbae4 100644 --- a/build_files/cmake/Modules/FindXR_OpenXR_SDK.cmake +++ b/build_files/cmake/Modules/FindXR_OpenXR_SDK.cmake @@ -20,12 +20,8 @@ # XR_OPENXR_SDK_LOADER_LIBRARY, where to find the OpenXR-SDK loader library. #============================================================================= -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #============================================================================= # If XR_OPENXR_SDK_ROOT_DIR was defined in the environment, use it. diff --git a/build_files/cmake/Modules/GTest.cmake b/build_files/cmake/Modules/GTest.cmake index 9a82fc49628..6981c1ddc55 100644 --- a/build_files/cmake/Modules/GTest.cmake +++ b/build_files/cmake/Modules/GTest.cmake @@ -1,5 +1,5 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. #[=======================================================================[.rst: GoogleTest diff --git a/build_files/cmake/Modules/GTestAddTests.cmake b/build_files/cmake/Modules/GTestAddTests.cmake index 8be07b8e2e5..850504bdbea 100644 --- a/build_files/cmake/Modules/GTestAddTests.cmake +++ b/build_files/cmake/Modules/GTestAddTests.cmake @@ -1,5 +1,5 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. # Blender: disable ASAN leak detection when trying to discover tests. set(ENV{ASAN_OPTIONS} "detect_leaks=0") diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake index ea9a1edeb43..a744f4202da 100644 --- a/build_files/cmake/Modules/GTestTesting.cmake +++ b/build_files/cmake/Modules/GTestTesting.cmake @@ -1,12 +1,8 @@ #============================================================================= # Copyright 2014 Blender Foundation. # -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. +# Distributed under the OSI-approved BSD 3-Clause License, +# see accompanying file BSD-3-Clause-license.txt for details. # # Inspired on the Testing.cmake from Libmv # diff --git a/doc/license/BSD-3-Clause-license.txt b/doc/license/BSD-3-Clause-license.txt new file mode 100644 index 00000000000..3879237a0a9 --- /dev/null +++ b/doc/license/BSD-3-Clause-license.txt @@ -0,0 +1,26 @@ +BSD 3-Clause License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 3d1b6e1d865..145b1fa492c 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -1201,9 +1201,13 @@ void GeometryManager::device_update_volume_images(Device *device, Scene *scene, } ImageHandle &handle = attr.data_voxel(); - const int slot = handle.svm_slot(); - if (slot != -1) { - volume_images.insert(slot); + /* We can build directly from OpenVDB data structures, no need to + * load such images early. */ + if (!handle.vdb_loader()) { + const int slot = handle.svm_slot(); + if (slot != -1) { + volume_images.insert(slot); + } } } } diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 691eb162dd0..a5dfcf60d61 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -18,6 +18,7 @@ #include "device/device.h" #include "render/colorspace.h" #include "render/image_oiio.h" +#include "render/image_vdb.h" #include "render/scene.h" #include "render/stats.h" @@ -172,6 +173,31 @@ device_texture *ImageHandle::image_memory(const int tile_index) const return img ? img->mem : NULL; } +VDBImageLoader *ImageHandle::vdb_loader(const int tile_index) const +{ + if (tile_index >= tile_slots.size()) { + return NULL; + } + + ImageManager::Image *img = manager->images[tile_slots[tile_index]]; + + if (img == NULL) { + return NULL; + } + + ImageLoader *loader = img->loader; + + if (loader == NULL) { + return NULL; + } + + if (loader->is_vdb_loader()) { + return dynamic_cast<VDBImageLoader *>(loader); + } + + return NULL; +} + bool ImageHandle::operator==(const ImageHandle &other) const { return manager == other.manager && tile_slots == other.tile_slots; @@ -258,6 +284,11 @@ bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b) } } +bool ImageLoader::is_vdb_loader() const +{ + return false; +} + /* Image Manager */ ImageManager::ImageManager(const DeviceInfo &info) diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 47be0ee559a..cb059256ce3 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -39,6 +39,7 @@ class Progress; class RenderStats; class Scene; class ColorSpaceProcessor; +class VDBImageLoader; /* Image Parameters */ class ImageParams { @@ -124,6 +125,8 @@ class ImageLoader { virtual bool equals(const ImageLoader &other) const = 0; static bool equals(const ImageLoader *a, const ImageLoader *b); + virtual bool is_vdb_loader() const; + /* Work around for no RTTI. */ }; @@ -149,6 +152,8 @@ class ImageHandle { int svm_slot(const int tile_index = 0) const; device_texture *image_memory(const int tile_index = 0) const; + VDBImageLoader *vdb_loader(const int tile_index = 0) const; + protected: vector<int> tile_slots; ImageManager *manager; diff --git a/intern/cycles/render/image_vdb.cpp b/intern/cycles/render/image_vdb.cpp index 500131c2d84..3f7dd45ee88 100644 --- a/intern/cycles/render/image_vdb.cpp +++ b/intern/cycles/render/image_vdb.cpp @@ -185,4 +185,16 @@ void VDBImageLoader::cleanup() #endif } +bool VDBImageLoader::is_vdb_loader() const +{ + return true; +} + +#ifdef WITH_OPENVDB +openvdb::GridBase::ConstPtr VDBImageLoader::get_grid() +{ + return grid; +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/render/image_vdb.h b/intern/cycles/render/image_vdb.h index 7dec63b11e6..4500cfbfb88 100644 --- a/intern/cycles/render/image_vdb.h +++ b/intern/cycles/render/image_vdb.h @@ -43,6 +43,12 @@ class VDBImageLoader : public ImageLoader { virtual void cleanup() override; + virtual bool is_vdb_loader() const override; + +#ifdef WITH_OPENVDB + openvdb::GridBase::ConstPtr get_grid(); +#endif + protected: string grid_name; #ifdef WITH_OPENVDB diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index 607363d01c6..0b57243fec1 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -15,34 +15,25 @@ */ #include "render/attribute.h" +#include "render/image_vdb.h" #include "render/mesh.h" #include "render/scene.h" +#ifdef WITH_OPENVDB +# include <openvdb/tools/Dense.h> +# include <openvdb/tools/GridTransformer.h> +# include <openvdb/tools/Morphology.h> +#endif + #include "util/util_foreach.h" #include "util/util_hash.h" #include "util/util_logging.h" +#include "util/util_openvdb.h" #include "util/util_progress.h" #include "util/util_types.h" CCL_NAMESPACE_BEGIN -const int64_t VOXEL_INDEX_NONE = -1; - -static int64_t compute_voxel_index(const int3 &resolution, int64_t x, int64_t y, int64_t z) -{ - if (x < 0 || x >= resolution.x) { - return VOXEL_INDEX_NONE; - } - else if (y < 0 || y >= resolution.y) { - return VOXEL_INDEX_NONE; - } - else if (z < 0 || z >= resolution.z) { - return VOXEL_INDEX_NONE; - } - - return x + y * resolution.x + z * resolution.x * resolution.y; -} - struct QuadData { int v0, v1, v2, v3; @@ -123,122 +114,148 @@ static void create_quad(int3 corners[8], quads.push_back(quad); } -struct VolumeParams { - int3 resolution; - float3 cell_size; - float3 start_point; - int pad_size; -}; - -static const int CUBE_SIZE = 8; - /* Create a mesh from a volume. * * The way the algorithm works is as follows: * - * - The coordinates of active voxels from a dense volume (or 3d image) are - * gathered inside an auxiliary volume. - * - Each set of coordinates of an CUBE_SIZE cube are mapped to the same - * coordinate of the auxiliary volume. - * - Quads are created between active and non-active voxels in the auxiliary - * volume to generate a tight mesh around the volume. + * - The topologies of input OpenVDB grids are merged into a temporary grid. + * - Voxels of the temporary grid are dilated to account for the padding necessary for volume + * sampling. + * - Quads are created on the boundary between active and inactive leaf nodes of the temporary + * grid. */ class VolumeMeshBuilder { - /* Auxiliary volume that is used to check if a node already added. */ - vector<char> grid; - - /* The resolution of the auxiliary volume, set to be equal to 1/CUBE_SIZE - * of the original volume on each axis. */ - int3 res; - - size_t number_of_nodes; - - /* Offset due to padding in the original grid. Padding will transform the - * coordinates of the original grid from 0...res to -padding...res+padding, - * so some coordinates are negative, and we need to properly account for - * them. */ - int3 pad_offset; - - VolumeParams *params; - public: - VolumeMeshBuilder(VolumeParams *volume_params); +#ifdef WITH_OPENVDB + /* use a MaskGrid to store the topology to save memory */ + openvdb::MaskGrid::Ptr topology_grid; + openvdb::CoordBBox bbox; +#endif + bool first_grid; + + VolumeMeshBuilder(); - void add_node(int x, int y, int z); +#ifdef WITH_OPENVDB + void add_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping); +#endif - void add_node_with_padding(int x, int y, int z); + void add_padding(int pad_size); - void create_mesh(vector<float3> &vertices, vector<int> &indices, vector<float3> &face_normals); + void create_mesh(vector<float3> &vertices, + vector<int> &indices, + vector<float3> &face_normals, + const float face_overlap_avoidance); - private: void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads); - void convert_object_space(const vector<int3> &vertices, vector<float3> &out_vertices); + void convert_object_space(const vector<int3> &vertices, + vector<float3> &out_vertices, + const float face_overlap_avoidance); void convert_quads_to_tris(const vector<QuadData> &quads, vector<int> &tris, vector<float3> &face_normals); -}; -VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params) -{ - params = volume_params; - number_of_nodes = 0; + bool empty_grid() const; - const int64_t x = divide_up(params->resolution.x, CUBE_SIZE); - const int64_t y = divide_up(params->resolution.y, CUBE_SIZE); - const int64_t z = divide_up(params->resolution.z, CUBE_SIZE); +#ifdef WITH_OPENVDB + template<typename GridType> + void merge_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping) + { + typename GridType::ConstPtr typed_grid = openvdb::gridConstPtrCast<GridType>(grid); - /* Adding 2*pad_size since we pad in both positive and negative directions - * along the axis. */ - const int64_t px = divide_up(params->resolution.x + 2 * params->pad_size, CUBE_SIZE); - const int64_t py = divide_up(params->resolution.y + 2 * params->pad_size, CUBE_SIZE); - const int64_t pz = divide_up(params->resolution.z + 2 * params->pad_size, CUBE_SIZE); + if (do_clipping) { + using ValueType = typename GridType::ValueType; + typename GridType::Ptr copy = typed_grid->deepCopy(); + typename GridType::ValueOnIter iter = copy->beginValueOn(); - res = make_int3(px, py, pz); - pad_offset = make_int3(px - x, py - y, pz - z); + for (; iter; ++iter) { + if (iter.getValue() < ValueType(volume_clipping)) { + iter.setValueOff(); + } + } - grid.resize(px * py * pz, 0); -} + typed_grid = copy; + } -void VolumeMeshBuilder::add_node(int x, int y, int z) -{ - /* Map coordinates to index space. */ - const int index_x = (x / CUBE_SIZE) + pad_offset.x; - const int index_y = (y / CUBE_SIZE) + pad_offset.y; - const int index_z = (z / CUBE_SIZE) + pad_offset.z; + topology_grid->topologyUnion(*typed_grid); + } +#endif +}; - assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0)); +VolumeMeshBuilder::VolumeMeshBuilder() +{ + first_grid = true; +} - const int64_t index = compute_voxel_index(res, index_x, index_y, index_z); - if (index == VOXEL_INDEX_NONE) { - return; +#ifdef WITH_OPENVDB +void VolumeMeshBuilder::add_grid(openvdb::GridBase::ConstPtr grid, + bool do_clipping, + float volume_clipping) +{ + /* set the transform of our grid from the first one */ + if (first_grid) { + topology_grid = openvdb::MaskGrid::create(); + topology_grid->setTransform(grid->transform().copy()); + first_grid = false; } - - /* We already have a node here. */ - if (grid[index] == 1) { - return; + /* if the transforms do not match, we need to resample one of the grids so that + * its index space registers with that of the other, here we resample our mask + * grid so memory usage is kept low */ + else if (topology_grid->transform() != grid->transform()) { + openvdb::MaskGrid::Ptr temp_grid = topology_grid->copyWithNewTree(); + temp_grid->setTransform(grid->transform().copy()); + openvdb::tools::resampleToMatch<openvdb::tools::BoxSampler>(*topology_grid, *temp_grid); + topology_grid = temp_grid; + topology_grid->setTransform(grid->transform().copy()); } - ++number_of_nodes; - - grid[index] = 1; + if (grid->isType<openvdb::FloatGrid>()) { + merge_grid<openvdb::FloatGrid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::Vec3fGrid>()) { + merge_grid<openvdb::Vec3fGrid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::Vec4fGrid>()) { + merge_grid<openvdb::Vec4fGrid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::BoolGrid>()) { + merge_grid<openvdb::BoolGrid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::DoubleGrid>()) { + merge_grid<openvdb::DoubleGrid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::Int32Grid>()) { + merge_grid<openvdb::Int32Grid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::Int64Grid>()) { + merge_grid<openvdb::Int64Grid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::Vec3IGrid>()) { + merge_grid<openvdb::Vec3IGrid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::Vec3dGrid>()) { + merge_grid<openvdb::Vec3dGrid>(grid, do_clipping, volume_clipping); + } + else if (grid->isType<openvdb::MaskGrid>()) { + topology_grid->topologyUnion(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid)); + } } +#endif -void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z) +void VolumeMeshBuilder::add_padding(int pad_size) { - for (int px = x - params->pad_size; px < x + params->pad_size; ++px) { - for (int py = y - params->pad_size; py < y + params->pad_size; ++py) { - for (int pz = z - params->pad_size; pz < z + params->pad_size; ++pz) { - add_node(px, py, pz); - } - } - } +#ifdef WITH_OPENVDB + openvdb::tools::dilateVoxels(topology_grid->tree(), pad_size); +#else + (void)pad_size; +#endif } void VolumeMeshBuilder::create_mesh(vector<float3> &vertices, vector<int> &indices, - vector<float3> &face_normals) + vector<float3> &face_normals, + const float face_overlap_avoidance) { /* We create vertices in index space (is), and only convert them to object * space when done. */ @@ -247,7 +264,7 @@ void VolumeMeshBuilder::create_mesh(vector<float3> &vertices, generate_vertices_and_quads(vertices_is, quads); - convert_object_space(vertices_is, vertices); + convert_object_space(vertices_is, vertices, face_overlap_avoidance); convert_quads_to_tris(quads, indices, face_normals); } @@ -255,85 +272,97 @@ void VolumeMeshBuilder::create_mesh(vector<float3> &vertices, void VolumeMeshBuilder::generate_vertices_and_quads(vector<ccl::int3> &vertices_is, vector<QuadData> &quads) { - unordered_map<size_t, int> used_verts; +#ifdef WITH_OPENVDB + const openvdb::MaskGrid::TreeType &tree = topology_grid->tree(); + tree.evalLeafBoundingBox(bbox); - for (int z = 0; z < res.z; ++z) { - for (int y = 0; y < res.y; ++y) { - for (int x = 0; x < res.x; ++x) { - int64_t voxel_index = compute_voxel_index(res, x, y, z); - if (grid[voxel_index] == 0) { - continue; - } + const int3 resolution = make_int3(bbox.dim().x(), bbox.dim().y(), bbox.dim().z()); - /* Compute min and max coords of the node in index space. */ - int3 min = make_int3((x - pad_offset.x) * CUBE_SIZE, - (y - pad_offset.y) * CUBE_SIZE, - (z - pad_offset.z) * CUBE_SIZE); - - /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */ - int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE); - - int3 corners[8] = { - make_int3(min[0], min[1], min[2]), - make_int3(max[0], min[1], min[2]), - make_int3(max[0], max[1], min[2]), - make_int3(min[0], max[1], min[2]), - make_int3(min[0], min[1], max[2]), - make_int3(max[0], min[1], max[2]), - make_int3(max[0], max[1], max[2]), - make_int3(min[0], max[1], max[2]), - }; - - /* Only create a quad if on the border between an active and - * an inactive node. - */ - - voxel_index = compute_voxel_index(res, x - 1, y, z); - if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN); - } + unordered_map<size_t, int> used_verts; - voxel_index = compute_voxel_index(res, x + 1, y, z); - if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX); - } + for (auto iter = tree.cbeginLeaf(); iter; ++iter) { + openvdb::CoordBBox leaf_bbox = iter->getNodeBoundingBox(); + /* +1 to convert from exclusive to include bounds. */ + leaf_bbox.max() = leaf_bbox.max().offsetBy(1); + + int3 min = make_int3(leaf_bbox.min().x(), leaf_bbox.min().y(), leaf_bbox.min().z()); + int3 max = make_int3(leaf_bbox.max().x(), leaf_bbox.max().y(), leaf_bbox.max().z()); + + int3 corners[8] = { + make_int3(min[0], min[1], min[2]), + make_int3(max[0], min[1], min[2]), + make_int3(max[0], max[1], min[2]), + make_int3(min[0], max[1], min[2]), + make_int3(min[0], min[1], max[2]), + make_int3(max[0], min[1], max[2]), + make_int3(max[0], max[1], max[2]), + make_int3(min[0], max[1], max[2]), + }; + + /* Only create a quad if on the border between an active and an inactive leaf. + * + * We verify that a leaf exists by probing a coordinate that is at its center, + * to do so we compute the center of the current leaf and offset this coordinate + * by the size of a leaf in each direction. + */ + static const int LEAF_DIM = openvdb::MaskGrid::TreeType::LeafNodeType::DIM; + auto center = leaf_bbox.min() + openvdb::Coord(LEAF_DIM / 2); + + if (!tree.probeLeaf(openvdb::Coord(center.x() - LEAF_DIM, center.y(), center.z()))) { + create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MIN); + } - voxel_index = compute_voxel_index(res, x, y - 1, z); - if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN); - } + if (!tree.probeLeaf(openvdb::Coord(center.x() + LEAF_DIM, center.y(), center.z()))) { + create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MAX); + } - voxel_index = compute_voxel_index(res, x, y + 1, z); - if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX); - } + if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() - LEAF_DIM, center.z()))) { + create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MIN); + } - voxel_index = compute_voxel_index(res, x, y, z - 1); - if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN); - } + if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() + LEAF_DIM, center.z()))) { + create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MAX); + } - voxel_index = compute_voxel_index(res, x, y, z + 1); - if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX); - } - } + if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() - LEAF_DIM))) { + create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MIN); + } + + if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() + LEAF_DIM))) { + create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MAX); } } +#else + (void)vertices_is; + (void)quads; +#endif } void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices, - vector<float3> &out_vertices) + vector<float3> &out_vertices, + const float face_overlap_avoidance) { +#ifdef WITH_OPENVDB + /* compute the offset for the face overlap avoidance */ + bbox = topology_grid->evalActiveVoxelBoundingBox(); + openvdb::Coord dim = bbox.dim(); + + float3 cell_size = make_float3(1.0f / dim.x(), 1.0f / dim.y(), 1.0f / dim.z()); + float3 point_offset = cell_size * face_overlap_avoidance; + out_vertices.reserve(vertices.size()); for (size_t i = 0; i < vertices.size(); ++i) { - float3 vertex = make_float3(vertices[i].x, vertices[i].y, vertices[i].z); - vertex *= params->cell_size; - vertex += params->start_point; - - out_vertices.push_back(vertex); + openvdb::math::Vec3d p = topology_grid->indexToWorld( + openvdb::math::Vec3d(vertices[i].x, vertices[i].y, vertices[i].z)); + float3 vertex = make_float3((float)p.x(), (float)p.y(), (float)p.z()); + out_vertices.push_back(vertex + point_offset); } +#else + (void)vertices; + (void)out_vertices; + (void)face_overlap_avoidance; +#endif } void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads, @@ -359,57 +388,128 @@ void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads, } } -/* ************************************************************************** */ +bool VolumeMeshBuilder::empty_grid() const +{ +#ifdef WITH_OPENVDB + return !topology_grid || topology_grid->tree().leafCount() == 0; +#else + return true; +#endif +} -struct VoxelAttributeGrid { - float *data; - int channels; -}; +#ifdef WITH_OPENVDB +template<typename GridType> +static openvdb::GridBase::ConstPtr openvdb_grid_from_device_texture(device_texture *image_memory, + float volume_clipping, + Transform transform_3d) +{ + using ValueType = typename GridType::ValueType; + + openvdb::CoordBBox dense_bbox(0, + 0, + 0, + image_memory->data_width - 1, + image_memory->data_height - 1, + image_memory->data_depth - 1); + openvdb::tools::Dense<ValueType, openvdb::tools::MemoryLayout::LayoutXYZ> dense( + dense_bbox, static_cast<ValueType *>(image_memory->host_pointer)); + + typename GridType::Ptr sparse = GridType::create(ValueType(0.0f)); + openvdb::tools::copyFromDense(dense, *sparse, ValueType(volume_clipping)); + + /* copyFromDense will remove any leaf node that contains constant data and replace it with a + * tile, however, we need to preserve the leaves in order to generate the mesh, so revoxelize the + * leaves that were pruned. This should not affect areas that were skipped due to the + * volume_clipping parameter. */ + sparse->tree().voxelizeActiveTiles(); + + /* Compute index to world matrix. */ + float3 voxel_size = make_float3(1.0f / image_memory->data_width, + 1.0f / image_memory->data_height, + 1.0f / image_memory->data_depth); + + transform_3d = transform_inverse(transform_3d); + + openvdb::Mat4R index_to_world_mat((double)(voxel_size.x * transform_3d[0][0]), + 0.0, + 0.0, + 0.0, + 0.0, + (double)(voxel_size.y * transform_3d[1][1]), + 0.0, + 0.0, + 0.0, + 0.0, + (double)(voxel_size.z * transform_3d[2][2]), + 0.0, + (double)transform_3d[0][3], + (double)transform_3d[1][3], + (double)transform_3d[2][3], + 1.0); + + openvdb::math::Transform::Ptr index_to_world_tfm = + openvdb::math::Transform::createLinearTransform(index_to_world_mat); + + sparse->setTransform(index_to_world_tfm); + + return sparse; +} +#endif + +/* ************************************************************************** */ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress) { string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str()); progress.set_status("Updating Mesh", msg); - vector<VoxelAttributeGrid> voxel_grids; - - /* Compute volume parameters. */ - VolumeParams volume_params; - volume_params.resolution = make_int3(0, 0, 0); - - Transform transform = transform_identity(); + VolumeMeshBuilder builder; +#ifdef WITH_OPENVDB foreach (Attribute &attr, mesh->attributes.attributes) { if (attr.element != ATTR_ELEMENT_VOXEL) { continue; } + bool do_clipping = false; + ImageHandle &handle = attr.data_voxel(); - device_texture *image_memory = handle.image_memory(); - int3 resolution = make_int3( - image_memory->data_width, image_memory->data_height, image_memory->data_depth); - if (volume_params.resolution == make_int3(0, 0, 0)) { - volume_params.resolution = resolution; - } - else if (volume_params.resolution != resolution) { - /* TODO: support this as it's common for OpenVDB. */ - VLOG(1) << "Can't create accurate volume mesh, all voxel grid resolutions must be equal\n"; - continue; + /* Try building from OpenVDB grid directly. */ + VDBImageLoader *vdb_loader = handle.vdb_loader(); + openvdb::GridBase::ConstPtr grid; + if (vdb_loader) { + grid = vdb_loader->get_grid(); + + /* If building from an OpenVDB grid, we need to manually clip the values. */ + do_clipping = true; } - VoxelAttributeGrid voxel_grid; - voxel_grid.data = static_cast<float *>(image_memory->host_pointer); - voxel_grid.channels = image_memory->data_elements; - voxel_grids.push_back(voxel_grid); + /* Else fall back to creating an OpenVDB grid from the dense volume data. */ + if (!grid) { + device_texture *image_memory = handle.image_memory(); - /* TODO: support multiple transforms. */ - if (image_memory->info.use_transform_3d) { - transform = image_memory->info.transform_3d; + if (image_memory->data_elements == 1) { + grid = openvdb_grid_from_device_texture<openvdb::FloatGrid>( + image_memory, mesh->volume_clipping, handle.metadata().transform_3d); + } + else if (image_memory->data_elements == 3) { + grid = openvdb_grid_from_device_texture<openvdb::Vec3fGrid>( + image_memory, mesh->volume_clipping, handle.metadata().transform_3d); + } + else if (image_memory->data_elements == 4) { + grid = openvdb_grid_from_device_texture<openvdb::Vec4fGrid>( + image_memory, mesh->volume_clipping, handle.metadata().transform_3d); + } + } + + if (grid) { + builder.add_grid(grid, do_clipping, mesh->volume_clipping); } } +#endif - if (voxel_grids.empty()) { + if (builder.empty_grid()) { return; } @@ -438,56 +538,19 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress) return; } - /* Compute start point and cell size from transform. */ - const int3 resolution = volume_params.resolution; - float3 start_point = make_float3(0.0f, 0.0f, 0.0f); - float3 cell_size = make_float3(1.0f / resolution.x, 1.0f / resolution.y, 1.0f / resolution.z); - - /* TODO: support arbitrary transforms, not just scale + translate. */ - const Transform itfm = transform_inverse(transform); - start_point = transform_point(&itfm, start_point); - cell_size = transform_direction(&itfm, cell_size); + builder.add_padding(pad_size); /* Slightly offset vertex coordinates to avoid overlapping faces with other * volumes or meshes. The proper solution would be to improve intersection in * the kernel to support robust handling of multiple overlapping faces or use * an all-hit intersection similar to shadows. */ - const float3 face_overlap_avoidance = cell_size * 0.1f * - hash_uint_to_float(hash_string(mesh->name.c_str())); - - volume_params.start_point = start_point + face_overlap_avoidance; - volume_params.cell_size = cell_size; - volume_params.pad_size = pad_size; - - /* Build bounding mesh around non-empty volume cells. */ - VolumeMeshBuilder builder(&volume_params); - const float clipping = mesh->volume_clipping; - - for (int z = 0; z < resolution.z; ++z) { - for (int y = 0; y < resolution.y; ++y) { - for (int x = 0; x < resolution.x; ++x) { - int64_t voxel_index = compute_voxel_index(resolution, x, y, z); - - for (size_t i = 0; i < voxel_grids.size(); ++i) { - const VoxelAttributeGrid &voxel_grid = voxel_grids[i]; - const int channels = voxel_grid.channels; - - for (int c = 0; c < channels; c++) { - if (voxel_grid.data[voxel_index * channels + c] >= clipping) { - builder.add_node_with_padding(x, y, z); - break; - } - } - } - } - } - } + const float face_overlap_avoidance = 0.1f * hash_uint_to_float(hash_string(mesh->name.c_str())); /* Create mesh. */ vector<float3> vertices; vector<int> indices; vector<float3> face_normals; - builder.create_mesh(vertices, indices, face_normals); + builder.create_mesh(vertices, indices, face_normals, face_overlap_avoidance); mesh->clear(true); mesh->reserve_mesh(vertices.size(), indices.size() / 3); @@ -514,10 +577,6 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress) indices.size() * sizeof(int)) / (1024.0 * 1024.0) << "Mb."; - - VLOG(1) << "Memory usage volume grid: " - << (resolution.x * resolution.y * resolution.z * sizeof(float)) / (1024.0 * 1024.0) - << "Mb."; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 08a8cb08254..70c4214c684 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -1156,8 +1156,15 @@ bool Session::render_need_denoise(bool &delayed) return false; } + /* Immediately denoise when we reach the start sample or last sample. */ + const int num_samples_finished = tile_manager.state.sample + 1; + if (num_samples_finished == params.denoising.start_sample || + num_samples_finished == params.samples) { + return true; + } + /* Do not denoise until the sample at which denoising should start is reached. */ - if (tile_manager.state.sample < min(params.denoising.start_sample, params.samples - 1)) { + if (num_samples_finished < params.denoising.start_sample) { return false; } diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index f5e488d1bd2..a35ec6c7e29 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -88,6 +88,7 @@ set(SRC_HEADERS util_murmurhash.h util_openimagedenoise.h util_opengl.h + util_openvdb.h util_optimization.h util_param.h util_path.h diff --git a/intern/cycles/util/util_openvdb.h b/intern/cycles/util/util_openvdb.h new file mode 100644 index 00000000000..a3ebb03e5a4 --- /dev/null +++ b/intern/cycles/util/util_openvdb.h @@ -0,0 +1,32 @@ +/* + * Copyright 2011-2020 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. + */ + +#ifndef __UTIL_OPENVDB_H__ +#define __UTIL_OPENVDB_H__ + +#ifdef WITH_OPENVDB +# include <openvdb/openvdb.h> + +namespace openvdb { + +using Vec4fTree = tree::Tree4<Vec4f, 5, 4, 3>::Type; +using Vec4fGrid = Grid<Vec4fTree>; + +}; // namespace openvdb + +#endif + +#endif /* __UTIL_OPENVDB_H__ */ diff --git a/intern/ffmpeg/tests/ffmpeg_codecs.cc b/intern/ffmpeg/tests/ffmpeg_codecs.cc index d3cba6d228a..9538bac84d2 100644 --- a/intern/ffmpeg/tests/ffmpeg_codecs.cc +++ b/intern/ffmpeg/tests/ffmpeg_codecs.cc @@ -5,6 +5,8 @@ extern "C" { #include <libavutil/log.h> } +namespace { + bool test_vcodec(AVCodec *codec, AVPixelFormat pixelformat) { av_log_set_level(AV_LOG_QUIET); @@ -108,6 +110,8 @@ bool test_codec_audio_by_name(const char *codecname, AVSampleFormat fmt) EXPECT_TRUE(test_codec_audio_by_name(str(codec), fmt)); \ } +} // namespace + /* generic codec ID's used in blender */ FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_HUFFYUV, AV_PIX_FMT_BGRA) diff --git a/intern/guardedalloc/tests/guardedalloc_overflow_test.cc b/intern/guardedalloc/tests/guardedalloc_overflow_test.cc index eb9a2a68cb0..e5754bc95ea 100644 --- a/intern/guardedalloc/tests/guardedalloc_overflow_test.cc +++ b/intern/guardedalloc/tests/guardedalloc_overflow_test.cc @@ -11,7 +11,7 @@ # define ABORT_PREDICATE ::testing::KilledBySignal(SIGABRT) #endif -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(__clang__) /* Disable since it's the purpose of this test. */ # pragma GCC diagnostic ignored "-Walloc-size-larger-than=" #endif diff --git a/release/datafiles/icons/brush.paint_texture.draw.dat b/release/datafiles/icons/brush.paint_texture.draw.dat Binary files differindex cfa5f1a6042..678a9ea26e5 100644 --- a/release/datafiles/icons/brush.paint_texture.draw.dat +++ b/release/datafiles/icons/brush.paint_texture.draw.dat diff --git a/release/datafiles/icons/brush.paint_texture.soften.dat b/release/datafiles/icons/brush.paint_texture.soften.dat Binary files differindex 8c547809792..2128de71dff 100644 --- a/release/datafiles/icons/brush.paint_texture.soften.dat +++ b/release/datafiles/icons/brush.paint_texture.soften.dat diff --git a/release/datafiles/icons/brush.paint_vertex.blur.dat b/release/datafiles/icons/brush.paint_vertex.blur.dat Binary files differindex 8c547809792..2128de71dff 100644 --- a/release/datafiles/icons/brush.paint_vertex.blur.dat +++ b/release/datafiles/icons/brush.paint_vertex.blur.dat diff --git a/release/datafiles/icons/brush.paint_vertex.draw.dat b/release/datafiles/icons/brush.paint_vertex.draw.dat Binary files differindex c1a8796ea02..74e00d243d6 100644 --- a/release/datafiles/icons/brush.paint_vertex.draw.dat +++ b/release/datafiles/icons/brush.paint_vertex.draw.dat diff --git a/release/datafiles/icons/brush.paint_weight.blur.dat b/release/datafiles/icons/brush.paint_weight.blur.dat Binary files differindex 8c547809792..2128de71dff 100644 --- a/release/datafiles/icons/brush.paint_weight.blur.dat +++ b/release/datafiles/icons/brush.paint_weight.blur.dat diff --git a/release/datafiles/icons/brush.paint_weight.draw.dat b/release/datafiles/icons/brush.paint_weight.draw.dat Binary files differindex cdb4ccf5efb..a2641927371 100644 --- a/release/datafiles/icons/brush.paint_weight.draw.dat +++ b/release/datafiles/icons/brush.paint_weight.draw.dat diff --git a/release/datafiles/icons/brush.particle.length.dat b/release/datafiles/icons/brush.particle.length.dat Binary files differindex 59e74fd9912..d088110b432 100644 --- a/release/datafiles/icons/brush.particle.length.dat +++ b/release/datafiles/icons/brush.particle.length.dat diff --git a/release/datafiles/icons/brush.particle.puff.dat b/release/datafiles/icons/brush.particle.puff.dat Binary files differindex 9dd194bfd93..db2bab46bfe 100644 --- a/release/datafiles/icons/brush.particle.puff.dat +++ b/release/datafiles/icons/brush.particle.puff.dat diff --git a/release/datafiles/icons/brush.particle.smooth.dat b/release/datafiles/icons/brush.particle.smooth.dat Binary files differindex 54b80a25841..7deaa4ed082 100644 --- a/release/datafiles/icons/brush.particle.smooth.dat +++ b/release/datafiles/icons/brush.particle.smooth.dat diff --git a/release/datafiles/icons/brush.sculpt.cloth.dat b/release/datafiles/icons/brush.sculpt.cloth.dat Binary files differindex 5e8fad60035..7e936167381 100644 --- a/release/datafiles/icons/brush.sculpt.cloth.dat +++ b/release/datafiles/icons/brush.sculpt.cloth.dat diff --git a/release/datafiles/icons/brush.sculpt.draw.dat b/release/datafiles/icons/brush.sculpt.draw.dat Binary files differindex 36ec5575bdd..014ce10e8cc 100644 --- a/release/datafiles/icons/brush.sculpt.draw.dat +++ b/release/datafiles/icons/brush.sculpt.draw.dat diff --git a/release/datafiles/icons/brush.sculpt.draw_sharp.dat b/release/datafiles/icons/brush.sculpt.draw_sharp.dat Binary files differindex ad42f4bf870..9bea1b02894 100644 --- a/release/datafiles/icons/brush.sculpt.draw_sharp.dat +++ b/release/datafiles/icons/brush.sculpt.draw_sharp.dat diff --git a/release/datafiles/icons/brush.sculpt.elastic_deform.dat b/release/datafiles/icons/brush.sculpt.elastic_deform.dat Binary files differindex 6d0ea25c1fe..0b12d717d3a 100644 --- a/release/datafiles/icons/brush.sculpt.elastic_deform.dat +++ b/release/datafiles/icons/brush.sculpt.elastic_deform.dat diff --git a/release/datafiles/icons/brush.sculpt.layer.dat b/release/datafiles/icons/brush.sculpt.layer.dat Binary files differindex 184f1bc9c13..1031d95332a 100644 --- a/release/datafiles/icons/brush.sculpt.layer.dat +++ b/release/datafiles/icons/brush.sculpt.layer.dat diff --git a/release/datafiles/icons/brush.sculpt.nudge.dat b/release/datafiles/icons/brush.sculpt.nudge.dat Binary files differindex 309a01a5645..e10157e9cd0 100644 --- a/release/datafiles/icons/brush.sculpt.nudge.dat +++ b/release/datafiles/icons/brush.sculpt.nudge.dat diff --git a/release/datafiles/icons/brush.sculpt.rotate.dat b/release/datafiles/icons/brush.sculpt.rotate.dat Binary files differindex a0bb63d14db..d63f1e3d7d4 100644 --- a/release/datafiles/icons/brush.sculpt.rotate.dat +++ b/release/datafiles/icons/brush.sculpt.rotate.dat diff --git a/release/datafiles/icons/brush.sculpt.snake_hook.dat b/release/datafiles/icons/brush.sculpt.snake_hook.dat Binary files differindex 64256d93702..20300c1d97c 100644 --- a/release/datafiles/icons/brush.sculpt.snake_hook.dat +++ b/release/datafiles/icons/brush.sculpt.snake_hook.dat diff --git a/release/datafiles/icons/brush.sculpt.thumb.dat b/release/datafiles/icons/brush.sculpt.thumb.dat Binary files differindex a2634afced9..9da33eccd98 100644 --- a/release/datafiles/icons/brush.sculpt.thumb.dat +++ b/release/datafiles/icons/brush.sculpt.thumb.dat diff --git a/release/datafiles/icons/ops.paint.weight_sample.dat b/release/datafiles/icons/ops.paint.weight_sample.dat Binary files differindex 423365f5a55..e8d20582f9a 100644 --- a/release/datafiles/icons/ops.paint.weight_sample.dat +++ b/release/datafiles/icons/ops.paint.weight_sample.dat diff --git a/release/datafiles/icons/ops.paint.weight_sample_group.dat b/release/datafiles/icons/ops.paint.weight_sample_group.dat Binary files differindex b37eb59ad23..7994db12d1b 100644 --- a/release/datafiles/icons/ops.paint.weight_sample_group.dat +++ b/release/datafiles/icons/ops.paint.weight_sample_group.dat diff --git a/release/datafiles/icons/ops.sculpt.cloth_filter.dat b/release/datafiles/icons/ops.sculpt.cloth_filter.dat Binary files differnew file mode 100644 index 00000000000..dc20c8f0bfd --- /dev/null +++ b/release/datafiles/icons/ops.sculpt.cloth_filter.dat diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject a7bbfac76c00edd0fb79a4766b7ac7c5dcbcac5 +Subproject 4af22e0492f401c609a0203cad1a9bc7fa00b86 diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 82ed41ec632483fa9260d90dae7afdf3192c509 +Subproject 25b00a0a52c81408b9dc15ea320a79ee956b3c0 diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index c11350dca53..52e5bebefe4 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -1926,6 +1926,12 @@ def km_file_browser_main(params): items.extend([ ("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, {"properties": [("need_active", True)]}), + # Both .execute and .select are needed here. The former only works if + # there's a file operator (i.e. not in regular editor mode) but is + # needed to load files. The latter makes selection work if there's no + # operator (i.e. in regular editor mode). + ("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, + {"properties": [("open", True), ("deselect_all", not params.legacy)]}), ("file.refresh", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), ("file.select", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("open", False), ("deselect_all", not params.legacy)]}), @@ -6364,6 +6370,18 @@ def km_3d_view_tool_sculpt_mask_by_color(params): ]}, ) +def km_3d_view_tool_sculpt_face_set_edit(params): + return ( + "3D View Tool: Sculpt, Face Set Edit", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": [ + ("sculpt.face_set_edit", {"type": params.tool_mouse, "value": 'ANY'}, + None), + ("sculpt.face_set_edit", {"type": params.tool_tweak, "value": 'ANY'}, + None) + ]}, + ) + def km_3d_view_tool_paint_weight_sample_weight(params): return ( "3D View Tool: Paint Weight, Sample Weight", @@ -6399,12 +6417,12 @@ def km_3d_view_tool_paint_gpencil_line(params): "3D View Tool: Paint Gpencil, Line", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'LINE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'LINE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, - {"properties": [("type", 'LINE'), ("wait_for_input", False)]}), + ("gpencil.primitive_line", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_line", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_line", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6415,10 +6433,10 @@ def km_3d_view_tool_paint_gpencil_polyline(params): "3D View Tool: Paint Gpencil, Polyline", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'POLYLINE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'POLYLINE'), ("wait_for_input", False)]}), + ("gpencil.primitive_polyline", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_polyline", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6429,12 +6447,12 @@ def km_3d_view_tool_paint_gpencil_box(params): "3D View Tool: Paint Gpencil, Box", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'BOX'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'BOX'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, - {"properties": [("type", 'BOX'), ("wait_for_input", False)]}), + ("gpencil.primitive_box", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_box", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_box", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6446,12 +6464,12 @@ def km_3d_view_tool_paint_gpencil_circle(params): "3D View Tool: Paint Gpencil, Circle", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, - {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}), + ("gpencil.primitive_circle", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_circle", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_circle", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6463,12 +6481,12 @@ def km_3d_view_tool_paint_gpencil_arc(params): "3D View Tool: Paint Gpencil, Arc", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'ARC'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + ("gpencil.primitive_curve", {"type": params.tool_tweak, "value": 'ANY'}, {"properties": [("type", 'ARC'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + ("gpencil.primitive_curve", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, {"properties": [("type", 'ARC'), ("wait_for_input", False)]}), + ("gpencil.primitive_curve", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("type",'ARC'), ("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6480,7 +6498,7 @@ def km_3d_view_tool_paint_gpencil_curve(params): "3D View Tool: Paint Gpencil, Curve", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, + ("gpencil.primitive_curve", {"type": params.tool_tweak, "value": 'ANY'}, {"properties": [("type", 'CURVE'), ("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), @@ -6908,6 +6926,7 @@ def generate_keymaps(params=None): km_3d_view_tool_sculpt_cloth_filter(params), km_3d_view_tool_sculpt_color_filter(params), km_3d_view_tool_sculpt_mask_by_color(params), + km_3d_view_tool_sculpt_face_set_edit(params), km_3d_view_tool_paint_weight_sample_weight(params), km_3d_view_tool_paint_weight_sample_vertex_group(params), km_3d_view_tool_paint_weight_gradient(params), diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py index e92f493960a..ceef2df63ff 100644 --- a/release/scripts/startup/bl_operators/userpref.py +++ b/release/scripts/startup/bl_operators/userpref.py @@ -354,7 +354,7 @@ class PREFERENCES_OT_keyitem_restore(Operator): item_id: IntProperty( name="Item Identifier", - description="Identifier of the item to remove", + description="Identifier of the item to restore", ) @classmethod diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 77308fed014..7ff2688f2a7 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -350,7 +350,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel): if enable_edit or (ob.use_shape_key_edit_mode and ob.type == 'MESH'): enable_pin = True - if ob.show_only_shape_key: + if ob.show_only_shape_key is False: enable_edit_value = True row = layout.row() diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index f1004358418..6a541863aef 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -722,6 +722,8 @@ def brush_settings(layout, context, brush, popover=False): elif sculpt_tool == 'BOUNDARY': col = layout.column() col.prop(brush, "boundary_deform_type") + col.prop(brush, "boundary_falloff_type") + col.prop(brush, "boundary_offset") elif sculpt_tool == 'TOPOLOGY': col = layout.column() @@ -1109,6 +1111,45 @@ def brush_basic_texpaint_settings(layout, context, brush, *, compact=False): header=True ) +def brush_basic__draw_color_selector(context, layout, brush, gp_settings, props): + tool_settings = context.scene.tool_settings + settings = tool_settings.gpencil_paint + ma = gp_settings.material + + row = layout.row(align=True) + if not gp_settings.use_material_pin: + ma = context.object.active_material + icon_id = 0 + if ma: + icon_id = ma.id_data.preview.icon_id + txt_ma = ma.name + maxw = 25 + if len(txt_ma) > maxw: + txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:] + else: + txt_ma = "" + + sub = row.row() + sub.ui_units_x = 8 + sub.popover( + panel="TOPBAR_PT_gpencil_materials", + text=txt_ma, + icon_value=icon_id, + ) + + row.prop(gp_settings, "use_material_pin", text="") + + if brush.gpencil_tool in {'DRAW', 'FILL'}: + row.separator(factor=1.0) + row.prop_enum(settings, "color_mode", 'MATERIAL', text="", icon='MATERIAL') + row.prop_enum(settings, "color_mode", 'VERTEXCOLOR', text="", icon='VPAINT_HLT') + sub_row = row.row(align=True) + sub_row.enabled = settings.color_mode == 'VERTEXCOLOR' + sub_row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor") + + if props: + row = layout.row(align=True) + row.prop(props, "subdivision") def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False): tool_settings = context.tool_settings diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 9f251a9abad..19c1c2e02c4 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -327,6 +327,7 @@ class SEQUENCER_MT_view(Menu): if is_preview: layout.separator() if st.display_mode == 'IMAGE': + layout.prop(st, "zoom_to_fit") layout.prop(ed, "show_overlay", text="Show Frame Overlay") layout.prop(st, "show_safe_areas", text="Show Safe Areas") layout.prop(st, "show_metadata", text="Show Metadata") diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index d07241203fb..38879d41a64 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1335,6 +1335,22 @@ class _defs_sculpt: draw_settings=draw_settings, ) + @ToolDef.from_fn + def face_set_edit(): + def draw_settings(_context, layout, tool): + props = tool.operator_properties("sculpt.face_set_edit") + layout.prop(props, "mode", expand=False) + layout.prop(props, "modify_hidden") + + return dict( + idname="builtin.face_set_edit", + label="Edit Face Set", + icon="ops.sculpt.face_set_edit", + widget=None, + keymap="3D View Tool: Sculpt, Face Set Edit", + draw_settings=draw_settings, + ) + class _defs_vertex_paint: @@ -1671,6 +1687,29 @@ class _defs_image_uv_sculpt: class _defs_gpencil_paint: @staticmethod + def gpencil_primitive_toolbar(context, layout, tool, props): + paint = context.tool_settings.gpencil_paint + brush = paint.brush + + if brush is None: + return False + + gp_settings = brush.gpencil_settings + + row = layout.row(align=True) + tool_settings = context.scene.tool_settings + settings = tool_settings.gpencil_paint + row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) + + from bl_ui.properties_paint_common import ( + brush_basic_gpencil_paint_settings, + brush_basic__draw_color_selector, + ) + + brush_basic__draw_color_selector(context, layout, brush, gp_settings, props) + brush_basic_gpencil_paint_settings(layout, context, brush, compact=True) + + @staticmethod def generate_from_brushes(context): return generate_from_enum_ex( context, @@ -1697,6 +1736,10 @@ class _defs_gpencil_paint: @ToolDef.from_fn def line(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_line") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.line", label="Line", @@ -1704,10 +1747,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def polyline(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_polyline") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.polyline", label="Polyline", @@ -1715,10 +1763,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def box(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_box") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.box", label="Box", @@ -1726,10 +1779,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def circle(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_circle") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.circle", label="Circle", @@ -1737,10 +1795,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def arc(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_curve") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.arc", label="Arc", @@ -1748,10 +1811,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def curve(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_curve") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.curve", label="Curve", @@ -1759,6 +1827,7 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn @@ -2542,6 +2611,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): else () ), None, + _defs_sculpt.face_set_edit, + None, _defs_transform.translate, _defs_transform.rotate, _defs_transform.scale, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 0c4680ea6ba..72f0128965c 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -385,19 +385,7 @@ class _draw_tool_settings_context_mode: if tool is None: return False - # is_paint = True - # FIXME: tools must use their own UI drawing! - if tool.idname in { - "builtin.line", - "builtin.box", - "builtin.circle", - "builtin.arc", - "builtin.curve", - "builtin.polyline", - }: - # is_paint = False - pass - elif tool.idname == "builtin.cutter": + if tool.idname == "builtin.cutter": row = layout.row(align=True) row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold") return False @@ -411,47 +399,16 @@ class _draw_tool_settings_context_mode: gp_settings = brush.gpencil_settings - def draw_color_selector(): - ma = gp_settings.material - row = layout.row(align=True) - if not gp_settings.use_material_pin: - ma = context.object.active_material - icon_id = 0 - if ma: - icon_id = ma.id_data.preview.icon_id - txt_ma = ma.name - maxw = 25 - if len(txt_ma) > maxw: - txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:] - else: - txt_ma = "" - - sub = row.row() - sub.ui_units_x = 8 - sub.popover( - panel="TOPBAR_PT_gpencil_materials", - text=txt_ma, - icon_value=icon_id, - ) - - row.prop(gp_settings, "use_material_pin", text="") - - if brush.gpencil_tool in {'DRAW', 'FILL'}: - row.separator(factor=1.0) - subrow = row.row(align=True) - row.prop_enum(settings, "color_mode", 'MATERIAL', text="", icon='MATERIAL') - row.prop_enum(settings, "color_mode", 'VERTEXCOLOR', text="", icon='VPAINT_HLT') - sub_row = row.row(align=True) - sub_row.enabled = settings.color_mode == 'VERTEXCOLOR' - sub_row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor") - row = layout.row(align=True) tool_settings = context.scene.tool_settings settings = tool_settings.gpencil_paint row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}: - draw_color_selector() + from bl_ui.properties_paint_common import ( + brush_basic__draw_color_selector, + ) + brush_basic__draw_color_selector(context, layout, brush, gp_settings, None) if context.object and brush.gpencil_tool == 'TINT': row.separator(factor=0.4) diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 9013836fd1e..bf84f5c57b3 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -42,8 +42,7 @@ int BLF_init(void); void BLF_exit(void); void BLF_default_dpi(int dpi); void BLF_default_set(int fontid); -int BLF_default(void); /* get default font ID so we can pass it to other functions */ -void BLF_batch_reset(void); /* call when changing opengl context. */ +int BLF_default(void); /* get default font ID so we can pass it to other functions */ void BLF_cache_clear(void); diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 95b074fa2df..c5c2bc3f3ba 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -125,11 +125,6 @@ void BLF_exit(void) blf_font_exit(); } -void BLF_batch_reset(void) -{ - blf_batch_draw_vao_clear(); -} - void BLF_cache_clear(void) { FontBLF *font; diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index ff31878a929..76829db755c 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -113,13 +113,6 @@ static void blf_batch_draw_exit(void) GPU_BATCH_DISCARD_SAFE(g_batch.batch); } -void blf_batch_draw_vao_clear(void) -{ - if (g_batch.batch) { - GPU_batch_vao_cache_clear(g_batch.batch); - } -} - void blf_batch_draw_begin(FontBLF *font) { if (g_batch.batch == NULL) { diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index ba0873f4fd4..b616f47a897 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -30,7 +30,6 @@ struct ResultBLF; struct rctf; struct rcti; -void blf_batch_draw_vao_clear(void); void blf_batch_draw_begin(struct FontBLF *font); void blf_batch_draw(void); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index ae0a669bfb3..6ea113d8828 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -44,7 +44,7 @@ extern "C" { /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file * was written with too new a version. */ -#define BLENDER_FILE_MIN_VERSION 280 +#define BLENDER_FILE_MIN_VERSION 290 #define BLENDER_FILE_MIN_SUBVERSION 0 /** User readable version string. */ diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index a2ad4f7dc2a..429ddf4e551 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -137,6 +137,11 @@ bool BKE_gpencil_merge_materials_table_get(struct Object *ob, const float sat_threshold, const float val_threshold, struct GHash *r_mat_table); +bool BKE_gpencil_merge_materials(struct Object *ob, + const float hue_threshold, + const float sat_threshold, + const float val_threshold, + int *r_removed); /* statistics functions */ void BKE_gpencil_stats_update(struct bGPdata *gpd); diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h index 6a9271700e8..dd41762c046 100644 --- a/source/blender/blenkernel/BKE_gpencil_curve.h +++ b/source/blender/blenkernel/BKE_gpencil_curve.h @@ -38,9 +38,9 @@ void BKE_gpencil_convert_curve(struct Main *bmain, struct Scene *scene, struct Object *ob_gp, struct Object *ob_cu, - const bool gpencil_lines, const bool use_collections, - const bool only_stroke); + const float scale_thickness, + const float sample); struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps, float error_threshold); diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index f9590696c2e..98dc411239e 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -413,9 +413,13 @@ void BKE_modifier_type_panel_id(ModifierType type, char *r_idname); * default values if pointer is optional. */ struct ModifierData *BKE_modifier_new(int type); + void BKE_modifier_free_ex(struct ModifierData *md, const int flag); void BKE_modifier_free(struct ModifierData *md); +/* Generate new UUID for the given modifier. */ +void BKE_modifier_session_uuid_generate(struct ModifierData *md); + bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md); void BKE_modifier_copydata_generic(const struct ModifierData *md, @@ -539,6 +543,8 @@ void BKE_modifier_deform_vertsEM(ModifierData *md, struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval, const bool get_cage_mesh); +void BKE_modifier_check_uuids_unique_and_report(const struct Object *object); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 215f4043e34..2029f4d38a1 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -409,6 +409,8 @@ struct Mesh *BKE_object_to_mesh(struct Depsgraph *depsgraph, void BKE_object_to_mesh_clear(struct Object *object); +void BKE_object_check_uuids_unique_and_report(const struct Object *object); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 58687858a9e..7b63a4154fa 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -337,6 +337,11 @@ typedef struct SculptBoundary { int vertices_capacity; int num_vertices; + /* Distance from a vertex in the boundary to initial vertex indexed by vertex index, taking into + * account the lengh of all edges between them. Any vertex that is not in the boundary will have + * a distance of 0. */ + float *distance; + /* Data for drawing the preview. */ SculptBoundaryPreviewEdge *edges; int edges_capacity; diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index edab543fc37..1090deae93f 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -183,6 +183,16 @@ typedef struct ARegionType { /* return context data */ int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result); + /* Is called whenever the current visible View2D's region changes. + * + * Used from user code such as view navigation/zoom operators to inform region about changes. + * The goal is to support zoom-to-fit features which gets disabled when manual navigation is + * performed. + * + * This callback is not called on indirect changes of the current viewport (which could happen + * when the `v2d->tot is changed and `cur` is adopted accordingly). */ + void (*on_view2d_changed)(const struct bContext *C, struct ARegion *region); + /* custom drawing callbacks */ ListBase drawcalls; diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 2277eb27ef1..7833ba9c046 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -311,6 +311,9 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, SubdivCCGNeighbors *r_neighbors); int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index); +void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + float r_point[3]); typedef enum SubdivCCGAdjacencyType { SUBDIV_CCG_ADJACENT_NONE, diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 63e7933dd56..0dc85dfaa18 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1810,6 +1810,12 @@ static void mesh_build_data(struct Depsgraph *depsgraph, BKE_object_boundbox_calc_from_mesh(ob, mesh_eval); + /* Make sure that drivers can target shapekey properties. + * Note that this causes a potential inconsistency, as the shapekey may have a + * different topology than the evaluated mesh. */ + BLI_assert(mesh->key == NULL || DEG_is_evaluated_id(&mesh->key->id)); + mesh_eval->key = mesh->key; + if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { if (DEG_is_active(depsgraph)) { BKE_sculpt_update_object_after_eval(depsgraph, ob); diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index e2d17f34992..1833ad5a748 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -165,7 +165,7 @@ void BKE_bpath_relative_rebase(Main *bmain, ReportList *reports) { BPathRebase_Data data = {NULL}; - const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY; + const int flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE); BLI_assert(basedir_src[0] != '\0'); BLI_assert(basedir_dst[0] != '\0'); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index af186dc4940..8cd30c2241f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -1481,6 +1481,11 @@ void BKE_brush_sculpt_reset(Brush *br) br->curve_preset = BRUSH_CURVE_POW4; br->spacing = 5; break; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + br->curve_preset = BRUSH_CURVE_SMOOTHER; + br->spacing = 10; + br->alpha = 1.0f; + break; case SCULPT_TOOL_SLIDE_RELAX: br->spacing = 10; br->alpha = 1.0f; @@ -1680,6 +1685,7 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_PAINT: case SCULPT_TOOL_MASK: case SCULPT_TOOL_DRAW_FACE_SETS: + case SCULPT_TOOL_DISPLACEMENT_ERASER: br->add_col[0] = 0.75f; br->add_col[1] = 0.75f; br->add_col[2] = 0.75f; diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 6d2432f53e4..0d65ee5faa3 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -408,9 +408,9 @@ static Collection *collection_duplicate_recursive(Main *bmain, } if (do_objects) { - /* We can loop on collection_old's objects, that list is currently identical the collection_new - * objects, and won't be changed here. */ - LISTBASE_FOREACH (CollectionObject *, cob, &collection_old->gobject) { + /* We can loop on collection_old's objects, but have to consider it mutable because with master + * collections collection_old and collection_new are the same data here. */ + LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection_old->gobject) { Object *ob_old = cob->ob; Object *ob_new = (Object *)ob_old->id.newid; diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index f358355912b..05c521e3b94 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -647,6 +647,31 @@ DO_INLINE void collision_interpolateOnTriangle(float to[3], VECADDMUL(to, v3, w3); } +static void cloth_selfcollision_impulse_vert(const float clamp_sq, + const float impulse[3], + struct ClothVertex *vert) +{ + float impulse_len_sq = len_squared_v3(impulse); + + if ((clamp_sq > 0.0f) && (impulse_len_sq > clamp_sq)) { + return; + } + + if (fabsf(vert->impulse[0]) < fabsf(impulse[0])) { + vert->impulse[0] = impulse[0]; + } + + if (fabsf(vert->impulse[1]) < fabsf(impulse[1])) { + vert->impulse[1] = impulse[1]; + } + + if (fabsf(vert->impulse[2]) < fabsf(impulse[2])) { + vert->impulse[2] = impulse[2]; + } + + vert->impulse_count++; +} + static int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, Object *collob, @@ -655,18 +680,17 @@ static int cloth_collision_response_static(ClothModifierData *clmd, const float dt) { int result = 0; - Cloth *cloth1; - float w1, w2, w3, u1, u2, u3; - float v1[3], v2[3], relativeVelocity[3]; - float magrelVel; - float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); - const bool is_hair = (clmd->hairdata != NULL); - - cloth1 = clmd->clothObject; + Cloth *cloth = clmd->clothObject; + const float clamp_sq = square_f(clmd->coll_parms->self_clamp * dt); + const float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); + const float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + const float min_distance = (clmd->coll_parms->epsilon + epsilon2) * (8.0f / 9.0f); + const bool is_hair = (clmd->hairdata != NULL); for (int i = 0; i < collision_count; i++, collpair++) { float i1[3], i2[3], i3[3]; - + float w1, w2, w3, u1, u2, u3; + float v1[3], v2[3], relativeVelocity[3]; zero_v3(i1); zero_v3(i2); zero_v3(i3); @@ -679,25 +703,25 @@ static int cloth_collision_response_static(ClothModifierData *clmd, /* Compute barycentric coordinates and relative "velocity" for both collision points. */ if (is_hair) { w2 = line_point_factor_v3( - collpair->pa, cloth1->verts[collpair->ap1].tx, cloth1->verts[collpair->ap2].tx); + collpair->pa, cloth->verts[collpair->ap1].tx, cloth->verts[collpair->ap2].tx); w1 = 1.0f - w2; - interp_v3_v3v3(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w2); + interp_v3_v3v3(v1, cloth->verts[collpair->ap1].tv, cloth->verts[collpair->ap2].tv, w2); } else { collision_compute_barycentric(collpair->pa, - cloth1->verts[collpair->ap1].tx, - cloth1->verts[collpair->ap2].tx, - cloth1->verts[collpair->ap3].tx, + cloth->verts[collpair->ap1].tx, + cloth->verts[collpair->ap2].tx, + cloth->verts[collpair->ap3].tx, &w1, &w2, &w3); collision_interpolateOnTriangle(v1, - cloth1->verts[collpair->ap1].tv, - cloth1->verts[collpair->ap2].tv, - cloth1->verts[collpair->ap3].tv, + cloth->verts[collpair->ap1].tv, + cloth->verts[collpair->ap2].tv, + cloth->verts[collpair->ap3].tv, w1, w2, w3); @@ -723,16 +747,16 @@ static int cloth_collision_response_static(ClothModifierData *clmd, /* Calculate the normal component of the relative velocity * (actually only the magnitude - the direction is stored in 'normal'). */ - magrelVel = dot_v3v3(relativeVelocity, collpair->normal); + const float magrelVel = dot_v3v3(relativeVelocity, collpair->normal); + const float d = min_distance - collpair->distance; /* If magrelVel < 0 the edges are approaching each other. */ if (magrelVel > 0.0f) { /* Calculate Impulse magnitude to stop all motion in normal direction. */ - float magtangent = 0, repulse = 0, d = 0; + float magtangent = 0, repulse = 0; double impulse = 0.0; float vrel_t_pre[3]; float temp[3]; - float time_multiplier; /* Calculate tangential velocity. */ copy_v3_v3(temp, collpair->normal); @@ -750,32 +774,23 @@ static int cloth_collision_response_static(ClothModifierData *clmd, impulse = magtangent / 1.5; - VECADDMUL(i1, vrel_t_pre, w1 * impulse); - VECADDMUL(i2, vrel_t_pre, w2 * impulse); + VECADDMUL(i1, vrel_t_pre, (double)w1 * impulse); + VECADDMUL(i2, vrel_t_pre, (double)w2 * impulse); if (!is_hair) { - VECADDMUL(i3, vrel_t_pre, w3 * impulse); + VECADDMUL(i3, vrel_t_pre, (double)w3 * impulse); } } /* Apply velocity stopping impulse. */ impulse = magrelVel / 1.5f; - VECADDMUL(i1, collpair->normal, w1 * impulse); - cloth1->verts[collpair->ap1].impulse_count++; - - VECADDMUL(i2, collpair->normal, w2 * impulse); - cloth1->verts[collpair->ap2].impulse_count++; - + VECADDMUL(i1, collpair->normal, (double)w1 * impulse); + VECADDMUL(i2, collpair->normal, (double)w2 * impulse); if (!is_hair) { - VECADDMUL(i3, collpair->normal, w3 * impulse); - cloth1->verts[collpair->ap3].impulse_count++; + VECADDMUL(i3, collpair->normal, (double)w3 * impulse); } - time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); - - d = clmd->coll_parms->epsilon * 8.0f / 9.0f + epsilon2 * 8.0f / 9.0f - collpair->distance; - if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) { repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel); @@ -790,7 +805,6 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, collpair->normal, impulse); VECADDMUL(i2, collpair->normal, impulse); - if (!is_hair) { VECADDMUL(i3, collpair->normal, impulse); } @@ -798,60 +812,26 @@ static int cloth_collision_response_static(ClothModifierData *clmd, result = 1; } - else { - float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); - float d; - - d = clmd->coll_parms->epsilon * 8.0f / 9.0f + epsilon2 * 8.0f / 9.0f - collpair->distance; - - if (d > ALMOST_ZERO) { - /* Stay on the safe side and clamp repulse. */ - float repulse = d / time_multiplier; - float impulse = repulse / 4.5f; - - VECADDMUL(i1, collpair->normal, w1 * impulse); - VECADDMUL(i2, collpair->normal, w2 * impulse); + else if (d > ALMOST_ZERO) { + /* Stay on the safe side and clamp repulse. */ + float repulse = d / time_multiplier; + float impulse = repulse / 4.5f; - if (!is_hair) { - VECADDMUL(i3, collpair->normal, w3 * impulse); - } - - cloth1->verts[collpair->ap1].impulse_count++; - cloth1->verts[collpair->ap2].impulse_count++; - - if (!is_hair) { - cloth1->verts[collpair->ap3].impulse_count++; - } + VECADDMUL(i1, collpair->normal, w1 * impulse); + VECADDMUL(i2, collpair->normal, w2 * impulse); - result = 1; + if (!is_hair) { + VECADDMUL(i3, collpair->normal, w3 * impulse); } + + result = 1; } if (result) { - float clamp = clmd->coll_parms->clamp * dt; - - if ((clamp > 0.0f) && - ((len_v3(i1) > clamp) || (len_v3(i2) > clamp) || (len_v3(i3) > clamp))) { - return 0; - } - - for (int j = 0; j < 3; j++) { - if (cloth1->verts[collpair->ap1].impulse_count > 0 && - fabsf(cloth1->verts[collpair->ap1].impulse[j]) < fabsf(i1[j])) { - cloth1->verts[collpair->ap1].impulse[j] = i1[j]; - } - - if (cloth1->verts[collpair->ap2].impulse_count > 0 && - fabsf(cloth1->verts[collpair->ap2].impulse[j]) < fabsf(i2[j])) { - cloth1->verts[collpair->ap2].impulse[j] = i2[j]; - } - - if (!is_hair) { - if (cloth1->verts[collpair->ap3].impulse_count > 0 && - fabsf(cloth1->verts[collpair->ap3].impulse[j]) < fabsf(i3[j])) { - cloth1->verts[collpair->ap3].impulse[j] = i3[j]; - } - } + cloth_selfcollision_impulse_vert(clamp_sq, i1, &cloth->verts[collpair->ap1]); + cloth_selfcollision_impulse_vert(clamp_sq, i2, &cloth->verts[collpair->ap2]); + if (!is_hair) { + cloth_selfcollision_impulse_vert(clamp_sq, i3, &cloth->verts[collpair->ap3]); } } } @@ -859,47 +839,22 @@ static int cloth_collision_response_static(ClothModifierData *clmd, return result; } -static void cloth_selfcollision_impulse_vert(const float clamp_sq, - const float impulse[3], - struct ClothVertex *vert) -{ - float impulse_len_sq = len_squared_v3(impulse); - - if ((clamp_sq > 0.0f) && (impulse_len_sq > clamp_sq)) { - return; - } - - if (fabsf(vert->impulse[0]) < fabsf(impulse[0])) { - vert->impulse[0] = impulse[0]; - } - - if (fabsf(vert->impulse[1]) < fabsf(impulse[1])) { - vert->impulse[1] = impulse[1]; - } - - if (fabsf(vert->impulse[2]) < fabsf(impulse[2])) { - vert->impulse[2] = impulse[2]; - } - - vert->impulse_count++; -} - static int cloth_selfcollision_response_static(ClothModifierData *clmd, CollPair *collpair, uint collision_count, const float dt) { int result = 0; - Cloth *cloth1; - float w1, w2, w3, u1, u2, u3; - float v1[3], v2[3], relativeVelocity[3]; - float magrelVel; - - cloth1 = clmd->clothObject; + Cloth *cloth = clmd->clothObject; + const float clamp_sq = square_f(clmd->coll_parms->self_clamp * dt); + const float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); + const float min_distance = (2.0f * clmd->coll_parms->selfepsilon) * (8.0f / 9.0f); for (int i = 0; i < collision_count; i++, collpair++) { float ia[3][3] = {{0.0f}}; float ib[3][3] = {{0.0f}}; + float w1, w2, w3, u1, u2, u3; + float v1[3], v2[3], relativeVelocity[3]; /* Only handle static collisions here. */ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) { @@ -908,34 +863,34 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, /* Compute barycentric coordinates for both collision points. */ collision_compute_barycentric(collpair->pa, - cloth1->verts[collpair->ap1].tx, - cloth1->verts[collpair->ap2].tx, - cloth1->verts[collpair->ap3].tx, + cloth->verts[collpair->ap1].tx, + cloth->verts[collpair->ap2].tx, + cloth->verts[collpair->ap3].tx, &w1, &w2, &w3); collision_compute_barycentric(collpair->pb, - cloth1->verts[collpair->bp1].tx, - cloth1->verts[collpair->bp2].tx, - cloth1->verts[collpair->bp3].tx, + cloth->verts[collpair->bp1].tx, + cloth->verts[collpair->bp2].tx, + cloth->verts[collpair->bp3].tx, &u1, &u2, &u3); /* Calculate relative "velocity". */ collision_interpolateOnTriangle(v1, - cloth1->verts[collpair->ap1].tv, - cloth1->verts[collpair->ap2].tv, - cloth1->verts[collpair->ap3].tv, + cloth->verts[collpair->ap1].tv, + cloth->verts[collpair->ap2].tv, + cloth->verts[collpair->ap3].tv, w1, w2, w3); collision_interpolateOnTriangle(v2, - cloth1->verts[collpair->bp1].tv, - cloth1->verts[collpair->bp2].tv, - cloth1->verts[collpair->bp3].tv, + cloth->verts[collpair->bp1].tv, + cloth->verts[collpair->bp2].tv, + cloth->verts[collpair->bp3].tv, u1, u2, u3); @@ -944,7 +899,8 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, /* Calculate the normal component of the relative velocity * (actually only the magnitude - the direction is stored in 'normal'). */ - magrelVel = dot_v3v3(relativeVelocity, collpair->normal); + const float magrelVel = dot_v3v3(relativeVelocity, collpair->normal); + const float d = min_distance - collpair->distance; /* TODO: Impulses should be weighed by mass as this is self col, * this has to be done after mass distribution is implemented. */ @@ -952,10 +908,10 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, /* If magrelVel < 0 the edges are approaching each other. */ if (magrelVel > 0.0f) { /* Calculate Impulse magnitude to stop all motion in normal direction. */ - float magtangent = 0, repulse = 0, d = 0; + float magtangent = 0, repulse = 0; double impulse = 0.0; float vrel_t_pre[3]; - float temp[3], time_multiplier; + float temp[3]; /* Calculate tangential velocity. */ copy_v3_v3(temp, collpair->normal); @@ -973,29 +929,25 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, impulse = magtangent / 1.5; - VECADDMUL(ia[0], vrel_t_pre, w1 * impulse); - VECADDMUL(ia[1], vrel_t_pre, w2 * impulse); - VECADDMUL(ia[2], vrel_t_pre, w3 * impulse); + VECADDMUL(ia[0], vrel_t_pre, (double)w1 * impulse); + VECADDMUL(ia[1], vrel_t_pre, (double)w2 * impulse); + VECADDMUL(ia[2], vrel_t_pre, (double)w3 * impulse); - VECADDMUL(ib[0], vrel_t_pre, -u1 * impulse); - VECADDMUL(ib[1], vrel_t_pre, -u2 * impulse); - VECADDMUL(ib[2], vrel_t_pre, -u3 * impulse); + VECADDMUL(ib[0], vrel_t_pre, (double)u1 * -impulse); + VECADDMUL(ib[1], vrel_t_pre, (double)u2 * -impulse); + VECADDMUL(ib[2], vrel_t_pre, (double)u3 * -impulse); } /* Apply velocity stopping impulse. */ impulse = magrelVel / 3.0f; - VECADDMUL(ia[0], collpair->normal, w1 * impulse); - VECADDMUL(ia[1], collpair->normal, w2 * impulse); - VECADDMUL(ia[2], collpair->normal, w3 * impulse); - - VECADDMUL(ib[0], collpair->normal, -u1 * impulse); - VECADDMUL(ib[1], collpair->normal, -u2 * impulse); - VECADDMUL(ib[2], collpair->normal, -u3 * impulse); + VECADDMUL(ia[0], collpair->normal, (double)w1 * impulse); + VECADDMUL(ia[1], collpair->normal, (double)w2 * impulse); + VECADDMUL(ia[2], collpair->normal, (double)w3 * impulse); - time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); - - d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance; + VECADDMUL(ib[0], collpair->normal, (double)u1 * -impulse); + VECADDMUL(ib[1], collpair->normal, (double)u2 * -impulse); + VECADDMUL(ib[2], collpair->normal, (double)u3 * -impulse); if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) { repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel); @@ -1005,54 +957,43 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, } repulse = max_ff(impulse, repulse); - impulse = repulse / 1.5f; - VECADDMUL(ia[0], collpair->normal, w1 * impulse); - VECADDMUL(ia[1], collpair->normal, w2 * impulse); - VECADDMUL(ia[2], collpair->normal, w3 * impulse); + VECADDMUL(ia[0], collpair->normal, (double)w1 * impulse); + VECADDMUL(ia[1], collpair->normal, (double)w2 * impulse); + VECADDMUL(ia[2], collpair->normal, (double)w3 * impulse); - VECADDMUL(ib[0], collpair->normal, -u1 * impulse); - VECADDMUL(ib[1], collpair->normal, -u2 * impulse); - VECADDMUL(ib[2], collpair->normal, -u3 * impulse); + VECADDMUL(ib[0], collpair->normal, (double)u1 * -impulse); + VECADDMUL(ib[1], collpair->normal, (double)u2 * -impulse); + VECADDMUL(ib[2], collpair->normal, (double)u3 * -impulse); } result = 1; } - else { - float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); - float d; - - d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance; - - if (d > ALMOST_ZERO) { - /* Stay on the safe side and clamp repulse. */ - float repulse = d * 1.0f / time_multiplier; - float impulse = repulse / 9.0f; + else if (d > ALMOST_ZERO) { + /* Stay on the safe side and clamp repulse. */ + float repulse = d * 1.0f / time_multiplier; + float impulse = repulse / 9.0f; - VECADDMUL(ia[0], collpair->normal, w1 * impulse); - VECADDMUL(ia[1], collpair->normal, w2 * impulse); - VECADDMUL(ia[2], collpair->normal, w3 * impulse); + VECADDMUL(ia[0], collpair->normal, w1 * impulse); + VECADDMUL(ia[1], collpair->normal, w2 * impulse); + VECADDMUL(ia[2], collpair->normal, w3 * impulse); - VECADDMUL(ib[0], collpair->normal, -u1 * impulse); - VECADDMUL(ib[1], collpair->normal, -u2 * impulse); - VECADDMUL(ib[2], collpair->normal, -u3 * impulse); + VECADDMUL(ib[0], collpair->normal, u1 * -impulse); + VECADDMUL(ib[1], collpair->normal, u2 * -impulse); + VECADDMUL(ib[2], collpair->normal, u3 * -impulse); - result = 1; - } + result = 1; } if (result) { - float clamp_sq = clmd->coll_parms->self_clamp * dt; - clamp_sq *= clamp_sq; - - cloth_selfcollision_impulse_vert(clamp_sq, ia[0], &cloth1->verts[collpair->ap1]); - cloth_selfcollision_impulse_vert(clamp_sq, ia[1], &cloth1->verts[collpair->ap2]); - cloth_selfcollision_impulse_vert(clamp_sq, ia[2], &cloth1->verts[collpair->ap3]); + cloth_selfcollision_impulse_vert(clamp_sq, ia[0], &cloth->verts[collpair->ap1]); + cloth_selfcollision_impulse_vert(clamp_sq, ia[1], &cloth->verts[collpair->ap2]); + cloth_selfcollision_impulse_vert(clamp_sq, ia[2], &cloth->verts[collpair->ap3]); - cloth_selfcollision_impulse_vert(clamp_sq, ib[0], &cloth1->verts[collpair->bp1]); - cloth_selfcollision_impulse_vert(clamp_sq, ib[1], &cloth1->verts[collpair->bp2]); - cloth_selfcollision_impulse_vert(clamp_sq, ib[2], &cloth1->verts[collpair->bp3]); + cloth_selfcollision_impulse_vert(clamp_sq, ib[0], &cloth->verts[collpair->bp1]); + cloth_selfcollision_impulse_vert(clamp_sq, ib[1], &cloth->verts[collpair->bp2]); + cloth_selfcollision_impulse_vert(clamp_sq, ib[2], &cloth->verts[collpair->bp3]); } } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 01ce95d9d70..047f927ae88 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -602,8 +602,7 @@ static void constraint_target_to_mat4(Object *ob, pchan = BKE_pose_channel_find_name(ob->pose, substring); if (pchan) { /* Multiply the PoseSpace accumulation/final matrix for this - * PoseChannel by the Armature Object's Matrix to get a worldspace - * matrix. + * PoseChannel by the Armature Object's Matrix to get a world-space matrix. */ bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE); diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 179f2f44180..1b35fdd1706 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -1572,7 +1572,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph, space_transform)) { CustomDataTransferLayerMap *lay_mapit; - changed = (lay_map.first != NULL); + changed |= (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[VDATA], lay_mapit); @@ -1650,7 +1650,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph, space_transform)) { CustomDataTransferLayerMap *lay_mapit; - changed = (lay_map.first != NULL); + changed |= (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[EDATA], lay_mapit); @@ -1746,7 +1746,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph, space_transform)) { CustomDataTransferLayerMap *lay_mapit; - changed = (lay_map.first != NULL); + changed |= (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[LDATA], lay_mapit); @@ -1837,7 +1837,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph, space_transform)) { CustomDataTransferLayerMap *lay_mapit; - changed = (lay_map.first != NULL); + changed |= (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[PDATA], lay_mapit); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index bbc4e48677d..a1c4e7d1ef2 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1965,6 +1965,7 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob, Material *ma_secondary = NULL; MaterialGPencilStyle *gp_style_primary = NULL; MaterialGPencilStyle *gp_style_secondary = NULL; + GHash *mat_used = BLI_ghash_int_new(__func__); short *totcol = BKE_object_material_len_p(ob); if (totcol == 0) { @@ -1977,8 +1978,15 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob, if (ma_primary == NULL) { continue; } + for (int idx_secondary = 0; idx_secondary < *totcol; idx_secondary++) { + if ((idx_secondary == idx_primary) || + BLI_ghash_haskey(r_mat_table, POINTER_FROM_INT(idx_secondary))) { + continue; + } + if (BLI_ghash_haskey(mat_used, POINTER_FROM_INT(idx_secondary))) { + continue; + } - for (int idx_secondary = idx_primary + 1; idx_secondary < *totcol; idx_secondary++) { /* Read secondary material to compare with primary material. */ ma_secondary = BKE_gpencil_material(ob, idx_secondary + 1); if ((ma_secondary == NULL) || @@ -2016,6 +2024,11 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob, } float s_hsv_a[3], s_hsv_b[3], f_hsv_a[3], f_hsv_b[3], col[3]; + zero_v3(s_hsv_a); + zero_v3(s_hsv_b); + zero_v3(f_hsv_a); + zero_v3(f_hsv_b); + copy_v3_v3(col, gp_style_primary->stroke_rgba); rgb_to_hsv_compat_v(col, s_hsv_a); copy_v3_v3(col, gp_style_secondary->stroke_rgba); @@ -2026,24 +2039,102 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob, copy_v3_v3(col, gp_style_secondary->fill_rgba); rgb_to_hsv_compat_v(col, f_hsv_b); - /* Check stroke and fill color (only Hue and Saturation). */ + /* Check stroke and fill color. */ if ((!compare_ff(s_hsv_a[0], s_hsv_b[0], hue_threshold)) || (!compare_ff(s_hsv_a[1], s_hsv_b[1], sat_threshold)) || + (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold)) || (!compare_ff(f_hsv_a[0], f_hsv_b[0], hue_threshold)) || (!compare_ff(f_hsv_a[1], f_hsv_b[1], sat_threshold)) || - (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold)) || - (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold)) || - (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold)) || - (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold))) { + (!compare_ff(f_hsv_a[2], f_hsv_b[2], val_threshold)) || + (!compare_ff(gp_style_primary->stroke_rgba[3], + gp_style_secondary->stroke_rgba[3], + val_threshold)) || + (!compare_ff( + gp_style_primary->fill_rgba[3], gp_style_secondary->fill_rgba[3], val_threshold))) { continue; } /* Save conversion indexes. */ - BLI_ghash_insert( - r_mat_table, POINTER_FROM_INT(idx_secondary), POINTER_FROM_INT(idx_primary)); - changed = true; + if (!BLI_ghash_haskey(r_mat_table, POINTER_FROM_INT(idx_secondary))) { + BLI_ghash_insert( + r_mat_table, POINTER_FROM_INT(idx_secondary), POINTER_FROM_INT(idx_primary)); + changed = true; + + if (!BLI_ghash_haskey(mat_used, POINTER_FROM_INT(idx_primary))) { + BLI_ghash_insert(mat_used, POINTER_FROM_INT(idx_primary), POINTER_FROM_INT(idx_primary)); + } + } } } + /* Free hash memory. */ + BLI_ghash_free(mat_used, NULL, NULL); + + return changed; +} + +/** + * Merge similar materials + * \param ob: Grease pencil object + * \param hue_threshold: Threshold for Hue + * \param sat_threshold: Threshold for Saturation + * \param val_threshold: Threshold for Value + * \param r_removed: Number of materials removed + * \return True if done + */ +bool BKE_gpencil_merge_materials(Object *ob, + const float hue_threshold, + const float sat_threshold, + const float val_threshold, + int *r_removed) +{ + bGPdata *gpd = ob->data; + + short *totcol = BKE_object_material_len_p(ob); + if (totcol == 0) { + *r_removed = 0; + return 0; + } + + /* Review materials. */ + GHash *mat_table = BLI_ghash_int_new(__func__); + + bool changed = BKE_gpencil_merge_materials_table_get( + ob, hue_threshold, sat_threshold, val_threshold, mat_table); + + *r_removed = BLI_ghash_len(mat_table); + + /* Update stroke material index. */ + if (changed) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* Check if the color is editable. */ + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + if (gp_style != NULL) { + if (gp_style->flag & GP_MATERIAL_HIDE) { + continue; + } + if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && + (gp_style->flag & GP_MATERIAL_LOCKED)) { + continue; + } + } + + if (BLI_ghash_haskey(mat_table, POINTER_FROM_INT(gps->mat_nr))) { + int *idx = BLI_ghash_lookup(mat_table, POINTER_FROM_INT(gps->mat_nr)); + gps->mat_nr = POINTER_AS_INT(idx); + } + } + } + } + } + + /* Free hash memory. */ + BLI_ghash_free(mat_table, NULL, NULL); return changed; } diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c index eb22927a731..881ce019d32 100644 --- a/source/blender/blenkernel/intern/gpencil_curve.c +++ b/source/blender/blenkernel/intern/gpencil_curve.c @@ -60,60 +60,111 @@ * \{ */ /* Helper: Check materials with same color. */ -static int gpencil_check_same_material_color(Object *ob_gp, const float color[4], Material **r_mat) +static int gpencil_check_same_material_color(Object *ob_gp, + const float color_stroke[4], + const float color_fill[4], + const bool do_fill, + const bool do_stroke, + Material **r_mat) { + int index = -1; Material *ma = NULL; + *r_mat = NULL; float color_cu[4]; - copy_v4_v4(color_cu, color); + float hsv_stroke[4], hsv_fill[4]; + + copy_v4_v4(color_cu, color_stroke); + zero_v3(hsv_stroke); + rgb_to_hsv_v(color_cu, hsv_stroke); + hsv_stroke[3] = color_stroke[3]; + + copy_v4_v4(color_cu, color_fill); + zero_v3(hsv_fill); + rgb_to_hsv_v(color_cu, hsv_fill); + hsv_fill[3] = color_fill[3]; - float hsv1[4]; - rgb_to_hsv_v(color_cu, hsv1); - hsv1[3] = color[3]; + bool match_stroke = false; + bool match_fill = false; for (int i = 1; i <= ob_gp->totcol; i++) { ma = BKE_object_material_get(ob_gp, i); MaterialGPencilStyle *gp_style = ma->gp_style; - /* Check color with small tolerance (better in HSV). */ + const bool fill = (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID); + const bool stroke = (gp_style->fill_style == GP_MATERIAL_STROKE_STYLE_SOLID); + + if (do_fill && !fill) { + continue; + } + + if (do_stroke && !stroke) { + continue; + } + + /* Check color with small tolerance (better result in HSV). */ float hsv2[4]; - rgb_to_hsv_v(gp_style->fill_rgba, hsv2); - hsv2[3] = gp_style->fill_rgba[3]; - if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) && - (compare_v4v4(hsv1, hsv2, 0.01f))) { - *r_mat = ma; - return i - 1; + if (do_fill) { + zero_v3(hsv2); + rgb_to_hsv_v(gp_style->fill_rgba, hsv2); + hsv2[3] = gp_style->fill_rgba[3]; + if (compare_v4v4(hsv_fill, hsv2, 0.01f)) { + *r_mat = ma; + index = i - 1; + match_fill = true; + } + } + else { + match_fill = true; + } + + if (do_stroke) { + zero_v3(hsv2); + rgb_to_hsv_v(gp_style->stroke_rgba, hsv2); + hsv2[3] = gp_style->stroke_rgba[3]; + if (compare_v4v4(hsv_stroke, hsv2, 0.01f)) { + *r_mat = ma; + index = i - 1; + match_stroke = true; + } + } + else { + match_stroke = true; + } + + /* If match, don't look for more. */ + if (match_stroke || match_fill) { + break; } } - *r_mat = NULL; - return -1; + if (!match_stroke || !match_fill) { + *r_mat = NULL; + index = -1; + } + + return index; } /* Helper: Add gpencil material using curve material as base. */ static Material *gpencil_add_from_curve_material(Main *bmain, Object *ob_gp, - const float cu_color[4], - const bool gpencil_lines, + const float stroke_color[4], + const float fill_color[4], + const bool stroke, const bool fill, int *r_idx) { - Material *mat_gp = BKE_gpencil_object_material_new( - bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx); + Material *mat_gp = BKE_gpencil_object_material_new(bmain, ob_gp, "Material", r_idx); MaterialGPencilStyle *gp_style = mat_gp->gp_style; /* Stroke color. */ - if (gpencil_lines) { - ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f); + if (stroke) { + copy_v4_v4(mat_gp->gp_style->stroke_rgba, stroke_color); gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } - else { - copy_v4_v4(mat_gp->gp_style->stroke_rgba, cu_color); - gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; - } /* Fill color. */ - copy_v4_v4(mat_gp->gp_style->fill_rgba, cu_color); - /* Fill is false if the original curve hasn't material assigned, so enable it. */ if (fill) { + copy_v4_v4(mat_gp->gp_style->fill_rgba, fill_color); gp_style->flag |= GP_MATERIAL_FILL_SHOW; } @@ -128,13 +179,18 @@ static Material *gpencil_add_from_curve_material(Main *bmain, /* Helper: Create new stroke section. */ static void gpencil_add_new_points(bGPDstroke *gps, - float *coord_array, - float pressure, - int init, - int totpoints, + const float *coord_array, + const float pressure_start, + const float pressure_end, + const int init, + const int totpoints, const float init_co[3], - bool last) + const bool last) { + BLI_assert(totpoints > 0); + + const float step = 1.0f / ((float)totpoints - 1.0f); + float factor = 0.0f; for (int i = 0; i < totpoints; i++) { bGPDspoint *pt = &gps->points[i + init]; copy_v3_v3(&pt->x, &coord_array[3 * i]); @@ -149,8 +205,9 @@ static void gpencil_add_new_points(bGPDstroke *gps, } } - pt->pressure = pressure; pt->strength = 1.0f; + pt->pressure = interpf(pressure_end, pressure_start, factor); + factor += step; } } @@ -169,18 +226,85 @@ static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob) return mycol; } +static int gpencil_get_stroke_material_fromcurve( + Main *bmain, Object *ob_gp, Object *ob_cu, bool *do_stroke, bool *do_fill) +{ + Curve *cu = (Curve *)ob_cu->data; + + Material *mat_gp = NULL; + Material *mat_curve_stroke = NULL; + Material *mat_curve_fill = NULL; + + float color_stroke[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float color_fill[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + /* If the curve has 2 materials, the first is considered as Fill and the second as Stroke. + * If the has only one material, if the name contains _stroke, the is used + * as stroke, else as fill.*/ + if (ob_cu->totcol >= 2) { + *do_stroke = true; + *do_fill = true; + mat_curve_fill = BKE_object_material_get(ob_cu, 1); + mat_curve_stroke = BKE_object_material_get(ob_cu, 2); + } + else if (ob_cu->totcol == 1) { + mat_curve_stroke = BKE_object_material_get(ob_cu, 1); + if ((mat_curve_stroke) && (strstr(mat_curve_stroke->id.name, "_stroke") != NULL)) { + *do_stroke = true; + *do_fill = false; + mat_curve_fill = NULL; + } + else { + *do_stroke = false; + *do_fill = true; + /* Invert materials. */ + mat_curve_fill = mat_curve_stroke; + mat_curve_stroke = NULL; + } + } + else { + /* No materials in the curve. */ + *do_fill = false; + return -1; + } + + if (mat_curve_stroke) { + copy_v4_v4(color_stroke, &mat_curve_stroke->r); + } + if (mat_curve_fill) { + copy_v4_v4(color_fill, &mat_curve_fill->r); + } + + int r_idx = gpencil_check_same_material_color( + ob_gp, color_stroke, color_fill, *do_stroke, *do_fill, &mat_gp); + + if ((ob_gp->totcol < r_idx) || (r_idx < 0)) { + mat_gp = gpencil_add_from_curve_material( + bmain, ob_gp, color_stroke, color_fill, *do_stroke, *do_fill, &r_idx); + } + + /* Set fill and stroke depending of curve type (3D or 2D). */ + if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) { + mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; + } + else { + mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW; + } + + return r_idx; +} /* Helper: Convert one spline to grease pencil stroke. */ static void gpencil_convert_spline(Main *bmain, Object *ob_gp, Object *ob_cu, - const bool gpencil_lines, - const bool only_stroke, + const float scale_thickness, + const float sample, bGPDframe *gpf, Nurb *nu) { - Curve *cu = (Curve *)ob_cu->data; - bGPdata *gpd = (bGPdata *)ob_gp->data; bool cyclic = true; /* Create Stroke. */ @@ -215,75 +339,8 @@ static void gpencil_convert_spline(Main *bmain, /* Materials * Notice: The color of the material is the color of viewport and not the final shader color. */ - Material *mat_gp = NULL; - bool fill = true; - /* Check if grease pencil has a material with same color.*/ - float color[4]; - if ((cu->mat) && (*cu->mat)) { - Material *mat_cu = *cu->mat; - copy_v4_v4(color, &mat_cu->r); - } - else { - /* Gray (unassigned from SVG add-on) */ - zero_v4(color); - add_v3_fl(color, 0.6f); - color[3] = 1.0f; - fill = false; - } - - /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and - * there is only one color, the stroke must not be closed, fill to false and use for - * stroke the fill color. - */ - bool do_stroke = false; - if (ob_cu->totcol == 1) { - Material *ma_stroke = BKE_object_material_get(ob_cu, 1); - if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) { - do_stroke = true; - } - } - - int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp); - if ((ob_cu->totcol > 0) && (r_idx < 0)) { - Material *mat_curve = BKE_object_material_get(ob_cu, 1); - mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx); - - if ((mat_curve) && (mat_curve->gp_style != NULL)) { - MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style; - MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style; - - copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba); - gp_style_gp->fill_style = gp_style_cur->fill_style; - gp_style_gp->mix_factor = gp_style_cur->mix_factor; - } - - /* If object has more than 1 material, use second material for stroke color. */ - if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) { - mat_curve = BKE_object_material_get(ob_cu, 2); - if (mat_curve) { - copy_v4_v4(mat_gp->gp_style->stroke_rgba, &mat_curve->r); - } - } - else if ((only_stroke) || (do_stroke)) { - /* Also use the first color if the fill is none for stroke color. */ - if (ob_cu->totcol > 0) { - mat_curve = BKE_object_material_get(ob_cu, 1); - if (mat_curve) { - copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); - mat_gp->gp_style->stroke_rgba[3] = mat_curve->a; - /* Set fill and stroke depending of curve type (3D or 2D). */ - if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) { - mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; - mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; - } - else { - mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; - mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW; - } - } - } - } - } + bool do_stroke, do_fill; + int r_idx = gpencil_get_stroke_material_fromcurve(bmain, ob_gp, ob_cu, &do_stroke, &do_fill); CLAMP_MIN(r_idx, 0); /* Assign material index to stroke. */ @@ -347,7 +404,11 @@ static void gpencil_convert_spline(Main *bmain, copy_v3_v3(init_co, &coord_array[0]); } /* Add points to the stroke */ - gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last); + float radius_start = prevbezt->radius * scale_thickness; + float radius_end = bezt->radius * scale_thickness; + + gpencil_add_new_points( + gps, coord_array, radius_start, radius_end, init, resolu, init_co, last); /* Free memory. */ MEM_SAFE_FREE(coord_array); @@ -378,7 +439,7 @@ static void gpencil_convert_spline(Main *bmain, gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); /* Add points. */ - gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false); + gpencil_add_new_points(gps, coord_array, 1.0f, 1.0f, 0, gps->totpoints, init_co, false); MEM_SAFE_FREE(coord_array); } @@ -389,10 +450,14 @@ static void gpencil_convert_spline(Main *bmain, } } /* Cyclic curve, close stroke. */ - if ((cyclic) && (!do_stroke)) { + if (cyclic) { BKE_gpencil_stroke_close(gps); } + if (sample > 0.0f) { + BKE_gpencil_stroke_sample(gps, sample, false); + } + /* Recalc fill geometry. */ BKE_gpencil_stroke_geometry_update(gpd, gps); } @@ -415,17 +480,17 @@ static void gpencil_editstroke_deselect_all(bGPDcurve *gpc) * \param scene: Original scene. * \param ob_gp: Grease pencil object to add strokes. * \param ob_cu: Curve to convert. - * \param gpencil_lines: Use lines for strokes. * \param use_collections: Create layers using collection names. - * \param only_stroke: The material must be only stroke without fill. + * \param scale_thickness: Scale thickness factor. + * \param sample: Sample distance, zero to disable. */ void BKE_gpencil_convert_curve(Main *bmain, Scene *scene, Object *ob_gp, Object *ob_cu, - const bool gpencil_lines, const bool use_collections, - const bool only_stroke) + const float scale_thickness, + const float sample) { if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) { return; @@ -463,11 +528,32 @@ void BKE_gpencil_convert_curve(Main *bmain, /* Read all splines of the curve and create a stroke for each. */ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { - gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu); + gpencil_convert_spline(bmain, ob_gp, ob_cu, scale_thickness, sample, gpf, nu); + } + + /* Merge any similar material. */ + int removed = 0; + BKE_gpencil_merge_materials(ob_gp, 0.001f, 0.001f, 0.001f, &removed); + + /* Remove any unused slot. */ + int actcol = ob_gp->actcol; + + for (int slot = 1; slot <= ob_gp->totcol; slot++) { + while (slot <= ob_gp->totcol && !BKE_object_material_slot_used(ob_gp->data, slot)) { + ob_gp->actcol = slot; + BKE_object_material_slot_remove(bmain, ob_gp); + + if (actcol >= slot) { + actcol--; + } + } } + ob_gp->actcol = actcol; + /* Tag for recalculation */ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&ob_gp->id, ID_RECALC_GEOMETRY); } /** \} */ diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 92e16be878f..2a7d3f1797d 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -405,7 +405,7 @@ static float densfunc(const MetaElem *ball, float x, float y, float z) } /** - * Computes density at given position form all metaballs which contain this point in their box. + * Computes density at given position form all meta-balls which contain this point in their box. * Traverses BVH using a queue. */ static float metaball(PROCESS *process, float x, float y, float z) @@ -1443,9 +1443,9 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa if (process.totelem > 0) { build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); - /* Don't polygonize metaballs with too high resolution (base mball to small) - * note: Eps was 0.0001f but this was giving problems for blood animation for durian, - * using 0.00001f. */ + /* Don't polygonize meta-balls with too high resolution (base mball to small) + * note: Eps was 0.0001f but this was giving problems for blood animation for + * the open movie "Sintel", using 0.00001f. */ if (ob->scale[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || ob->scale[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || ob->scale[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) { diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index fccc4380fec..2a16d0eb0f8 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -95,7 +95,15 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int /* This is a direct copy of a main mesh, so for now it has the same topology. */ mesh_dst->runtime.deformed_only = true; } - /* XXX WHAT? Why? Comment, please! And pretty sure this is not valid for regular Mesh copying? */ + /* This option is set for run-time meshes that have been copied from the current objects mode. + * Currently this is used for edit-mesh although it could be used for sculpt or other + * kinds of data specific to an objects mode. + * + * The flag signals that the mesh hasn't been modified from the data that generated it, + * allowing us to use the object-mode data for drawing. + * + * While this could be the callers responsibility, keep here since it's + * highly unlikely we want to create a duplicate and not use it for drawing. */ mesh_dst->runtime.is_original = false; /* Only do tessface if we have no polys. */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 5789e0f0557..afd02d7001e 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -41,6 +41,7 @@ #include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_path_util.h" +#include "BLI_session_uuid.h" #include "BLI_string.h" #include "BLI_string_utils.h" #include "BLI_utildefines.h" @@ -150,6 +151,8 @@ ModifierData *BKE_modifier_new(int type) mti->initData(md); } + BKE_modifier_session_uuid_generate(md); + return md; } @@ -192,6 +195,11 @@ void BKE_modifier_free(ModifierData *md) BKE_modifier_free_ex(md, 0); } +void BKE_modifier_session_uuid_generate(ModifierData *md) +{ + md->session_uuid = BLI_session_uuid_generate(); +} + bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md) { if (modifiers && md) { @@ -368,6 +376,17 @@ void BKE_modifier_copydata_ex(ModifierData *md, ModifierData *target, const int mti->foreachObjectLink(target, NULL, (ObjectWalkFunc)modifier_copy_data_id_us_cb, NULL); } } + + if (flag & LIB_ID_CREATE_NO_MAIN) { + /* Make sure UUID is the same between the source and the target. + * This is needed in the cases when UUID is to be preserved and when there is no copyData + * callback, or the copyData does not do full byte copy of the modifier data. */ + target->session_uuid = md->session_uuid; + } + else { + /* In the case copyData made full byte copy force UUID to be re-generated. */ + BKE_modifier_session_uuid_generate(md); + } } void BKE_modifier_copydata(ModifierData *md, ModifierData *target) @@ -1071,3 +1090,26 @@ struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph, } return BKE_modifiers_findby_name(object_eval, md->name); } + +void BKE_modifier_check_uuids_unique_and_report(const Object *object) +{ + struct GSet *used_uuids = BLI_gset_new( + BLI_session_uuid_ghash_hash, BLI_session_uuid_ghash_compare, "modifier used uuids"); + + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + const SessionUUID *session_uuid = &md->session_uuid; + if (!BLI_session_uuid_is_generated(session_uuid)) { + printf("Modifier %s -> %s does not have UUID generated.\n", object->id.name + 2, md->name); + continue; + } + + if (BLI_gset_lookup(used_uuids, session_uuid) != NULL) { + printf("Modifier %s -> %s has duplicate UUID generated.\n", object->id.name + 2, md->name); + continue; + } + + BLI_gset_insert(used_uuids, (void *)session_uuid); + } + + BLI_gset_free(used_uuids, NULL); +} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 024e60ea989..31420b3adc6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -4714,3 +4714,9 @@ void BKE_object_to_mesh_clear(Object *object) BKE_id_free(NULL, object->runtime.object_as_temp_mesh); object->runtime.object_as_temp_mesh = NULL; } + +void BKE_object_check_uuids_unique_and_report(const Object *object) +{ + BKE_pose_check_uuids_unique_and_report(object->pose); + BKE_modifier_check_uuids_unique_and_report(object); +} diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 553cff33fbb..d69f4a39263 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -30,6 +30,7 @@ #include "BLI_listbase.h" #include "BLI_string_utf8.h" +#include "BLI_alloca.h" #include "BLI_math.h" #include "BLI_rand.h" @@ -44,6 +45,7 @@ #include "BKE_collection.h" #include "BKE_duplilist.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_idprop.h" @@ -84,11 +86,11 @@ typedef struct DupliContext { const struct DupliGenerator *gen; /** Result containers. */ - ListBase *duplilist; /* legacy doubly-linked list */ + ListBase *duplilist; /* Legacy doubly-linked list. */ } DupliContext; typedef struct DupliGenerator { - short type; /* dupli type */ + short type; /* Dupli Type, see members of #OB_DUPLI. */ void (*make_duplis)(const DupliContext *ctx); } DupliGenerator; @@ -160,7 +162,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, DupliObject *dob; int i; - /* add a DupliObject instance to the result container */ + /* Add a #DupliObject instance to the result container. */ if (ctx->duplilist) { dob = MEM_callocN(sizeof(DupliObject), "dupli object"); BLI_addtail(ctx->duplilist, dob); @@ -173,28 +175,28 @@ static DupliObject *make_dupli(const DupliContext *ctx, mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); dob->type = ctx->gen->type; - /* set persistent id, which is an array with a persistent index for each level + /* Set persistent id, which is an array with a persistent index for each level * (particle number, vertex number, ..). by comparing this we can find the same - * dupli object between frames, which is needed for motion blur. last level - * goes first in the array. */ + * dupli-object between frames, which is needed for motion blur. + * The last level is ordered first in the array. */ dob->persistent_id[0] = index; for (i = 1; i < ctx->level + 1; i++) { dob->persistent_id[i] = ctx->persistent_id[ctx->level - i]; } - /* fill rest of values with INT_MAX which index will never have as value */ + /* Fill rest of values with #INT_MAX which index will never have as value. */ for (; i < MAX_DUPLI_RECUR; i++) { dob->persistent_id[i] = INT_MAX; } - /* metaballs never draw in duplis, they are instead merged into one by the basis - * mball outside of the group. this does mean that if that mball is not in the + /* Meta-balls never draw in duplis, they are instead merged into one by the basis + * meta-ball outside of the group. this does mean that if that meta-ball is not in the * scene, they will not show up at all, limitation that should be solved once. */ if (ob->type == OB_MBALL) { dob->no_draw = true; } - /* random number */ - /* the logic here is designed to match Cycles */ + /* Random number. + * The logic here is designed to match Cycles. */ dob->random_id = BLI_hash_string(dob->ob->id.name + 2); if (dob->persistent_id[0] != INT_MAX) { @@ -214,16 +216,16 @@ static DupliObject *make_dupli(const DupliContext *ctx, } /** - * Recursive dupli objects. + * Recursive dupli-objects. * - * \param space_mat: is the local dupli space (excluding dupli #Object.obmat). + * \param space_mat: is the local dupli-space (excluding dupli #Object.obmat). */ static void make_recursive_duplis(const DupliContext *ctx, Object *ob, const float space_mat[4][4], int index) { - /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */ + /* Simple preventing of too deep nested collections with #MAX_DUPLI_RECUR. */ if (ctx->level < MAX_DUPLI_RECUR) { DupliContext rctx; copy_dupli_context(&rctx, ctx, ob, space_mat, index); @@ -269,9 +271,9 @@ static void make_child_duplis(const DupliContext *ctx, DupliContext pctx; copy_dupli_context(&pctx, ctx, ctx->object, NULL, _base_id); - /* metaballs have a different dupli handling */ + /* Meta-balls have a different dupli handling. */ if (ob->type != OB_MBALL) { - ob->flag |= OB_DONE; /* doesn't render */ + ob->flag |= OB_DONE; /* Doesn't render. */ } make_child_duplis_cb(&pctx, userdata, ob); } @@ -287,9 +289,9 @@ static void make_child_duplis(const DupliContext *ctx, DupliContext pctx; copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid); - /* metaballs have a different dupli handling */ + /* Meta-balls have a different dupli-handling. */ if (ob->type != OB_MBALL) { - ob->flag |= OB_DONE; /* doesn't render */ + ob->flag |= OB_DONE; /* Doesn't render. */ } make_child_duplis_cb(&pctx, userdata, ob); @@ -301,6 +303,57 @@ static void make_child_duplis(const DupliContext *ctx, /** \} */ /* -------------------------------------------------------------------- */ +/** \name Internal Data Access Utilities + * \{ */ + +static Mesh *mesh_data_from_duplicator_object(Object *ob, + BMEditMesh **r_em, + const float (**r_vert_coords)[3], + const float (**r_vert_normals)[3]) +{ + /* Gather mesh info. */ + BMEditMesh *em = BKE_editmesh_from_object(ob); + Mesh *me_eval; + + *r_em = NULL; + *r_vert_coords = NULL; + if (r_vert_normals != NULL) { + *r_vert_normals = NULL; + } + + /* We do not need any render-specific handling anymore, depsgraph takes care of that. */ + /* NOTE: Do direct access to the evaluated mesh: this function is used + * during meta balls evaluation. But even without those all the objects + * which are needed for correct instancing are already evaluated. */ + if (em != NULL) { + /* Note that this will only show deformation if #eModifierMode_OnCage is enabled. + * We could change this but it matches 2.7x behavior. */ + me_eval = em->mesh_eval_cage; + if ((me_eval == NULL) || (me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) { + EditMeshData *emd = me_eval ? me_eval->runtime.edit_data : NULL; + + /* Only assign edit-mesh in the case we can't use `me_eval`. */ + *r_em = em; + me_eval = NULL; + + if ((emd != NULL) && (emd->vertexCos != NULL)) { + *r_vert_coords = emd->vertexCos; + if (r_vert_normals != NULL) { + BKE_editmesh_cache_ensure_vert_normals(em, emd); + *r_vert_normals = emd->vertexNos; + } + } + } + } + else { + me_eval = BKE_object_get_evaluated_mesh(ob); + } + return me_eval; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Dupli-Collection Implementation (#OB_DUPLICOLLECTION) * \{ */ @@ -315,23 +368,23 @@ static void make_duplis_collection(const DupliContext *ctx) } collection = ob->instance_collection; - /* combine collection offset and obmat */ + /* Combine collection offset and `obmat`. */ unit_m4(collection_mat); sub_v3_v3(collection_mat[3], collection->instance_offset); mul_m4_m4m4(collection_mat, ob->obmat, collection_mat); - /* don't access 'ob->obmat' from now on. */ + /* Don't access 'ob->obmat' from now on. */ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, cob, mode) { if (cob != ob) { float mat[4][4]; - /* collection dupli offset, should apply after everything else */ + /* Collection dupli-offset, should apply after everything else. */ mul_m4_m4m4(mat, collection_mat, cob->obmat); make_dupli(ctx, cob, mat, _base_id); - /* recursion */ + /* Recursion. */ make_recursive_duplis(ctx, cob, collection_mat, _base_id); } } @@ -349,120 +402,207 @@ static const DupliGenerator gen_dupli_collection = { /** \name Dupli-Vertices Implementation (#OB_DUPLIVERTS for Geometry) * \{ */ -typedef struct VertexDupliData { - Mesh *me_eval; - BMEditMesh *edit_mesh; - int totvert; - float (*orco)[3]; +/** Values shared between different mesh types. */ +typedef struct VertexDupliData_Params { + /** + * It's important we use this context instead of the `ctx` passed into #make_child_duplis + * since these won't match in the case of recursion. + */ + const DupliContext *ctx; + bool use_rotation; +} VertexDupliData_Params; - const DupliContext *ctx; - Object *inst_ob; /* object to instantiate (argument for vertex map callback) */ - float child_imat[4][4]; -} VertexDupliData; +typedef struct VertexDupliData_Mesh { + VertexDupliData_Params params; + + int totvert; + const MVert *mvert; + + const float (*orco)[3]; +} VertexDupliData_Mesh; + +typedef struct VertexDupliData_EditMesh { + VertexDupliData_Params params; + + BMEditMesh *em; + /* Can be NULL. */ + const float (*vert_coords)[3]; + const float (*vert_normals)[3]; + + /** + * \note The edit-mesh may assign #DupliObject.orco in cases when a regular mesh wouldn't. + * For edit-meshes we only check for deformation, for regular meshes we check if #CD_ORCO exists. + * + * At the moment this isn't a meaningful difference since requesting #CD_ORCO causes the + * edit-mesh to be converted into a mesh. + */ + bool has_orco; +} VertexDupliData_EditMesh; + +/** + * \param no: The direction, + * currently this is copied from a `short[3]` normal without division. + * Can be null when \a use_rotation is false. + */ static void get_duplivert_transform(const float co[3], - const short no[3], - bool use_rotation, - short axis, - short upflag, - float mat[4][4]) + const float no[3], + const bool use_rotation, + const short axis, + const short upflag, + float r_mat[4][4]) { float quat[4]; const float size[3] = {1.0f, 1.0f, 1.0f}; if (use_rotation) { - /* construct rotation matrix from normals */ - float nor_f[3]; - nor_f[0] = (float)-no[0]; - nor_f[1] = (float)-no[1]; - nor_f[2] = (float)-no[2]; - vec_to_quat(quat, nor_f, axis, upflag); + /* Construct rotation matrix from normals. */ + float no_flip[3]; + negate_v3_v3(no_flip, no); + vec_to_quat(quat, no_flip, axis, upflag); } else { unit_qt(quat); } - loc_quat_size_to_mat4(mat, co, quat, size); + loc_quat_size_to_mat4(r_mat, co, quat, size); } -static void vertex_dupli(const VertexDupliData *vdd, - int index, - const float co[3], - const short no[3]) +static DupliObject *vertex_dupli(const DupliContext *ctx, + Object *inst_ob, + const float child_imat[4][4], + int index, + const float co[3], + const float no[3], + const bool use_rotation) { - Object *inst_ob = vdd->inst_ob; - DupliObject *dob; - float obmat[4][4], space_mat[4][4]; + /* `obmat` is transform to vertex. */ + float obmat[4][4]; + get_duplivert_transform(co, no, use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat); - /* space_mat is transform to vertex */ - get_duplivert_transform( - co, no, vdd->use_rotation, inst_ob->trackflag, inst_ob->upflag, space_mat); - /* make offset relative to inst_ob using relative child transform */ - mul_mat3_m4_v3((float(*)[4])vdd->child_imat, space_mat[3]); - /* apply obmat _after_ the local vertex transform */ - mul_m4_m4m4(obmat, inst_ob->obmat, space_mat); + float space_mat[4][4]; - dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index); + /* Make offset relative to inst_ob using relative child transform. */ + mul_mat3_m4_v3(child_imat, obmat[3]); + /* Apply `obmat` _after_ the local vertex transform. */ + mul_m4_m4m4(obmat, inst_ob->obmat, obmat); - if (vdd->orco) { - copy_v3_v3(dob->orco, vdd->orco[index]); - } + /* Space matrix is constructed by removing `obmat` transform, + * this yields the world-space transform for recursive duplis. */ + mul_m4_m4m4(space_mat, obmat, inst_ob->imat); + + DupliObject *dob = make_dupli(ctx, inst_ob, obmat, index); + + /* Recursion. */ + make_recursive_duplis(ctx, inst_ob, space_mat, index); - /* recursion */ - make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index); + return dob; } -static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child) +static void make_child_duplis_verts_from_mesh(const DupliContext *ctx, + void *userdata, + Object *inst_ob) { - VertexDupliData *vdd = userdata; - Mesh *me_eval = vdd->me_eval; + VertexDupliData_Mesh *vdd = userdata; + const bool use_rotation = vdd->params.use_rotation; - vdd->inst_ob = child; - invert_m4_m4(child->imat, child->obmat); - /* relative transform from parent to child space */ - mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat); + const MVert *mvert = vdd->mvert; + const int totvert = vdd->totvert; - const MVert *mvert = me_eval->mvert; - for (int i = 0; i < me_eval->totvert; i++) { - vertex_dupli(vdd, i, mvert[i].co, mvert[i].no); + invert_m4_m4(inst_ob->imat, inst_ob->obmat); + /* Relative transform from parent to child space. */ + float child_imat[4][4]; + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + + const MVert *mv = mvert; + for (int i = 0; i < totvert; i++, mv++) { + const float *co = mv->co; + const float no[3] = {UNPACK3(mv->no)}; + DupliObject *dob = vertex_dupli(vdd->params.ctx, inst_ob, child_imat, i, co, no, use_rotation); + if (vdd->orco) { + copy_v3_v3(dob->orco, vdd->orco[i]); + } } } -static void make_duplis_verts(const DupliContext *ctx) +static void make_child_duplis_verts_from_editmesh(const DupliContext *ctx, + void *userdata, + Object *inst_ob) { - Object *parent = ctx->object; - VertexDupliData vdd; + VertexDupliData_EditMesh *vdd = userdata; + BMEditMesh *em = vdd->em; + const bool use_rotation = vdd->params.use_rotation; - vdd.ctx = ctx; - vdd.use_rotation = parent->transflag & OB_DUPLIROT; + invert_m4_m4(inst_ob->imat, inst_ob->obmat); + /* Relative transform from parent to child space. */ + float child_imat[4][4]; + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); - /* gather mesh info */ - { - vdd.edit_mesh = BKE_editmesh_from_object(parent); - - /* We do not need any render-specific handling anymore, depsgraph takes care of that. */ - /* NOTE: Do direct access to the evaluated mesh: this function is used - * during meta balls evaluation. But even without those all the objects - * which are needed for correct instancing are already evaluated. */ - if (vdd.edit_mesh != NULL) { - vdd.me_eval = vdd.edit_mesh->mesh_eval_cage; + BMVert *v; + BMIter iter; + int i; + + const float(*vert_coords)[3] = vdd->vert_coords; + const float(*vert_normals)[3] = vdd->vert_normals; + + BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) { + const float *co, *no; + if (vert_coords != NULL) { + co = vert_coords[i]; + no = vert_normals ? vert_normals[i] : NULL; } else { - vdd.me_eval = BKE_object_get_evaluated_mesh(parent); + co = v->co; + no = v->no; } - if (vdd.me_eval == NULL) { - return; + DupliObject *dob = vertex_dupli(vdd->params.ctx, inst_ob, child_imat, i, co, no, use_rotation); + if (vdd->has_orco) { + copy_v3_v3(dob->orco, v->co); } - - vdd.orco = CustomData_get_layer(&vdd.me_eval->vdata, CD_ORCO); - vdd.totvert = vdd.me_eval->totvert; } +} - make_child_duplis(ctx, &vdd, make_child_duplis_verts); +static void make_duplis_verts(const DupliContext *ctx) +{ + Object *parent = ctx->object; + const bool use_rotation = parent->transflag & OB_DUPLIROT; + + /* Gather mesh info. */ + BMEditMesh *em = NULL; + const float(*vert_coords)[3] = NULL; + const float(*vert_normals)[3] = NULL; + Mesh *me_eval = mesh_data_from_duplicator_object( + parent, &em, &vert_coords, use_rotation ? &vert_normals : NULL); + if (em == NULL && me_eval == NULL) { + return; + } - vdd.me_eval = NULL; + VertexDupliData_Params vdd_params = { + .ctx = ctx, + .use_rotation = use_rotation, + }; + + if (em != NULL) { + VertexDupliData_EditMesh vdd = { + .params = vdd_params, + .em = em, + .vert_coords = vert_coords, + .vert_normals = vert_normals, + .has_orco = (vert_coords != NULL), + }; + make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_editmesh); + } + else { + VertexDupliData_Mesh vdd = { + .params = vdd_params, + .totvert = me_eval->totvert, + .mvert = me_eval->mvert, + .orco = CustomData_get_layer(&me_eval->vdata, CD_ORCO), + }; + make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_mesh); + } } static const DupliGenerator gen_dupli_verts = { @@ -492,7 +632,7 @@ static Object *find_family_object( ch_utf8_len = BLI_str_utf8_from_unicode(ch, ch_utf8); ch_utf8[ch_utf8_len] = '\0'; - ch_utf8_len += 1; /* compare with null terminator */ + ch_utf8_len += 1; /* Compare with null terminator. */ for (ob = bmain->objects.first; ob; ob = ob->id.next) { if (STREQLEN(ob->id.name + 2 + family_len, ch_utf8, ch_utf8_len)) { @@ -502,7 +642,7 @@ static Object *find_family_object( } } - /* inserted value can be NULL, just to save searches in future */ + /* Inserted value can be NULL, just to save searches in future. */ BLI_ghash_insert(family_gh, ch_key, ob); } @@ -522,14 +662,14 @@ static void make_duplis_font(const DupliContext *ctx) const char32_t *text = NULL; bool text_free = false; - /* font dupliverts not supported inside collections */ + /* Font dupli-verts not supported inside collections. */ if (ctx->collection) { return; } copy_m4_m4(pmat, par->obmat); - /* in par the family name is stored, use this to find the other objects */ + /* In `par` the family name is stored, use this to find the other objects. */ BKE_vfont_to_curve_ex( par, par->data, FO_DUPLI, NULL, &text, &text_len, &text_free, &chartransdata); @@ -545,7 +685,7 @@ static void make_duplis_font(const DupliContext *ctx) ct = chartransdata; - /* cache result */ + /* Cache result. */ family_len = strlen(cu->family); family_gh = BLI_ghash_int_new_ex(__func__, 256); @@ -555,9 +695,9 @@ static void make_duplis_font(const DupliContext *ctx) /* Advance matching BLI_str_utf8_as_utf32. */ for (a = 0; a < text_len; a++, ct++) { - /* XXX That G.main is *really* ugly, but not sure what to do here... - * Definitively don't think it would be safe to put back Main *bmain pointer - * in DupliContext as done in 2.7x? */ + /* XXX That G.main is *really* ugly, but not sure what to do here. + * Definitively don't think it would be safe to put back `Main *bmain` pointer + * in #DupliContext as done in 2.7x? */ ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh); if (is_eval_curve) { @@ -670,37 +810,65 @@ static const DupliGenerator gen_dupli_verts_pointcloud = { /** \name Dupli-Faces Implementation (#OB_DUPLIFACES) * \{ */ -typedef struct FaceDupliData { - Mesh *me_eval; - int totface; - MPoly *mpoly; - MLoop *mloop; - MVert *mvert; - float (*orco)[3]; - MLoopUV *mloopuv; +/** Values shared between different mesh types. */ +typedef struct FaceDupliData_Params { + /** + * It's important we use this context instead of the `ctx` passed into #make_child_duplis + * since these won't match in the case of recursion. + */ + const DupliContext *ctx; + bool use_scale; -} FaceDupliData; +} FaceDupliData_Params; -static void get_dupliface_transform( - MPoly *mpoly, MLoop *mloop, MVert *mvert, bool use_scale, float scale_fac, float mat[4][4]) +typedef struct FaceDupliData_Mesh { + FaceDupliData_Params params; + + int totface; + const MPoly *mpoly; + const MLoop *mloop; + const MVert *mvert; + const float (*orco)[3]; + const MLoopUV *mloopuv; +} FaceDupliData_Mesh; + +typedef struct FaceDupliData_EditMesh { + FaceDupliData_Params params; + + BMEditMesh *em; + + bool has_orco, has_uvs; + int cd_loop_uv_offset; + /* Can be NULL. */ + const float (*vert_coords)[3]; +} FaceDupliData_EditMesh; + +static void get_dupliface_transform_from_coords(const float coords[][3], + const int coords_len, + const bool use_scale, + const float scale_fac, + float r_mat[4][4]) { float loc[3], quat[4], scale, size[3]; - float f_no[3]; - /* location */ - BKE_mesh_calc_poly_center(mpoly, mloop, mvert, loc); - /* rotation */ + /* Location. */ { - const float *v1, *v2, *v3; - BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, f_no); - v1 = mvert[mloop[0].v].co; - v2 = mvert[mloop[1].v].co; - v3 = mvert[mloop[2].v].co; - tri_to_quat_ex(quat, v1, v2, v3, f_no); + const float w = 1.0f / (float)coords_len; + zero_v3(loc); + for (int i = 0; i < coords_len; i++) { + madd_v3_v3fl(loc, coords[i], w); + } + } + /* Rotation. */ + { + float f_no[3]; + cross_poly_v3(f_no, coords, (uint)coords_len); + normalize_v3(f_no); + tri_to_quat_ex(quat, coords[0], coords[1], coords[2], f_no); } - /* scale */ + /* Scale. */ if (use_scale) { - float area = BKE_mesh_calc_poly_area(mpoly, mloop, mvert); + const float area = area_poly_v3(coords, (uint)coords_len); scale = sqrtf(area) * scale_fac; } else { @@ -708,58 +876,131 @@ static void get_dupliface_transform( } size[0] = size[1] = size[2] = scale; - loc_quat_size_to_mat4(mat, loc, quat, size); + loc_quat_size_to_mat4(r_mat, loc, quat, size); } -static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Object *inst_ob) +static DupliObject *face_dupli(const DupliContext *ctx, + Object *inst_ob, + const float child_imat[4][4], + const int index, + const bool use_scale, + const float scale_fac, + const float (*coords)[3], + const int coords_len) { - FaceDupliData *fdd = userdata; - MPoly *mpoly = fdd->mpoly, *mp; - MLoop *mloop = fdd->mloop; - MVert *mvert = fdd->mvert; - float(*orco)[3] = fdd->orco; - MLoopUV *mloopuv = fdd->mloopuv; - int a, totface = fdd->totface; - float child_imat[4][4]; - DupliObject *dob; + float obmat[4][4]; + float space_mat[4][4]; - invert_m4_m4(inst_ob->imat, inst_ob->obmat); - /* relative transform from parent to child space */ - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + /* `obmat` is transform to face. */ + get_dupliface_transform_from_coords(coords, coords_len, use_scale, scale_fac, obmat); - for (a = 0, mp = mpoly; a < totface; a++, mp++) { - MLoop *loopstart = mloop + mp->loopstart; - float space_mat[4][4], obmat[4][4]; + /* Make offset relative to inst_ob using relative child transform. */ + mul_mat3_m4_v3(child_imat, obmat[3]); - if (UNLIKELY(mp->totloop < 3)) { - continue; - } + /* XXX ugly hack to ensure same behavior as in master. + * This should not be needed, #Object.parentinv is not consistent outside of parenting. */ + { + float imat[3][3]; + copy_m3_m4(imat, inst_ob->parentinv); + mul_m4_m3m4(obmat, imat, obmat); + } - /* obmat is transform to face */ - get_dupliface_transform( - mp, loopstart, mvert, fdd->use_scale, ctx->object->instance_faces_scale, obmat); - /* make offset relative to inst_ob using relative child transform */ - mul_mat3_m4_v3(child_imat, obmat[3]); - - /* XXX ugly hack to ensure same behavior as in master - * this should not be needed, parentinv is not consistent - * outside of parenting. - */ - { - float imat[3][3]; - copy_m3_m4(imat, inst_ob->parentinv); - mul_m4_m3m4(obmat, imat, obmat); - } + /* Apply `obmat` _after_ the local face transform. */ + mul_m4_m4m4(obmat, inst_ob->obmat, obmat); + + /* Space matrix is constructed by removing `obmat` transform, + * this yields the world-space transform for recursive duplis. */ + mul_m4_m4m4(space_mat, obmat, inst_ob->imat); + + DupliObject *dob = make_dupli(ctx, inst_ob, obmat, index); + + /* Recursion. */ + make_recursive_duplis(ctx, inst_ob, space_mat, index); + + return dob; +} + +/** Wrap #face_dupli, needed since we can't #alloca in a loop. */ +static DupliObject *face_dupli_from_mesh(const DupliContext *ctx, + Object *inst_ob, + const float child_imat[4][4], + const int index, + const bool use_scale, + const float scale_fac, + + /* Mesh variables. */ + const MPoly *mpoly, + const MLoop *mloopstart, + const MVert *mvert) +{ + const int coords_len = mpoly->totloop; + float(*coords)[3] = BLI_array_alloca(coords, (size_t)coords_len); + + const MLoop *ml = mloopstart; + for (int i = 0; i < coords_len; i++, ml++) { + copy_v3_v3(coords[i], mvert[ml->v].co); + } + + return face_dupli(ctx, inst_ob, child_imat, index, use_scale, scale_fac, coords, coords_len); +} + +/** Wrap #face_dupli, needed since we can't #alloca in a loop. */ +static DupliObject *face_dupli_from_editmesh(const DupliContext *ctx, + Object *inst_ob, + const float child_imat[4][4], + const int index, + const bool use_scale, + const float scale_fac, + + /* Mesh variables. */ + BMFace *f, + const float (*vert_coords)[3]) +{ + const int coords_len = f->len; + float(*coords)[3] = BLI_array_alloca(coords, (size_t)coords_len); + + BMLoop *l_first, *l_iter; + int i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + if (vert_coords != NULL) { + do { + copy_v3_v3(coords[i++], vert_coords[BM_elem_index_get(l_iter->v)]); + } while ((l_iter = l_iter->next) != l_first); + } + else { + do { + copy_v3_v3(coords[i++], l_iter->v->co); + } while ((l_iter = l_iter->next) != l_first); + } - /* apply obmat _after_ the local face transform */ - mul_m4_m4m4(obmat, inst_ob->obmat, obmat); + return face_dupli(ctx, inst_ob, child_imat, index, use_scale, scale_fac, coords, coords_len); +} - /* space matrix is constructed by removing obmat transform, - * this yields the worldspace transform for recursive duplis - */ - mul_m4_m4m4(space_mat, obmat, inst_ob->imat); +static void make_child_duplis_faces_from_mesh(const DupliContext *ctx, + void *userdata, + Object *inst_ob) +{ + FaceDupliData_Mesh *fdd = userdata; + const MPoly *mpoly = fdd->mpoly, *mp; + const MLoop *mloop = fdd->mloop; + const MVert *mvert = fdd->mvert; + const float(*orco)[3] = fdd->orco; + const MLoopUV *mloopuv = fdd->mloopuv; + const int totface = fdd->totface; + const bool use_scale = fdd->params.use_scale; + int a; - dob = make_dupli(ctx, inst_ob, obmat, a); + float child_imat[4][4]; + + invert_m4_m4(inst_ob->imat, inst_ob->obmat); + /* Relative transform from parent to child space. */ + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + const float scale_fac = ctx->object->instance_faces_scale; + + for (a = 0, mp = mpoly; a < totface; a++, mp++) { + const MLoop *loopstart = mloop + mp->loopstart; + DupliObject *dob = face_dupli_from_mesh( + fdd->params.ctx, inst_ob, child_imat, a, use_scale, scale_fac, mp, loopstart, mvert); const float w = 1.0f / (float)mp->totloop; if (orco) { @@ -772,51 +1013,90 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w); } } - - /* recursion */ - make_recursive_duplis(ctx, inst_ob, space_mat, a); } } -static void make_duplis_faces(const DupliContext *ctx) +static void make_child_duplis_faces_from_editmesh(const DupliContext *ctx, + void *userdata, + Object *inst_ob) { - Object *parent = ctx->object; - FaceDupliData fdd; + FaceDupliData_EditMesh *fdd = userdata; + BMEditMesh *em = fdd->em; + float child_imat[4][4]; + int a; + BMFace *f; + BMIter iter; + const bool use_scale = fdd->params.use_scale; - fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0); + const float(*vert_coords)[3] = fdd->vert_coords; - /* gather mesh info */ - { - BMEditMesh *em = BKE_editmesh_from_object(parent); - - /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */ - /* NOTE: Do direct access to the evaluated mesh: this function is used - * during meta balls evaluation. But even without those all the objects - * which are needed for correct instancing are already evaluated. */ - if (em != NULL) { - fdd.me_eval = em->mesh_eval_cage; - } - else { - fdd.me_eval = BKE_object_get_evaluated_mesh(parent); - } + BLI_assert((vert_coords == NULL) || (em->bm->elem_index_dirty & BM_VERT) == 0); - if (fdd.me_eval == NULL) { - return; + invert_m4_m4(inst_ob->imat, inst_ob->obmat); + /* Relative transform from parent to child space. */ + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + const float scale_fac = ctx->object->instance_faces_scale; + + BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, a) { + DupliObject *dob = face_dupli_from_editmesh( + fdd->params.ctx, inst_ob, child_imat, a, use_scale, scale_fac, f, vert_coords); + + if (fdd->has_orco) { + const float w = 1.0f / (float)f->len; + BMLoop *l_first, *l_iter; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + madd_v3_v3fl(dob->orco, l_iter->v->co, w); + } while ((l_iter = l_iter->next) != l_first); + } + if (fdd->has_uvs) { + BM_face_uv_calc_center_median(f, fdd->cd_loop_uv_offset, dob->uv); } + } +} - fdd.orco = CustomData_get_layer(&fdd.me_eval->vdata, CD_ORCO); - const int uv_idx = CustomData_get_render_layer(&fdd.me_eval->ldata, CD_MLOOPUV); - fdd.mloopuv = CustomData_get_layer_n(&fdd.me_eval->ldata, CD_MLOOPUV, uv_idx); +static void make_duplis_faces(const DupliContext *ctx) +{ + Object *parent = ctx->object; - fdd.totface = fdd.me_eval->totpoly; - fdd.mpoly = fdd.me_eval->mpoly; - fdd.mloop = fdd.me_eval->mloop; - fdd.mvert = fdd.me_eval->mvert; + /* Gather mesh info. */ + BMEditMesh *em = NULL; + const float(*vert_coords)[3] = NULL; + Mesh *me_eval = mesh_data_from_duplicator_object(parent, &em, &vert_coords, NULL); + if (em == NULL && me_eval == NULL) { + return; } - make_child_duplis(ctx, &fdd, make_child_duplis_faces); - - fdd.me_eval = NULL; + FaceDupliData_Params fdd_params = { + .ctx = ctx, + .use_scale = parent->transflag & OB_DUPLIFACES_SCALE, + }; + + if (em != NULL) { + const int uv_idx = CustomData_get_render_layer(&em->bm->ldata, CD_MLOOPUV); + FaceDupliData_EditMesh fdd = { + .params = fdd_params, + .em = em, + .vert_coords = vert_coords, + .has_orco = (vert_coords != NULL), + .has_uvs = (uv_idx != -1), + .cd_loop_uv_offset = CustomData_get_n_offset(&em->bm->ldata, CD_MLOOPUV, uv_idx), + }; + make_child_duplis(ctx, &fdd, make_child_duplis_faces_from_editmesh); + } + else { + const int uv_idx = CustomData_get_render_layer(&me_eval->ldata, CD_MLOOPUV); + FaceDupliData_Mesh fdd = { + .params = fdd_params, + .totface = me_eval->totpoly, + .mpoly = me_eval->mpoly, + .mloop = me_eval->mloop, + .mvert = me_eval->mvert, + .mloopuv = CustomData_get_layer_n(&me_eval->ldata, CD_MLOOPUV, uv_idx), + .orco = CustomData_get_layer(&me_eval->vdata, CD_ORCO), + }; + make_child_duplis(ctx, &fdd, make_child_duplis_faces_from_mesh); + } } static const DupliGenerator gen_dupli_faces = { @@ -870,7 +1150,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem no_draw_flag |= PARS_NO_DISP; } - /* NOTE: in old animsys, used parent object's timeoffset... */ + /* NOTE: in old animation system, used parent object's time-offset. */ ctime = DEG_get_ctime(ctx->depsgraph); totpart = psys->totpart; @@ -884,16 +1164,16 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem sim.ob = par; sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); - /* make sure emitter imat is in global coordinates instead of render view coordinates */ + /* Make sure emitter `imat` is in global coordinates instead of render view coordinates. */ invert_m4_m4(par->imat, par->obmat); - /* first check for loops (particle system object used as dupli object) */ + /* First check for loops (particle system object used as dupli-object). */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->instance_object, NULL, par)) { return; } } - else { /*PART_DRAW_GR */ + else { /* #PART_DRAW_GR. */ if (part->instance_collection == NULL) { return; } @@ -909,7 +1189,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } } - /* if we have a hair particle system, use the path cache */ + /* If we have a hair particle system, use the path cache. */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) { hair = (totchild == 0 || psys->childcache) && psys->pathcache; @@ -918,7 +1198,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem return; } - /* we use cache, update totchild according to cached data */ + /* We use cache, update `totchild` according to cached data. */ totchild = psys->totchildcache; totpart = psys->totcached; } @@ -927,7 +1207,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - /* gather list of objects or single object */ + /* Gather list of objects or single object. */ int totcollection = 0; const bool use_whole_collection = part->draw & PART_DRAW_WHOLE_GR; @@ -996,23 +1276,27 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem for (pa = psys->particles; a < totpart + totchild; a++, pa++) { if (a < totpart) { - /* handle parent particle */ + /* Handle parent particle. */ if (pa->flag & no_draw_flag) { continue; } - /* pa_num = pa->num; */ /* UNUSED */ +#if 0 /* UNUSED */ + pa_num = pa->num; +#endif size = pa->size; } else { - /* handle child particle */ + /* Handle child particle. */ cpa = &psys->child[a - totpart]; - /* pa_num = a; */ /* UNUSED */ +#if 0 /* UNUSED */ + pa_num = a; +#endif size = psys_get_child_size(psys, cpa, ctime, NULL); } - /* some hair paths might be non-existent so they can't be used for duplication */ + /* Some hair paths might be non-existent so they can't be used for duplication. */ if (hair && psys->pathcache && ((a < totpart && psys->pathcache[a]->segments < 0) || (a >= totpart && psys->childcache[a - totpart]->segments < 0))) { @@ -1020,12 +1304,12 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } if (part->ren_as == PART_DRAW_GR) { - /* prevent divide by zero below [#28336] */ + /* Prevent divide by zero below T28336. */ if (totcollection == 0) { continue; } - /* for collections, pick the object based on settings */ + /* For collections, pick the object based on settings. */ if (part->draw & PART_DRAW_RAND_GR && !use_whole_collection) { b = BLI_rng_get_int(rng) % totcollection; } @@ -1037,7 +1321,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } if (hair) { - /* hair we handle separate and compute transform based on hair keys */ + /* Hair we handle separate and compute transform based on hair keys. */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); @@ -1051,7 +1335,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem pamat[3][3] = 1.0f; } else { - /* first key */ + /* First key. */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; @@ -1070,16 +1354,16 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem part->instance_collection, object, mode) { copy_m4_m4(tmat, oblist[b]->obmat); - /* apply particle scale */ + /* Apply particle scale. */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); - /* collection dupli offset, should apply after everything else */ + /* Collection dupli-offset, should apply after everything else. */ if (!is_zero_v3(part->instance_collection->instance_offset)) { sub_v3_v3(tmat[3], part->instance_collection->instance_offset); } - /* individual particle transform */ + /* Individual particle transform. */ mul_m4_m4m4(mat, pamat, tmat); dob = make_dupli(ctx, object, mat, a); @@ -1113,13 +1397,13 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem quat_to_mat4(obmat, q); obmat[3][3] = 1.0f; - /* add scaling if requested */ + /* Add scaling if requested. */ if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0) { mul_m4_m4m4(obmat, obmat, size_mat); } } else if (part->draw & PART_DRAW_NO_SCALE_OB) { - /* remove scaling */ + /* Remove scaling. */ float size_mat[4][4], original_size[3]; mat4_to_size(original_size, obmat); @@ -1147,7 +1431,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem BLI_rng_free(rng); } - /* clean up */ + /* Clean up. */ if (oblist) { MEM_freeN(oblist); } @@ -1163,9 +1447,9 @@ static void make_duplis_particles(const DupliContext *ctx) ParticleSystem *psys; int psysid; - /* particle system take up one level in id, the particles another */ + /* Particle system take up one level in id, the particles another. */ for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) { - /* particles create one more level for persistent psys index */ + /* Particles create one more level for persistent `psys` index. */ DupliContext pctx; copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid); make_duplis_particle_system(&pctx, psys); @@ -1192,7 +1476,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) return NULL; } - /* Should the dupli's be generated for this object? - Respect restrict flags */ + /* Should the dupli's be generated for this object? - Respect restrict flags. */ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEWPORT)) { return NULL; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index bdda03bab12..7e25e8c96ae 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1002,7 +1002,7 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) return NULL; } -/* Used by metaballs, return *all* objects (including duplis) +/* Used by meta-balls, return *all* objects (including duplis) * existing in the scene (including scene's sets). */ int BKE_scene_base_iter_next( Depsgraph *depsgraph, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) @@ -1073,7 +1073,7 @@ int BKE_scene_base_iter_next( else { if (iter->phase != F_DUPLI) { if (depsgraph && (*base)->object->transflag & OB_DUPLI) { - /* collections cannot be duplicated for metaballs yet, + /* Collections cannot be duplicated for meta-balls yet, * this enters eternal loop because of * makeDispListMBall getting called inside of collection_duplilist */ if ((*base)->object->instance_collection == NULL) { diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 1ab9766a7ec..6a6f74d9fb4 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2965,6 +2965,9 @@ static void lattice_to_softbody(Scene *scene, Object *ob) if (ob->softflag & OB_SB_EDGES) { makelatticesprings(lt, ob->soft->bspring, ob->softflag & OB_SB_QUADS, ob); build_bps_springlist(ob); /* link bps to springs */ + if (ob->softflag & OB_SB_SELF) { + calculate_collision_balls(ob); + } } } diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 86c57491393..0997b42a19f 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -234,7 +234,7 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_ SubdivCCG *subdiv_ccg = data->subdiv_ccg; const int ptex_face_index = data->face_ptex_offset[face_index]; const int grid_size = subdiv_ccg->grid_size; - const float grid_size_1_inv = 1.0f / (float)(grid_size - 1); + const float grid_size_1_inv = 1.0f / (grid_size - 1); const int element_size = element_size_bytes_get(subdiv_ccg); SubdivCCGFace *faces = subdiv_ccg->faces; SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces; @@ -243,9 +243,9 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_ const int grid_index = face->start_grid_index + corner; unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index]; for (int y = 0; y < grid_size; y++) { - const float grid_v = (float)y * grid_size_1_inv; + const float grid_v = y * grid_size_1_inv; for (int x = 0; x < grid_size; x++) { - const float grid_u = (float)x * grid_size_1_inv; + const float grid_u = x * grid_size_1_inv; float u, v; BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v); const size_t grid_element_index = (size_t)y * grid_size + x; @@ -265,7 +265,7 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const int face_ { SubdivCCG *subdiv_ccg = data->subdiv_ccg; const int grid_size = subdiv_ccg->grid_size; - const float grid_size_1_inv = 1.0f / (float)(grid_size - 1); + const float grid_size_1_inv = 1.0f / (grid_size - 1); const int element_size = element_size_bytes_get(subdiv_ccg); SubdivCCGFace *faces = subdiv_ccg->faces; SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces; @@ -275,9 +275,9 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const int face_ const int ptex_face_index = data->face_ptex_offset[face_index] + corner; unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index]; for (int y = 0; y < grid_size; y++) { - const float u = 1.0f - ((float)y * grid_size_1_inv); + const float u = 1.0f - (y * grid_size_1_inv); for (int x = 0; x < grid_size; x++) { - const float v = 1.0f - ((float)x * grid_size_1_inv); + const float v = 1.0f - (x * grid_size_1_inv); const size_t grid_element_index = (size_t)y * grid_size + x; const size_t grid_element_offset = grid_element_index * element_size; subdiv_ccg_eval_grid_element(data, ptex_face_index, u, v, &grid[grid_element_offset]); @@ -766,7 +766,7 @@ static void subdiv_ccg_average_inner_face_normals(SubdivCCG *subdiv_ccg, counter++; } /* Normalize and store. */ - mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y), normal_acc, 1.0f / (float)counter); + mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y), normal_acc, 1.0f / counter); } } } @@ -1009,7 +1009,7 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg, CCGElem *grid_center_element = CCG_grid_elem(key, grid, 0, 0); element_accumulator_add(¢er_accumulator, subdiv_ccg, key, grid_center_element); } - element_accumulator_mul_fl(¢er_accumulator, 1.0f / (float)num_face_grids); + element_accumulator_mul_fl(¢er_accumulator, 1.0f / num_face_grids); for (int corner = 0; corner < num_face_grids; corner++) { CCGElem *grid = grids[face->start_grid_index + corner]; CCGElem *grid_center_element = CCG_grid_elem(key, grid, 0, 0); @@ -1066,7 +1066,7 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg, } } for (int i = 1; i < grid_size2 - 1; i++) { - element_accumulator_mul_fl(&tls->accumulators[i], 1.0f / (float)num_adjacent_faces); + element_accumulator_mul_fl(&tls->accumulators[i], 1.0f / num_adjacent_faces); } /* Copy averaged value to all the other faces. */ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { @@ -1118,7 +1118,7 @@ static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg, key, subdiv_ccg, &adjacent_vertex->corner_coords[face_index]); element_accumulator_add(&accumulator, subdiv_ccg, key, grid_element); } - element_accumulator_mul_fl(&accumulator, 1.0f / (float)num_adjacent_faces); + element_accumulator_mul_fl(&accumulator, 1.0f / num_adjacent_faces); /* Copy averaged value to all the other faces. */ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { CCGElem *grid_element = subdiv_ccg_coord_to_elem( @@ -1933,4 +1933,47 @@ void BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG *subdiv_ccg, int grid_index) subdiv_ccg->grid_hidden[grid_index] = BLI_BITMAP_NEW(key.grid_area, __func__); } +static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + int *r_ptex_face_index, + float *r_u, + float *r_v) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + + const float grid_size = subdiv_ccg->grid_size; + const float grid_size_1_inv = 1.0f / (grid_size - 1); + + const float grid_u = coord->x * grid_size_1_inv; + const float grid_v = coord->y * grid_size_1_inv; + + const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord->grid_index); + const SubdivCCGFace *faces = subdiv_ccg->faces; + const SubdivCCGFace *face = &faces[face_index]; + const int *face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); + *r_ptex_face_index = face_ptex_offset[face_index]; + + const float corner = coord->grid_index - face->start_grid_index; + + if (face->num_grids == 4) { + BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_u, r_v); + } + else { + *r_ptex_face_index += corner; + *r_u = 1.0f - grid_v; + *r_v = 1.0f - grid_u; + } +} + +void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + float r_point[3]) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + int ptex_face_index; + float u, v; + subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, &ptex_face_index, &u, &v); + BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_point); +} + /** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c index f03cf4c4d21..2c900fbd600 100644 --- a/source/blender/blenkernel/intern/subdiv_deform.c +++ b/source/blender/blenkernel/intern/subdiv_deform.c @@ -214,7 +214,7 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, } } - /* Initialize subdivion mesh creation context. */ + /* Initialize subdivision mesh creation context. */ SubdivDeformContext subdiv_context = {0}; subdiv_context.coarse_mesh = coarse_mesh; subdiv_context.subdiv = subdiv; diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c index 37cca12721a..4400e9c976f 100644 --- a/source/blender/blenkernel/intern/subdiv_foreach.c +++ b/source/blender/blenkernel/intern/subdiv_foreach.c @@ -1746,7 +1746,7 @@ static void subdiv_foreach_vertices_of_loose_edges_task(void *__restrict userdat const int num_subdiv_vertices_per_coarse_edge = resolution - 2; const Mesh *coarse_mesh = ctx->coarse_mesh; const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index]; - /* Subdivion vertices which corresponds to edge's v1 and v2. */ + /* Subdivision vertices which corresponds to edge's v1 and v2. */ const int subdiv_v1_index = ctx->vertices_corner_offset + coarse_edge->v1; const int subdiv_v2_index = ctx->vertices_corner_offset + coarse_edge->v2; /* First subdivided inner vertex of the edge. */ diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 987cc0311c7..8f97fb82db7 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -1207,7 +1207,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, return NULL; } } - /* Initialize subdivion mesh creation context. */ + /* Initialize subdivision mesh creation context. */ SubdivMeshContext subdiv_context = {0}; subdiv_context.settings = settings; subdiv_context.coarse_mesh = coarse_mesh; diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc index fd2de9864af..752f833461d 100644 --- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc +++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc @@ -182,8 +182,9 @@ static int get_edge(const CDT_result *r, int out_index_1, int out_index_2) for (i = 0; i < r->edges_len; i++) { if ((r->edges[i][0] == out_index_1 && r->edges[i][1] == out_index_2) || - (r->edges[i][0] == out_index_2 && r->edges[i][1] == out_index_1)) + (r->edges[i][0] == out_index_2 && r->edges[i][1] == out_index_1)) { return i; + } } return -1; } @@ -191,28 +192,33 @@ static int get_edge(const CDT_result *r, int out_index_1, int out_index_2) /* return true if given output edge has given input edge id in its originals list */ static bool out_edge_has_input_id(const CDT_result *r, int out_edge_index, int in_edge_index) { - if (r->edges_orig == NULL) + if (r->edges_orig == NULL) { return false; - if (out_edge_index < 0 || out_edge_index >= r->edges_len) + } + if (out_edge_index < 0 || out_edge_index >= r->edges_len) { return false; + } for (int i = 0; i < r->edges_orig_len_table[out_edge_index]; i++) { - if (r->edges_orig[r->edges_orig_start_table[out_edge_index] + i] == in_edge_index) + if (r->edges_orig[r->edges_orig_start_table[out_edge_index] + i] == in_edge_index) { return true; + } } return false; } /* which face is for given output vertex ngon? */ -static int get_face(const CDT_result *r, int *out_indices, int nverts) +static int get_face(const CDT_result *r, const int *out_indices, int nverts) { int f, cycle_start, k, fstart; bool ok; - if (r->faces_len == 0) + if (r->faces_len == 0) { return -1; + } for (f = 0; f < r->faces_len; f++) { - if (r->faces_len_table[f] != nverts) + if (r->faces_len_table[f] != nverts) { continue; + } fstart = r->faces_start_table[f]; for (cycle_start = 0; cycle_start < nverts; cycle_start++) { ok = true; @@ -242,13 +248,16 @@ static int get_face_tri(const CDT_result *r, int out_index_1, int out_index_2, i /* return true if given otuput face has given input face id in its originals list */ static bool out_face_has_input_id(const CDT_result *r, int out_face_index, int in_face_index) { - if (r->faces_orig == NULL) + if (r->faces_orig == NULL) { return false; - if (out_face_index < 0 || out_face_index >= r->faces_len) + } + if (out_face_index < 0 || out_face_index >= r->faces_len) { return false; + } for (int i = 0; i < r->faces_orig_len_table[out_face_index]; i++) { - if (r->faces_orig[r->faces_orig_start_table[out_face_index] + i] == in_face_index) + if (r->faces_orig[r->faces_orig_start_table[out_face_index] + i] == in_face_index) { return true; + } } return false; } @@ -266,40 +275,46 @@ static void dump_result(CDT_result *r) r->edges_len, r->faces_len); fprintf(stderr, "\nvert coords:\n"); - for (i = 0; i < r->verts_len; i++) + for (i = 0; i < r->verts_len; i++) { fprintf(stderr, "%d: (%f,%f)\n", i, r->vert_coords[i][0], r->vert_coords[i][1]); + } fprintf(stderr, "vert orig:\n"); for (i = 0; i < r->verts_len; i++) { fprintf(stderr, "%d:", i); - for (j = 0; j < r->verts_orig_len_table[i]; j++) + for (j = 0; j < r->verts_orig_len_table[i]; j++) { fprintf(stderr, " %d", r->verts_orig[r->verts_orig_start_table[i] + j]); + } fprintf(stderr, "\n"); } fprintf(stderr, "\nedges:\n"); - for (i = 0; i < r->edges_len; i++) + for (i = 0; i < r->edges_len; i++) { fprintf(stderr, "%d: (%d,%d)\n", i, r->edges[i][0], r->edges[i][1]); + } if (r->edges_orig) { fprintf(stderr, "edge orig:\n"); for (i = 0; i < r->edges_len; i++) { fprintf(stderr, "%d:", i); - for (j = 0; j < r->edges_orig_len_table[i]; j++) + for (j = 0; j < r->edges_orig_len_table[i]; j++) { fprintf(stderr, " %d", r->edges_orig[r->edges_orig_start_table[i] + j]); + } fprintf(stderr, "\n"); } } fprintf(stderr, "\nfaces:\n"); for (i = 0; i < r->faces_len; i++) { fprintf(stderr, "%d: ", i); - for (j = 0; j < r->faces_len_table[i]; j++) + for (j = 0; j < r->faces_len_table[i]; j++) { fprintf(stderr, " %d", r->faces[r->faces_start_table[i] + j]); + } fprintf(stderr, "\n"); } if (r->faces_orig) { fprintf(stderr, "face orig:\n"); for (i = 0; i < r->faces_len; i++) { fprintf(stderr, "%d:", i); - for (j = 0; j < r->faces_orig_len_table[i]; j++) + for (j = 0; j < r->faces_orig_len_table[i]; j++) { fprintf(stderr, " %d", r->faces_orig[r->faces_orig_start_table[i] + j]); + } fprintf(stderr, "\n"); } } @@ -908,8 +923,9 @@ TEST(delaunay, OverlapFaces) EXPECT_TRUE(out_face_has_input_id(out, f1_out, 0)); EXPECT_TRUE(out_face_has_input_id(out, f1_out, 1)); f2_out = get_face_tri(out, v_out[8], v_out[9], v_out[10]); - if (f2_out == -1) + if (f2_out == -1) { f2_out = get_face_tri(out, v_out[8], v_out[9], v_out[11]); + } EXPECT_NE(f2_out, -1); EXPECT_TRUE(out_face_has_input_id(out, f2_out, 0)); EXPECT_TRUE(out_face_has_input_id(out, f2_out, 2)); diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 4b8e6ed8085..6cfebd0ea05 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -8,10 +8,6 @@ #include "BLI_path_util.h" #include "BLI_string.h" -#ifdef _WIN32 -# include "BKE_global.h" -#endif - /* -------------------------------------------------------------------- */ /* tests */ diff --git a/source/blender/blenlib/tests/BLI_polyfill_2d_test.cc b/source/blender/blenlib/tests/BLI_polyfill_2d_test.cc index a5949c58037..624a296e758 100644 --- a/source/blender/blenlib/tests/BLI_polyfill_2d_test.cc +++ b/source/blender/blenlib/tests/BLI_polyfill_2d_test.cc @@ -56,7 +56,7 @@ static void test_valid_polyfill_prepare(unsigned int tris[][3], unsigned int tri * - all tris set. * - all verts used at least once. */ -static void test_polyfill_simple(const float poly[][2], +static void test_polyfill_simple(const float /*poly*/[][2], const unsigned int poly_tot, const unsigned int tris[][3], const unsigned int tris_tot) @@ -79,7 +79,7 @@ static void test_polyfill_simple(const float poly[][2], MEM_freeN(tot_used); } -static void test_polyfill_topology(const float poly[][2], +static void test_polyfill_topology(const float /*poly*/[][2], const unsigned int poly_tot, const unsigned int tris[][3], const unsigned int tris_tot) @@ -125,7 +125,7 @@ static void test_polyfill_topology(const float poly[][2], * Check all faces are flipped the same way */ static void test_polyfill_winding(const float poly[][2], - const unsigned int poly_tot, + const unsigned int /*poly_tot*/, const unsigned int tris[][3], const unsigned int tris_tot) { diff --git a/source/blender/blenlib/tests/performance/CMakeLists.txt b/source/blender/blenlib/tests/performance/CMakeLists.txt index c7cb65f78b2..88fbed0a49b 100644 --- a/source/blender/blenlib/tests/performance/CMakeLists.txt +++ b/source/blender/blenlib/tests/performance/CMakeLists.txt @@ -21,10 +21,6 @@ set(INC . .. - ../../../source/blender/blenlib - ../../../source/blender/makesdna - ../../../intern/guardedalloc - ../../../intern/atomic ) setup_libdirs() diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 27f282cb760..70fc852ed1b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5296,6 +5296,8 @@ static void direct_link_modifiers(BlendDataReader *reader, ListBase *lb, Object BLO_read_list(reader, lb); for (md = lb->first; md; md = md->next) { + BKE_modifier_session_uuid_generate(md); + md->error = NULL; md->runtime = NULL; diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 631961e342d..b4bee9a3c7e 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -174,7 +174,7 @@ static void blo_update_defaults_screen(bScreen *screen, } else if (area->spacetype == SPACE_SEQ) { SpaceSeq *seq = area->spacedata.first; - seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES; + seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT; } else if (area->spacetype == SPACE_TEXT) { /* Show syntax and line numbers in Script workspace text editor. */ @@ -722,6 +722,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) brush->sculpt_tool = SCULPT_TOOL_DRAW_FACE_SETS; } + brush_name = "Multires Displacement Eraser"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER; + } + /* Use the same tool icon color in the brush cursor */ for (brush = bmain->brushes.first; brush; brush = brush->id.next) { if (brush->ob_mode & OB_MODE_SCULPT) { diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index b97b5cc95f2..0eeb0d21b5b 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../blenkernel ../blenlib ../blentranslation + ../depsgraph ../makesdna ../../../intern/atomic ../../../intern/eigen diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c index 8db125970fd..4671df90d53 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.c +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c @@ -90,6 +90,8 @@ #include "BKE_key.h" #include "BKE_main.h" +#include "DEG_depsgraph_query.h" + #include "bmesh.h" #include "intern/bmesh_private.h" /* For element checking. */ @@ -231,7 +233,13 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar /* -------------------------------------------------------------------- */ /* Shape Key */ - int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0; + int tot_shape_keys = 0; + if (me->key != NULL && DEG_is_original_id(&me->id)) { + /* Evaluated meshes can be topologically inconsistent with their shape keys. + * Shape keys are also already integrated into the state of the evaluated + * mesh, so considering them here would kind of apply them twice. */ + tot_shape_keys = BLI_listbase_count(&me->key->block); + } if (is_new == false) { tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY)); } @@ -239,7 +247,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL; - if ((params->active_shapekey != 0) && (me->key != NULL)) { + if ((params->active_shapekey != 0) && tot_shape_keys > 0) { actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1); } else { @@ -298,7 +306,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1; + const int cd_shape_key_offset = tot_shape_keys ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : + -1; const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1; diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index a9d1972bd7e..61a81e56a2e 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -2511,6 +2511,22 @@ bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) return false; } +bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len) +{ + if (e->l) { + BMLoop *l_iter, *l_first; + + l_iter = l_first = e->l; + do { + if (l_iter->f->len == len) { + return true; + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + + return false; +} + /** * Use within assert's to check normals are valid. */ diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index 4ec6b0e50d1..1ff2558ce83 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -243,6 +243,9 @@ bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag) ATTR_WARN_ bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(); + bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); double BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_query_uv.c b/source/blender/bmesh/intern/bmesh_query_uv.c index b9ea51f0c4d..1aa75bfb037 100644 --- a/source/blender/bmesh/intern/bmesh_query_uv.c +++ b/source/blender/bmesh/intern/bmesh_query_uv.c @@ -95,6 +95,20 @@ void BM_face_uv_calc_center_median_weighted(const BMFace *f, #undef UV_ASPECT +void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2]) +{ + const BMLoop *l_iter; + const BMLoop *l_first; + zero_v2(r_cent); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + add_v2_v2(r_cent, luv->uv); + } while ((l_iter = l_iter->next) != l_first); + + mul_v2_fl(r_cent, 1.0f / (float)f->len); +} + /** * Calculate the UV cross product (use the sign to check the winding). */ diff --git a/source/blender/bmesh/intern/bmesh_query_uv.h b/source/blender/bmesh/intern/bmesh_query_uv.h index 3465a831bea..0a86c0cbeae 100644 --- a/source/blender/bmesh/intern/bmesh_query_uv.h +++ b/source/blender/bmesh/intern/bmesh_query_uv.h @@ -31,6 +31,8 @@ void BM_face_uv_calc_center_median_weighted(const BMFace *f, const float aspect[2], const int cd_loop_uv_offset, float r_cent[2]) ATTR_NONNULL(); +void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2]) + ATTR_NONNULL(); float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index ec3ed05375c..b9c9aa3aec8 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -427,9 +427,8 @@ static FKind get_face_kind(BevelParams *bp, BMFace *f) /* Are d1 and d2 parallel or nearly so? */ static bool nearly_parallel(const float d1[3], const float d2[3]) { - float ang; + float ang = angle_v3v3(d1, d2); - ang = angle_v3v3(d1, d2); return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG); } @@ -493,10 +492,8 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto, int ifrom, int jfrom, int kfrom) { - NewVert *nvto, *nvfrom; - - nvto = mesh_vert(vm, ito, jto, kto); - nvfrom = mesh_vert(vm, ifrom, jfrom, kfrom); + NewVert *nvto = mesh_vert(vm, ito, jto, kto); + NewVert *nvfrom = mesh_vert(vm, ifrom, jfrom, kfrom); nvto->v = nvfrom->v; copy_v3_v3(nvto->co, nvfrom->co); } @@ -504,9 +501,7 @@ static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto, int ifrom, int /* Find the EdgeHalf in bv's array that has edge bme. */ static EdgeHalf *find_edge_half(BevVert *bv, BMEdge *bme) { - int i; - - for (i = 0; i < bv->edgecount; i++) { + for (int i = 0; i < bv->edgecount; i++) { if (bv->edges[i].e == bme) { return &bv->edges[i]; } @@ -527,15 +522,12 @@ static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv) */ static EdgeHalf *find_other_end_edge_half(BevelParams *bp, EdgeHalf *e, BevVert **r_bvother) { - BevVert *bvo; - EdgeHalf *eother; - - bvo = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2); + BevVert *bvo = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2); if (bvo) { if (r_bvother) { *r_bvother = bvo; } - eother = find_edge_half(bvo, e->e); + EdgeHalf *eother = find_edge_half(bvo, e->e); BLI_assert(eother != NULL); return eother; } @@ -549,12 +541,10 @@ static EdgeHalf *find_other_end_edge_half(BevelParams *bp, EdgeHalf *e, BevVert * If from_e is NULL, find the first beveled edge. */ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) { - EdgeHalf *e; - if (from_e == NULL) { from_e = &bv->edges[bv->edgecount - 1]; } - e = from_e; + EdgeHalf *e = from_e; do { if (e->is_bev) { return e; @@ -584,9 +574,8 @@ static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2) * where the next or previous edge in the face must be bme2. */ static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2) { - BMLoop *l; BMIter iter; - + BMLoop *l; BM_ITER_ELEM (l, &iter, bme1, BM_LOOPS_OF_EDGE) { if (l->prev->e == bme2 || l->next->e == bme2) { return true; @@ -604,9 +593,9 @@ static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2) */ static BMFace *boundvert_rep_face(BoundVert *v, BMFace **r_fother) { - BMFace *frep, *frep2; + BMFace *frep; - frep2 = NULL; + BMFace *frep2 = NULL; if (v->ebev) { frep = v->ebev->fprev; if (v->efirst->fprev != frep) { @@ -675,20 +664,16 @@ static BMFace *bev_create_ngon(BMesh *bm, int mat_nr, bool do_interp) { - BMIter iter; - BMLoop *l; - BMFace *f, *interp_f; - BMEdge *bme; - float save_co[3]; - int i; - - f = BM_face_create_verts(bm, vert_arr, totv, facerep, BM_CREATE_NOP, true); + BMFace *f = BM_face_create_verts(bm, vert_arr, totv, facerep, BM_CREATE_NOP, true); if ((facerep || (face_arr && face_arr[0])) && f) { BM_elem_attrs_copy(bm, bm, facerep ? facerep : face_arr[0], f); if (do_interp) { - i = 0; + int i = 0; + BMIter iter; + BMLoop *l; BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { + BMFace *interp_f; if (face_arr) { /* Assume loops of created face are in same order as verts. */ BLI_assert(l->v == vert_arr[i]); @@ -698,10 +683,11 @@ static BMFace *bev_create_ngon(BMesh *bm, interp_f = facerep; } if (interp_f) { - bme = NULL; + BMEdge *bme = NULL; if (edge_arr) { bme = edge_arr[i]; } + float save_co[3]; if (bme) { copy_v3_v3(save_co, l->v->co); closest_to_line_segment_v3(l->v->co, save_co, bme->v1->co, bme->v2->co); @@ -720,6 +706,8 @@ static BMFace *bev_create_ngon(BMesh *bm, * this is done so the operator can select newly created geometry. */ if (f) { BM_elem_flag_enable(f, BM_ELEM_TAG); + BMIter iter; + BMEdge *bme; BM_ITER_ELEM (bme, &iter, f, BM_EDGES_OF_FACE) { flag_out_edge(bm, bme); } @@ -784,16 +772,11 @@ static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2, int lay */ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f2) { - BMLoop *lef1, *lef2; - BMLoop *lv1f1, *lv1f2, *lv2f1, *lv2f2; - BMVert *v1, *v2; - UNUSED_VARS_NDEBUG(v1, v2); - int i; - if (bm->ldata.totlayer == 0) { return true; } + BMLoop *lef1, *lef2; if (!BM_edge_loop_pair(e, &lef1, &lef2)) { return false; } @@ -806,16 +789,17 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f if (lef1->f != f1 || lef2->f != f2) { return false; } - v1 = lef1->v; - v2 = lef2->v; + BMVert *v1 = lef1->v; + BMVert *v2 = lef2->v; BLI_assert((v1 == e->v1 && v2 == e->v2) || (v1 == e->v2 && v2 == e->v1)); - lv1f1 = lef1; - lv2f1 = lef1->next; - lv1f2 = lef2->next; - lv2f2 = lef2; + UNUSED_VARS_NDEBUG(v1, v2); + BMLoop *lv1f1 = lef1; + BMLoop *lv2f1 = lef1->next; + BMLoop *lv1f2 = lef2->next; + BMLoop *lv2f2 = lef2; BLI_assert(lv1f1->v == v1 && lv1f1->f == f1 && lv2f1->v == v2 && lv2f1->f == f1 && lv1f2->v == v1 && lv1f2->f == f2 && lv2f2->v == v2 && lv2f2->f == f2); - for (i = 0; i < bm->ldata.totlayer; i++) { + for (int i = 0; i < bm->ldata.totlayer; i++) { if (CustomData_layer_has_math(&bm->ldata, i)) { if (!contig_ldata_across_loops(bm, lv1f1, lv1f2, i) || !contig_ldata_across_loops(bm, lv2f1, lv2f2, i)) { @@ -834,18 +818,9 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f */ static void math_layer_info_init(BevelParams *bp, BMesh *bm) { - int i, f, stack_top, totface, current_component; - int bmf_index, bmf_other_index; - int *face_component; - BMFace *bmf, *bmf_other; - BMEdge *bme; - BMFace **stack; - bool *in_stack; - BMIter eiter, fiter; - bp->math_layer_info.has_math_layers = false; bp->math_layer_info.face_component = NULL; - for (i = 0; i < bm->ldata.totlayer; i++) { + for (int i = 0; i < bm->ldata.totlayer; i++) { if (CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) { bp->math_layer_info.has_math_layers = true; break; @@ -857,32 +832,32 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm) BM_mesh_elem_index_ensure(bm, BM_FACE); BM_mesh_elem_table_ensure(bm, BM_FACE); - totface = bm->totface; - face_component = BLI_memarena_alloc(bp->mem_arena, totface * sizeof(int)); + int totface = bm->totface; + int *face_component = BLI_memarena_alloc(bp->mem_arena, sizeof(int) * totface); bp->math_layer_info.face_component = face_component; /* Use an array as a stack. Stack size can't exceed total faces if keep track of what is in * stack. */ - stack = MEM_malloc_arrayN(totface, sizeof(BMFace *), __func__); - in_stack = MEM_malloc_arrayN(totface, sizeof(bool), __func__); + BMFace **stack = MEM_malloc_arrayN(totface, sizeof(BMFace *), __func__); + bool *in_stack = MEM_malloc_arrayN(totface, sizeof(bool), __func__); /* Set all component ids by DFS from faces with unassigned components. */ - for (f = 0; f < totface; f++) { + for (int f = 0; f < totface; f++) { face_component[f] = -1; in_stack[f] = false; } - current_component = -1; - for (f = 0; f < totface; f++) { + int current_component = -1; + for (int f = 0; f < totface; f++) { if (face_component[f] == -1 && !in_stack[f]) { - stack_top = 0; + int stack_top = 0; current_component++; BLI_assert(stack_top < totface); stack[stack_top] = BM_face_at_index(bm, f); in_stack[f] = true; while (stack_top >= 0) { - bmf = stack[stack_top]; + BMFace *bmf = stack[stack_top]; stack_top--; - bmf_index = BM_elem_index_get(bmf); + int bmf_index = BM_elem_index_get(bmf); in_stack[bmf_index] = false; if (face_component[bmf_index] != -1) { continue; @@ -892,10 +867,14 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm) * are where contig_ldata_across_edge(...) is true for the * shared edge and two faces. */ + BMIter eiter; + BMEdge *bme; BM_ITER_ELEM (bme, &eiter, bmf, BM_EDGES_OF_FACE) { + BMIter fiter; + BMFace *bmf_other; BM_ITER_ELEM (bmf_other, &fiter, bme, BM_FACES_OF_EDGE) { if (bmf_other != bmf) { - bmf_other_index = BM_elem_index_get(bmf_other); + int bmf_other_index = BM_elem_index_get(bmf_other); if (face_component[bmf_other_index] != -1 || in_stack[bmf_other_index]) { continue; } @@ -929,26 +908,22 @@ static void math_layer_info_init(BevelParams *bp, BMesh *bm) */ static BMFace *choose_rep_face(BevelParams *bp, BMFace **face, int nfaces) { - int bmf_index, value_index, best_f, i; - BMFace *bmf; - float cent[3]; #define VEC_VALUE_LEN 6 float(*value_vecs)[VEC_VALUE_LEN] = NULL; - bool *still_viable = NULL; int num_viable = 0; value_vecs = BLI_array_alloca(value_vecs, nfaces); - still_viable = BLI_array_alloca(still_viable, nfaces); + bool *still_viable = BLI_array_alloca(still_viable, nfaces); for (int f = 0; f < nfaces; f++) { - bmf = face[f]; + BMFace *bmf = face[f]; if (bmf == NULL) { still_viable[f] = false; continue; } still_viable[f] = true; num_viable++; - bmf_index = BM_elem_index_get(bmf); - value_index = 0; + int bmf_index = BM_elem_index_get(bmf); + int value_index = 0; /* First tie-breaker: lower math-layer connected component id. */ value_vecs[f][value_index++] = bp->math_layer_info.face_component ? (float)bp->math_layer_info.face_component[bmf_index] : @@ -958,6 +933,7 @@ static BMFace *choose_rep_face(BevelParams *bp, BMFace **face, int nfaces) /* Next tie-breaker: lower material index. */ value_vecs[f][value_index++] = bmf->mat_nr >= 0 ? (float)bmf->mat_nr : 0.0f; /* Next three tie-breakers: z, x, y components of face center. */ + float cent[3]; BM_face_calc_center_bounds(bmf, cent); value_vecs[f][value_index++] = cent[2]; value_vecs[f][value_index++] = cent[0]; @@ -968,8 +944,8 @@ static BMFace *choose_rep_face(BevelParams *bp, BMFace **face, int nfaces) /* Look for a face that has a unique minimum value for in a value_index, * trying each value_index in turn until find a unique minimum. */ - best_f = -1; - for (value_index = 0; num_viable > 1 && value_index < VEC_VALUE_LEN; value_index++) { + int best_f = -1; + for (int value_index = 0; num_viable > 1 && value_index < VEC_VALUE_LEN; value_index++) { for (int f = 0; f < nfaces; f++) { if (!still_viable[f] || f == best_f) { continue; @@ -981,7 +957,7 @@ static BMFace *choose_rep_face(BevelParams *bp, BMFace **face, int nfaces) if (value_vecs[f][value_index] < value_vecs[best_f][value_index]) { best_f = f; /* Previous f's are now not viable any more. */ - for (i = f - 1; i >= 0; i--) { + for (int i = f - 1; i >= 0; i--) { if (still_viable[i]) { still_viable[i] = false; num_viable--; @@ -1005,32 +981,28 @@ static BMFace *choose_rep_face(BevelParams *bp, BMFace **face, int nfaces) * Caller should ensure that no seams are violated by doing this. */ static void bev_merge_uvs(BMesh *bm, BMVert *v) { - BMIter iter; - MLoopUV *luv; - BMLoop *l; - float uv[2]; - int n; int num_of_uv_layers = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV); - int i; - for (i = 0; i < num_of_uv_layers; i++) { + for (int i = 0; i < num_of_uv_layers; i++) { int cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, i); if (cd_loop_uv_offset == -1) { return; } - n = 0; - zero_v2(uv); + int n = 0; + float uv[2] = {0.0f, 0.0f}; + BMIter iter; + BMLoop *l; BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); add_v2_v2(uv, luv->uv); n++; } if (n > 1) { mul_v2_fl(uv, 1.0f / (float)n); BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); copy_v2_v2(luv->uv, uv); } } @@ -1041,15 +1013,12 @@ static void bev_merge_uvs(BMesh *bm, BMVert *v) * and part of faces that share edge bme. */ static void bev_merge_edge_uvs(BMesh *bm, BMEdge *bme, BMVert *v) { - BMIter iter; - MLoopUV *luv; - BMLoop *l, *l1, *l2; - float uv[2]; int num_of_uv_layers = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV); - int i; - l1 = NULL; - l2 = NULL; + BMLoop *l1 = NULL; + BMLoop *l2 = NULL; + BMIter iter; + BMLoop *l; BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { if (l->e == bme) { l1 = l; @@ -1062,15 +1031,15 @@ static void bev_merge_edge_uvs(BMesh *bm, BMEdge *bme, BMVert *v) return; } - for (i = 0; i < num_of_uv_layers; i++) { + for (int i = 0; i < num_of_uv_layers; i++) { int cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, i); if (cd_loop_uv_offset == -1) { return; } - zero_v2(uv); - luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset); + float uv[2] = {0.0f, 0.0f}; + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset); add_v2_v2(uv, luv->uv); luv = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_uv_offset); add_v2_v2(uv, luv->uv); @@ -1085,10 +1054,10 @@ static void bev_merge_edge_uvs(BMesh *bm, BMEdge *bme, BMVert *v) /* Calculate coordinates of a point a distance d from v on e->e and return it in slideco. */ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float r_slideco[3]) { - float dir[3], len; - + float dir[3]; sub_v3_v3v3(dir, v->co, BM_edge_other_vert(e->e, v)->co); - len = normalize_v3(dir); + float len = normalize_v3(dir); + if (d > len) { d = len - (float)(50.0 * BEVEL_EPSILON_D); } @@ -1099,12 +1068,13 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float r_slideco[3]) /* Is co not on the edge e? If not, return the closer end of e in ret_closer_v. */ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_v) { - float h[3], u[3], lambda, lenu, *l1 = e->e->v1->co; + float h[3], u[3]; + float *l1 = e->e->v1->co; sub_v3_v3v3(u, e->e->v2->co, l1); sub_v3_v3v3(h, co, l1); - lenu = normalize_v3(u); - lambda = dot_v3v3(u, h); + float lenu = normalize_v3(u); + float lambda = dot_v3v3(u, h); if (lambda <= -BEVEL_EPSILON_BIG * lenu) { *ret_closer_v = e->e->v1; return true; @@ -1119,18 +1089,18 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_ /* Return whether the angle is less than, equal to, or larger than 180 degrees. */ static int edges_angle_kind(EdgeHalf *e1, EdgeHalf *e2, BMVert *v) { - BMVert *v1, *v2; - float dir1[3], dir2[3], cross[3], *no, dot; - - v1 = BM_edge_other_vert(e1->e, v); - v2 = BM_edge_other_vert(e2->e, v); + BMVert *v1 = BM_edge_other_vert(e1->e, v); + BMVert *v2 = BM_edge_other_vert(e2->e, v); + float dir1[3], dir2[3]; sub_v3_v3v3(dir1, v->co, v1->co); sub_v3_v3v3(dir2, v->co, v2->co); normalize_v3(dir1); normalize_v3(dir2); /* Angles are in [0,pi]. Need to compare cross product with normal to see if they are reflex. */ + float cross[3]; cross_v3_v3v3(cross, dir1, dir2); normalize_v3(cross); + float *no; if (e1->fnext) { no = e1->fnext->no; } @@ -1140,7 +1110,7 @@ static int edges_angle_kind(EdgeHalf *e1, EdgeHalf *e2, BMVert *v) else { no = v->no; } - dot = dot_v3v3(cross, no); + float dot = dot_v3v3(cross, no); if (fabsf(dot) < BEVEL_EPSILON_BIG) { return ANGLE_STRAIGHT; } @@ -1155,20 +1125,18 @@ static int edges_angle_kind(EdgeHalf *e1, EdgeHalf *e2, BMVert *v) static bool point_between_edges( const float co[3], BMVert *v, BMFace *f, EdgeHalf *e1, EdgeHalf *e2) { - BMVert *v1, *v2; float dir1[3], dir2[3], dirco[3], no[3]; - float ang11, ang1co; - v1 = BM_edge_other_vert(e1->e, v); - v2 = BM_edge_other_vert(e2->e, v); + BMVert *v1 = BM_edge_other_vert(e1->e, v); + BMVert *v2 = BM_edge_other_vert(e2->e, v); sub_v3_v3v3(dir1, v->co, v1->co); sub_v3_v3v3(dir2, v->co, v2->co); sub_v3_v3v3(dirco, v->co, co); normalize_v3(dir1); normalize_v3(dir2); normalize_v3(dirco); - ang11 = angle_normalized_v3v3(dir1, dir2); - ang1co = angle_normalized_v3v3(dir1, dirco); + float ang11 = angle_normalized_v3v3(dir1, dir2); + float ang1co = angle_normalized_v3v3(dir1, dirco); /* Angles are in [0,pi]. Need to compare cross product with normal to see if they are reflex. */ cross_v3_v3v3(no, dir1, dir2); if (dot_v3v3(no, f->no) < 0.0f) { @@ -1207,22 +1175,15 @@ static void offset_meet(EdgeHalf *e1, float meetco[3], const EdgeHalf *e_in_plane) { - float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3]; - float norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3]; - float isect2[3], dropco[3], plane[4]; - float ang, d; - BMVert *closer_v; - EdgeHalf *e, *e1next, *e2prev; - BMFace *fnext; - int isect_kind; - /* Get direction vectors for two offset lines. */ + float dir1[3], dir2[3]; sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co); sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); + float dir1n[3], dir2p[3]; if (edges_between) { - e1next = e1->next; - e2prev = e2->prev; + EdgeHalf *e1next = e1->next; + EdgeHalf *e2prev = e2->prev; sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co); sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co); } @@ -1232,7 +1193,8 @@ static void offset_meet(EdgeHalf *e1, zero_v3(dir2p); } - ang = angle_v3v3(dir1, dir2); + float ang = angle_v3v3(dir1, dir2); + float norm_perp1[3]; if (ang < BEVEL_EPSILON_ANG) { /* Special case: e1 and e2 are parallel; put offset point perp to both, from v. * need to find a suitable plane. @@ -1242,6 +1204,7 @@ static void offset_meet(EdgeHalf *e1, * If offsets are different, we're out of luck: * Use the max of the two (so get consistent looking results if the same situation * arises elsewhere in the object but with opposite roles for e1 and e2. */ + float norm_v[3]; if (f) { copy_v3_v3(norm_v, f->no); } @@ -1251,8 +1214,9 @@ static void offset_meet(EdgeHalf *e1, add_v3_v3(dir1, dir2); cross_v3_v3v3(norm_perp1, dir1, norm_v); normalize_v3(norm_perp1); + float off1a[3]; copy_v3_v3(off1a, v->co); - d = max_ff(e1->offset_r, e2->offset_l); + float d = max_ff(e1->offset_r, e2->offset_l); d = d / cosf(ang / 2.0f); madd_v3_v3fl(off1a, norm_perp1, d); copy_v3_v3(meetco, off1a); @@ -1260,7 +1224,7 @@ static void offset_meet(EdgeHalf *e1, else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) { /* Special case: e1 and e2 are antiparallel, so bevel is into a zero-area face. * Just make the offset point on the common line, at offset distance from v. */ - d = max_ff(e1->offset_r, e2->offset_l); + float d = max_ff(e1->offset_r, e2->offset_l); slide_dist(e2, v, d, meetco); } else { @@ -1273,6 +1237,7 @@ static void offset_meet(EdgeHalf *e1, * If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip. * Use f->no to figure out which side to look at angle from, as even if f is non-planar, * will be more accurate than vertex normal. */ + float norm_v1[3], norm_v2[3]; if (f && ang < BEVEL_SMALL_ANG) { copy_v3_v3(norm_v1, f->no); copy_v3_v3(norm_v2, f->no); @@ -1302,12 +1267,14 @@ static void offset_meet(EdgeHalf *e1, } /* Get vectors perp to each edge, perp to norm_v, and pointing into face. */ + float norm_perp2[3]; cross_v3_v3v3(norm_perp1, dir1, norm_v1); cross_v3_v3v3(norm_perp2, dir2, norm_v2); normalize_v3(norm_perp1); normalize_v3(norm_perp2); /* Get points that are offset distances from each line, then another point on each line. */ + float off1a[3], off1b[3], off2a[3], off2b[3]; copy_v3_v3(off1a, v->co); madd_v3_v3fl(off1a, norm_perp1, e1->offset_r); add_v3_v3v3(off1b, off1a, dir1); @@ -1316,7 +1283,8 @@ static void offset_meet(EdgeHalf *e1, add_v3_v3v3(off2b, off2a, dir2); /* Intersect the offset lines. */ - isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2); + float isect2[3]; + int isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2); if (isect_kind == 0) { /* Lines are collinear: we already tested for this, but this used a different epsilon. */ copy_v3_v3(meetco, off1a); /* Just to do something. */ @@ -1326,6 +1294,7 @@ static void offset_meet(EdgeHalf *e1, * One problem to check: if one of the offsets is 0, then we don't want an intersection * that is outside that edge itself. This can happen if angle between them is > 180 degrees, * or if the offset amount is > the edge length. */ + BMVert *closer_v; if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) { copy_v3_v3(meetco, closer_v->co); } @@ -1338,12 +1307,14 @@ static void offset_meet(EdgeHalf *e1, /* Lines didn't meet in 3d: get average of meetco and isect2. */ mid_v3_v3v3(meetco, meetco, isect2); } - for (e = e1; e != e2; e = e->next) { - fnext = e->fnext; + for (EdgeHalf *e = e1; e != e2; e = e->next) { + BMFace *fnext = e->fnext; if (!fnext) { continue; } + float plane[4]; plane_from_point_normal_v3(plane, v->co, fnext->no); + float dropco[3]; closest_to_plane_normalized_v3(dropco, plane, meetco); /* Don't drop to the faces next to the in plane edge. */ if (e_in_plane) { @@ -1376,21 +1347,21 @@ static void offset_meet(EdgeHalf *e1, static bool offset_meet_edge( EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetco[3], float *r_angle) { - float dir1[3], dir2[3], fno[3], ang, sinang; - + float dir1[3], dir2[3]; sub_v3_v3v3(dir1, BM_edge_other_vert(e1->e, v)->co, v->co); sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); normalize_v3(dir1); normalize_v3(dir2); /* Find angle from dir1 to dir2 as viewed from vertex normal side. */ - ang = angle_normalized_v3v3(dir1, dir2); + float ang = angle_normalized_v3v3(dir1, dir2); if (fabsf(ang) < BEVEL_GOOD_ANGLE) { if (r_angle) { *r_angle = 0.0f; } return false; } + float fno[3]; cross_v3_v3v3(fno, dir1, dir2); if (dot_v3v3(fno, v->no) < 0.0f) { ang = 2.0f * (float)M_PI - ang; /* Angle is reflex. */ @@ -1407,7 +1378,7 @@ static bool offset_meet_edge( return false; } - sinang = sinf(ang); + float sinang = sinf(ang); copy_v3_v3(meetco, v->co); if (e1->offset_r == 0.0f) { @@ -1440,15 +1411,14 @@ static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *em static bool offset_on_edge_between( EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v, float meetco[3], float *r_sinratio) { - float ang1, ang2; - float meet1[3], meet2[3]; - bool ok1, ok2; bool retval = false; BLI_assert(e1->is_bev && e2->is_bev && !emid->is_bev); - ok1 = offset_meet_edge(e1, emid, v, meet1, &ang1); - ok2 = offset_meet_edge(emid, e2, v, meet2, &ang2); + float ang1, ang2; + float meet1[3], meet2[3]; + bool ok1 = offset_meet_edge(e1, emid, v, meet1, &ang1); + bool ok2 = offset_meet_edge(emid, e2, v, meet2, &ang2); if (ok1 && ok2) { mid_v3_v3v3(meetco, meet1, meet2); if (r_sinratio) { @@ -1476,11 +1446,9 @@ static bool offset_on_edge_between( * If plane_no is NULL, choose an arbitrary plane different from eh's direction. */ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, float r_co[3]) { - float dir[3], no[3], fdir[3]; - BMVert *v; - - v = e->is_rev ? e->e->v2 : e->e->v1; + BMVert *v = e->is_rev ? e->e->v2 : e->e->v1; + float dir[3], no[3]; sub_v3_v3v3(dir, BM_edge_other_vert(e->e, v)->co, v->co); normalize_v3(dir); if (plane_no) { @@ -1495,6 +1463,8 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, flo no[1] = 1.0f; } } + + float fdir[3]; if (left) { cross_v3_v3v3(fdir, dir, no); } @@ -1513,7 +1483,6 @@ static void project_to_edge(const BMEdge *e, float projco[3]) { float otherco[3]; - if (!isect_line_line_v3(e->v1->co, e->v2->co, co_a, co_b, projco, otherco)) { #ifdef BEVEL_ASSERT_PROJECT BLI_assert(!"project meet failure"); @@ -1526,11 +1495,11 @@ static void project_to_edge(const BMEdge *e, * It is the closest point on the beveled edge to the line segment between bndv and bndv->next. */ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) { - float start[3], end[3], co3[3], d1[3], d2[3]; bool do_linear_interp = true; EdgeHalf *e = bndv->ebev; Profile *pro = &bndv->profile; + float start[3], end[3]; copy_v3_v3(start, bndv->nv.co); copy_v3_v3(end, bndv->next->nv.co); if (e) { @@ -1546,6 +1515,7 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) copy_v3_v3(pro->start, start); copy_v3_v3(pro->end, end); /* Default plane to project onto is the one with triangle start - middle - end in it. */ + float d1[3], d2[3]; sub_v3_v3v3(d1, pro->middle, start); sub_v3_v3v3(d2, pro->middle, end); normalize_v3(d1); @@ -1577,6 +1547,7 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) do_linear_interp = true; } else { + float co3[3]; add_v3_v3v3(co3, start, d3); add_v3_v3v3(co4, end, d4); isect_kind = isect_line_line_v3(start, co3, end, co4, meetco, isect2); @@ -1650,24 +1621,27 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) */ static void move_profile_plane(BoundVert *bndv, BMVert *bmvert) { - float d1[3], d2[3], no[3], no2[3], no3[3], dot2, dot3; Profile *pro = &bndv->profile; /* Only do this if projecting, and start, end, and proj_dir are not coplanar. */ if (is_zero_v3(pro->proj_dir)) { return; } + + float d1[3], d2[3]; sub_v3_v3v3(d1, bmvert->co, pro->start); normalize_v3(d1); sub_v3_v3v3(d2, bmvert->co, pro->end); normalize_v3(d2); + float no[3], no2[3], no3[3]; cross_v3_v3v3(no, d1, d2); cross_v3_v3v3(no2, d1, pro->proj_dir); cross_v3_v3v3(no3, d2, pro->proj_dir); + if (normalize_v3(no) > BEVEL_EPSILON_BIG && normalize_v3(no2) > BEVEL_EPSILON_BIG && normalize_v3(no3) > BEVEL_EPSILON_BIG) { - dot2 = dot_v3v3(no, no2); - dot3 = dot_v3v3(no, no3); + float dot2 = dot_v3v3(no, no2); + float dot3 = dot_v3v3(no, no3); if (fabsf(dot2) < (1 - BEVEL_EPSILON_BIG) && fabsf(dot3) < (1 - BEVEL_EPSILON_BIG)) { copy_v3_v3(bndv->profile.plane_no, no); } @@ -1686,25 +1660,26 @@ static void move_profile_plane(BoundVert *bndv, BMVert *bmvert) */ static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *bndv2) { - float d1[3], d2[3], no[3], no2[3], no3[3], dot1, dot2, l1, l2, l3; - /* Only do this if projecting, and d1, d2, and proj_dir are not coplanar. */ if (is_zero_v3(bndv1->profile.proj_dir) || is_zero_v3(bndv2->profile.proj_dir)) { return; } + float d1[3], d2[3], no[3]; sub_v3_v3v3(d1, bv->v->co, bndv1->nv.co); sub_v3_v3v3(d2, bv->v->co, bndv2->nv.co); cross_v3_v3v3(no, d1, d2); - l1 = normalize_v3(no); + float l1 = normalize_v3(no); + /* "no" is new normal projection plane, but don't move if it is coplanar with both of the * projection dirs. */ + float no2[3], no3[3]; cross_v3_v3v3(no2, d1, bndv1->profile.proj_dir); - l2 = normalize_v3(no2); + float l2 = normalize_v3(no2); cross_v3_v3v3(no3, d2, bndv2->profile.proj_dir); - l3 = normalize_v3(no3); + float l3 = normalize_v3(no3); if (l1 > BEVEL_EPSILON && (l2 > BEVEL_EPSILON || l3 > BEVEL_EPSILON)) { - dot1 = fabsf(dot_v3v3(no, no2)); - dot2 = fabsf(dot_v3v3(no, no3)); + float dot1 = fabsf(dot_v3v3(no, no2)); + float dot2 = fabsf(dot_v3v3(no, no3)); if (fabsf(dot1 - 1.0f) > BEVEL_EPSILON) { copy_v3_v3(bndv1->profile.plane_no, no); } @@ -1722,13 +1697,11 @@ static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *b * and -1 if they are reversed, and 0 if there is no shared face f. */ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f) { - BMLoop *la, *lb; - if (!f) { return 0; } - la = BM_face_edge_share_loop(f, a); - lb = BM_face_edge_share_loop(f, b); + BMLoop *la = BM_face_edge_share_loop(f, a); + BMLoop *lb = BM_face_edge_share_loop(f, b); if (!la || !lb) { return 0; } @@ -1761,8 +1734,7 @@ static bool make_unit_square_map(const float va[3], const float vb[3], float r_mat[4][4]) { - float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3]; - + float vb_vmid[3], va_vmid[3]; sub_v3_v3v3(va_vmid, vmid, va); sub_v3_v3v3(vb_vmid, vmid, vb); @@ -1774,6 +1746,7 @@ static bool make_unit_square_map(const float va[3], return false; } + float vo[3], vd[3], vddir[3]; sub_v3_v3v3(vo, va, vb_vmid); cross_v3_v3v3(vddir, vb_vmid, va_vmid); normalize_v3(vddir); @@ -1871,8 +1844,6 @@ static double superellipse_co(double x, float r, bool rbig) */ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int nseg, float r_co[3]) { - int subsample_spacing; - if (bp->seg == 1) { if (i == 0) { copy_v3_v3(r_co, pro->start); @@ -1890,7 +1861,7 @@ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int ns else { BLI_assert(is_power_of_2_i(nseg) && nseg <= bp->pro_spacing.seg_2); /* Find spacing between subsamples in prof_co_2. */ - subsample_spacing = bp->pro_spacing.seg_2 / nseg; + int subsample_spacing = bp->pro_spacing.seg_2 / nseg; copy_v3_v3(r_co, pro->prof_co_2 + 3 * i * subsample_spacing); } } @@ -2022,16 +1993,18 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b */ static void snap_to_superellipsoid(float co[3], const float super_r, bool midline) { - float a, b, c, x, y, z, r, rinv, dx, dy; - r = super_r; + float r = super_r; if (r == PRO_CIRCLE_R) { normalize_v3(co); return; } - x = a = max_ff(0.0f, co[0]); - y = b = max_ff(0.0f, co[1]); - z = c = max_ff(0.0f, co[2]); + float a = max_ff(0.0f, co[0]); + float b = max_ff(0.0f, co[1]); + float c = max_ff(0.0f, co[2]); + float x = a; + float y = b; + float z = c; if (r == PRO_SQUARE_R || r == PRO_SQUARE_IN_R) { /* Will only be called for 2d profile. */ BLI_assert(fabsf(z) < BEVEL_EPSILON); @@ -2040,8 +2013,8 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin y = min_ff(1.0f, y); if (r == PRO_SQUARE_R) { /* Snap to closer of x==1 and y==1 lines, or maybe both. */ - dx = 1.0f - x; - dy = 1.0f - y; + float dx = 1.0f - x; + float dy = 1.0f - y; if (dx < dy) { x = 1.0f; y = midline ? 1.0f : y; @@ -2064,7 +2037,7 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin } } else { - rinv = 1.0f / r; + float rinv = 1.0f / r; if (a == 0.0f) { if (b == 0.0f) { x = 0.0f; @@ -2249,11 +2222,8 @@ static void bevel_extend_edge_data(BevVert *bv) /* Mark edges as sharp if they are between a smooth reconstructed face and a new face. */ static void bevel_edges_sharp_boundary(BMesh *bm, BevelParams *bp) { - BMIter fiter, liter; - BMFace *f, *fother; - BMLoop *l, *lother; - FKind fkind; - + BMIter fiter; + BMFace *f; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { continue; @@ -2261,12 +2231,14 @@ static void bevel_edges_sharp_boundary(BMesh *bm, BevelParams *bp) if (get_face_kind(bp, f) != F_RECON) { continue; } + BMIter liter; + BMLoop *l; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { /* Cases we care about will have exactly one adjacent face. */ - lother = l->radial_next; - fother = lother->f; + BMLoop *lother = l->radial_next; + BMFace *fother = lother->f; if (lother != l && fother) { - fkind = get_face_kind(bp, lother->f); + FKind fkind = get_face_kind(bp, lother->f); if (ELEM(fkind, F_EDGE, F_VERT)) { BM_elem_flag_disable(l->e, BM_ELEM_SMOOTH); } @@ -2285,15 +2257,6 @@ static void bevel_edges_sharp_boundary(BMesh *bm, BevelParams *bp) */ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) { - BMIter liter, fiter; - BMFace *f; - BMLoop *l, *lnext, *lprev, *lprevprev, *lnextnext; - BMEdge *estep; - FKind fkind, fprevkind, fnextkind, fprevprevkind, fnextnextkind; - int cd_clnors_offset, l_index; - short *clnors; - float *pnorm, norm[3]; - if (bp->offset == 0.0 || !bp->harden_normals) { return; } @@ -2302,7 +2265,7 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) /* I suspect this is not necessary. TODO: test that guess. */ BM_mesh_normals_update(bm); - cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); /* If there is not already a custom split normal layer then making one (with BM_lnorspace_update) * will not respect the autosmooth angle between smooth faces. To get that to happen, we have @@ -2321,19 +2284,25 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); } + BMIter fiter; + BMFace *f; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - fkind = get_face_kind(bp, f); + FKind fkind = get_face_kind(bp, f); if (fkind == F_ORIG || fkind == F_RECON) { continue; } + BMIter liter; + BMLoop *l; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - estep = l->prev->e; /* Causes CW walk around l->v fan. */ - lprev = BM_vert_step_fan_loop(l, &estep); + BMEdge *estep = l->prev->e; /* Causes CW walk around l->v fan. */ + BMLoop *lprev = BM_vert_step_fan_loop(l, &estep); estep = l->e; /* Causes CCW walk around l->v fan. */ - lnext = BM_vert_step_fan_loop(l, &estep); - fprevkind = lprev ? get_face_kind(bp, lprev->f) : F_NONE; - fnextkind = lnext ? get_face_kind(bp, lnext->f) : F_NONE; - pnorm = NULL; + BMLoop *lnext = BM_vert_step_fan_loop(l, &estep); + FKind fprevkind = lprev ? get_face_kind(bp, lprev->f) : F_NONE; + FKind fnextkind = lnext ? get_face_kind(bp, lnext->f) : F_NONE; + + float norm[3]; + float *pnorm = NULL; if (fkind == F_EDGE) { if (fprevkind == F_EDGE && BM_elem_flag_test(l, BM_ELEM_LONG_TAG)) { add_v3_v3v3(norm, f->no, lprev->f->no); @@ -2364,6 +2333,7 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) pnorm = lnext->f->no; } else { + BMLoop *lprevprev, *lnextnext; if (lprev) { estep = lprev->prev->e; lprevprev = BM_vert_step_fan_loop(lprev, &estep); @@ -2378,8 +2348,8 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) else { lnextnext = NULL; } - fprevprevkind = lprevprev ? get_face_kind(bp, lprevprev->f) : F_NONE; - fnextnextkind = lnextnext ? get_face_kind(bp, lnextnext->f) : F_NONE; + FKind fprevprevkind = lprevprev ? get_face_kind(bp, lprevprev->f) : F_NONE; + FKind fnextnextkind = lnextnext ? get_face_kind(bp, lnextnext->f) : F_NONE; if (fprevkind == F_EDGE && fprevprevkind == F_RECON) { pnorm = lprevprev->f->no; } @@ -2400,8 +2370,8 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) if (pnorm == norm) { normalize_v3(norm); } - l_index = BM_elem_index_get(l); - clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], pnorm, clnors); } } @@ -2410,12 +2380,7 @@ static void bevel_harden_normals(BevelParams *bp, BMesh *bm) static void bevel_set_weighted_normal_face_strength(BMesh *bm, BevelParams *bp) { - BMFace *f; - BMIter fiter; - FKind fkind; - int strength; - int mode = bp->face_strength_mode; - bool do_set_strength; + const int mode = bp->face_strength_mode; const char *wn_layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; int cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT32, wn_layer_id); @@ -2427,9 +2392,12 @@ static void bevel_set_weighted_normal_face_strength(BMesh *bm, BevelParams *bp) const int cd_prop_int_offset = CustomData_get_n_offset( &bm->pdata, CD_PROP_INT32, cd_prop_int_idx); + BMIter fiter; + BMFace *f; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - fkind = get_face_kind(bp, f); - do_set_strength = true; + FKind fkind = get_face_kind(bp, f); + bool do_set_strength = true; + int strength; switch (fkind) { case F_VERT: strength = FACE_STRENGTH_WEAK; @@ -2460,14 +2428,11 @@ static void bevel_set_weighted_normal_face_strength(BMesh *bm, BevelParams *bp) /* Set the any_seam property for a BevVert and all its BoundVerts. */ static void set_bound_vert_seams(BevVert *bv, bool mark_seam, bool mark_sharp) { - BoundVert *v; - EdgeHalf *e; - bv->any_seam = false; - v = bv->vmesh->boundstart; + BoundVert *v = bv->vmesh->boundstart; do { v->any_seam = false; - for (e = v->efirst; e; e = e->next) { + for (EdgeHalf *e = v->efirst; e; e = e->next) { v->any_seam |= e->is_seam; if (e == v->elast) { break; @@ -2486,14 +2451,12 @@ static void set_bound_vert_seams(BevVert *bv, bool mark_seam, bool mark_sharp) static int count_bound_vert_seams(BevVert *bv) { - int ans, i; - if (!bv->any_seam) { return 0; } - ans = 0; - for (i = 0; i < bv->edgecount; i++) { + int ans = 0; + for (int i = 0; i < bv->edgecount; i++) { if (bv->edges[i].is_seam) { ans++; } @@ -2504,10 +2467,8 @@ static int count_bound_vert_seams(BevVert *bv) /* Is e between two faces with a 180 degree angle between their normals? */ static bool eh_on_plane(EdgeHalf *e) { - float dot; - if (e->fprev && e->fnext) { - dot = dot_v3v3(e->fprev->no, e->fnext->no); + float dot = dot_v3v3(e->fprev->no, e->fnext->no); if (fabsf(dot + 1.0f) <= BEVEL_EPSILON_BIG || fabsf(dot - 1.0f) <= BEVEL_EPSILON_BIG) { return true; } @@ -2545,17 +2506,16 @@ static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm) static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool construct) { VMesh *vm = bv->vmesh; - EdgeHalf *efirst, *e; - BoundVert *v; - float co[3]; BLI_assert(bp->affect_type == BEVEL_AFFECT_VERTICES); - e = efirst = &bv->edges[0]; + EdgeHalf *efirst = &bv->edges[0]; + EdgeHalf *e = efirst; do { + float co[3]; slide_dist(e, bv->v, e->offset_l, co); if (construct) { - v = add_new_bound_vert(bp->mem_arena, vm, co); + BoundVert *v = add_new_bound_vert(bp->mem_arena, vm, co); v->efirst = v->elast = e; e->leftv = e->rightv = v; } @@ -2590,19 +2550,15 @@ static void build_boundary_terminal_edge(BevelParams *bp, { MemArena *mem_arena = bp->mem_arena; VMesh *vm = bv->vmesh; - BoundVert *bndv; - EdgeHalf *e; - const float *no; - float co[3], d; - bool use_tri_fan; - e = efirst; + EdgeHalf *e = efirst; + float co[3]; if (bv->edgecount == 2) { /* Only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge. */ - no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL); + const float *no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL); offset_in_plane(e, no, true, co); if (construct) { - bndv = add_new_bound_vert(mem_arena, vm, co); + BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = bndv->elast = bndv->ebev = e; e->leftv = bndv; } @@ -2612,7 +2568,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL); offset_in_plane(e, no, false, co); if (construct) { - bndv = add_new_bound_vert(mem_arena, vm, co); + BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = bndv->elast = e; e->rightv = bndv; } @@ -2622,7 +2578,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, /* Make artificial extra point along unbeveled edge, and form triangle. */ slide_dist(e->next, bv->v, e->offset_l, co); if (construct) { - bndv = add_new_bound_vert(mem_arena, vm, co); + BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = bndv->elast = e->next; e->next->leftv = e->next->rightv = bndv; set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp); @@ -2638,7 +2594,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, /* TODO: should do something else if angle between e and e->prev > 180 */ offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL); if (construct) { - bndv = add_new_bound_vert(mem_arena, vm, co); + BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = e->prev; bndv->elast = bndv->ebev = e; e->leftv = bndv; @@ -2650,7 +2606,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, e = e->next; offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL); if (construct) { - bndv = add_new_bound_vert(mem_arena, vm, co); + BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = e->prev; bndv->elast = e; e->leftv = e->rightv = bndv; @@ -2660,14 +2616,14 @@ static void build_boundary_terminal_edge(BevelParams *bp, adjust_bound_vert(e->leftv, co); } /* For the edges not adjacent to the beveled edge, slide the bevel amount along. */ - d = efirst->offset_l_spec; + float d = efirst->offset_l_spec; if (bp->profile_type == BEVEL_PROFILE_CUSTOM || bp->profile < 0.25f) { d *= sqrtf(2.0f); /* Need to go further along the edge to make room for full profile area. */ } for (e = e->next; e->next != efirst; e = e->next) { slide_dist(e, bv->v, d, co); if (construct) { - bndv = add_new_bound_vert(mem_arena, vm, co); + BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = bndv->elast = e; e->leftv = e->rightv = bndv; } @@ -2679,7 +2635,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, if (bv->edgecount >= 3) { /* Special case: snap profile to plane of adjacent two edges. */ - bndv = vm->boundstart; + BoundVert *bndv = vm->boundstart; BLI_assert(bndv->ebev != NULL); set_profile_params(bp, bv, bndv); move_profile_plane(bndv, bv->v); @@ -2692,10 +2648,10 @@ static void build_boundary_terminal_edge(BevelParams *bp, vm->mesh_kind = M_NONE; } else if (vm->count == 3) { - use_tri_fan = true; + bool use_tri_fan = true; if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Prevent overhanging edges: use M_POLY if the extra point is planar with the profile. */ - bndv = efirst->leftv; + BoundVert *bndv = efirst->leftv; float profile_plane[4]; plane_from_point_normal_v3(profile_plane, bndv->profile.plane_co, bndv->profile.plane_no); bndv = efirst->rightv->next; /* The added boundvert placed along the non-adjacent edge. */ @@ -2714,13 +2670,10 @@ static void build_boundary_terminal_edge(BevelParams *bp, /* Helper for build_boundary to handle special miters. */ static void adjust_miter_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) { - float co1[3], co2[3], co3[3], edge_dir[3], line_p[3]; - BoundVert *v1, *v2, *v3, *v1prev, *v3next; - BMVert *vother; - EdgeHalf *emiter_other; int miter_outer = bp->miter_outer; - v1 = emiter->rightv; + BoundVert *v1 = emiter->rightv; + BoundVert *v2, *v3; if (miter_outer == BEVEL_MITER_PATCH) { v2 = v1->next; v3 = v2->next; @@ -2730,8 +2683,9 @@ static void adjust_miter_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) v2 = NULL; v3 = v1->next; } - v1prev = v1->prev; - v3next = v3->next; + BoundVert *v1prev = v1->prev; + BoundVert *v3next = v3->next; + float co2[3]; copy_v3_v3(co2, v1->nv.co); if (v1->is_arc_start) { copy_v3_v3(v1->profile.middle, co2); @@ -2739,7 +2693,8 @@ static void adjust_miter_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) /* co1 is intersection of line through co2 in dir of emiter->e * and plane with normal the dir of emiter->e and through v1prev. */ - vother = BM_edge_other_vert(emiter->e, bv->v); + float co1[3], edge_dir[3], line_p[3]; + BMVert *vother = BM_edge_other_vert(emiter->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, vother->co); normalize_v3(edge_dir); float d = bp->offset / (bp->seg / 2.0f); /* A fallback amount to move. */ @@ -2750,7 +2705,8 @@ static void adjust_miter_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) adjust_bound_vert(v1, co1); /* co3 is similar, but plane is through v3next and line is other side of miter edge. */ - emiter_other = v3->elast; + float co3[3]; + EdgeHalf *emiter_other = v3->elast; vother = BM_edge_other_vert(emiter_other->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, vother->co); normalize_v3(edge_dir); @@ -2763,19 +2719,16 @@ static void adjust_miter_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter) { - BoundVert *v, *vstart, *v3; - EdgeHalf *e; - BMVert *vother; - float edge_dir[3], co[3]; - - v = vstart = bv->vmesh->boundstart; + BoundVert *vstart = bv->vmesh->boundstart; + BoundVert *v = vstart; do { if (v->is_arc_start) { - v3 = v->next; - e = v->efirst; + BoundVert *v3 = v->next; + EdgeHalf *e = v->efirst; if (e != emiter) { + float edge_dir[3], co[3]; copy_v3_v3(co, v->nv.co); - vother = BM_edge_other_vert(e->e, bv->v); + BMVert *vother = BM_edge_other_vert(e->e, bv->v); sub_v3_v3v3(edge_dir, vother->co, bv->v->co); normalize_v3(edge_dir); madd_v3_v3v3fl(v->nv.co, co, edge_dir, bp->spread); @@ -2810,12 +2763,6 @@ static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *em static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) { MemArena *mem_arena = bp->mem_arena; - EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon, *emiter; - BoundVert *v, *v1, *v2, *v3; - VMesh *vm; - float co[3], r; - int in_plane, not_in_plane, miter_outer, miter_inner; - int ang_kind; /* Current bevel does nothing if only one edge into a vertex. */ if (bv->edgecount <= 1) { @@ -2827,11 +2774,11 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) return; } - vm = bv->vmesh; + VMesh *vm = bv->vmesh; /* Find a beveled edge to be efirst. */ - e = efirst = next_bev(bv, NULL); - BLI_assert(e->is_bev); + EdgeHalf *efirst = next_bev(bv, NULL); + BLI_assert(efirst->is_bev); if (bv->selcount == 1) { /* Special case: only one beveled edge in. */ @@ -2840,26 +2787,29 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } /* Special miters outside only for 3 or more beveled edges. */ - miter_outer = (bv->selcount >= 3) ? bp->miter_outer : BEVEL_MITER_SHARP; - miter_inner = bp->miter_inner; + int miter_outer = (bv->selcount >= 3) ? bp->miter_outer : BEVEL_MITER_SHARP; + int miter_inner = bp->miter_inner; /* Keep track of the first beveled edge of an outside miter (there can be at most 1 per bv). */ - emiter = NULL; + EdgeHalf *emiter = NULL; /* There is more than one beveled edge. * We make BoundVerts to connect the sides of the beveled edges. * Non-beveled edges in between will just join to the appropriate juncture point. */ - e = efirst; + EdgeHalf *e = efirst; do { BLI_assert(e->is_bev); - eon = NULL; + EdgeHalf *eon = NULL; /* Make the BoundVert for the right side of e; the other side will be made when the beveled * edge to the left of e is handled. * Analyze edges until next beveled edge: They are either "in plane" (preceding and subsequent * faces are coplanar) or not. The "non-in-plane" edges affect the silhouette and we prefer to * slide along one of those if possible. */ - in_plane = not_in_plane = 0; /* Counts of in-plane / not-in-plane. */ - enip = eip = NULL; /* Representatives of each type. */ + int in_plane = 0; /* Counts of in-plane / not-in-plane. */ + int not_in_plane = 0; + EdgeHalf *enip = NULL; /* Representatives of each type. */ + EdgeHalf *eip = NULL; + EdgeHalf *e2; for (e2 = e->next; !e2->is_bev; e2 = e2->next) { if (eh_on_plane(e2)) { in_plane++; @@ -2871,6 +2821,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } } + float r, co[3]; if (in_plane == 0 && not_in_plane == 0) { offset_meet(e, e2, bv->v, e->fnext, false, co, NULL); } @@ -2897,7 +2848,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } if (construct) { - v = add_new_bound_vert(mem_arena, vm, co); + BoundVert *v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e; v->elast = e2; v->ebev = e2; @@ -2907,10 +2858,10 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } e->rightv = v; e2->leftv = v; - for (e3 = e->next; e3 != e2; e3 = e3->next) { + for (EdgeHalf *e3 = e->next; e3 != e2; e3 = e3->next) { e3->leftv = e3->rightv = v; } - ang_kind = edges_angle_kind(e, e2, bv->v); + int ang_kind = edges_angle_kind(e, e2, bv->v); /* Are we doing special mitering? * There can only be one outer reflex angle, so only one outer miter, @@ -2922,15 +2873,16 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) emiter = e; } /* Make one or two more boundverts; for now all will have same co. */ - v1 = v; + BoundVert *v1 = v; v1->ebev = NULL; + BoundVert *v2; if (ang_kind == ANGLE_LARGER && miter_outer == BEVEL_MITER_PATCH) { v2 = add_new_bound_vert(mem_arena, vm, co); } else { v2 = NULL; } - v3 = add_new_bound_vert(mem_arena, vm, co); + BoundVert *v3 = add_new_bound_vert(mem_arena, vm, co); v3->ebev = e2; v3->efirst = e2; v3->elast = e2; @@ -2950,7 +2902,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } else { v2->efirst = e->next; - for (e3 = e->next; e3 != e2; e3 = e3->next) { + for (EdgeHalf *e3 = e->next; e3 != e2; e3 = e3->next) { e3->leftv = e3->rightv = v2; v2->elast = e3; } @@ -2969,7 +2921,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) int i = 0; /* Put first half of in-between edges at index 0, second half at index bp->seg. * If between is odd, put middle one at mid-index. */ - for (e3 = e->next; e3 != e2; e3 = e3->next) { + for (EdgeHalf *e3 = e->next; e3 != e2; e3 = e3->next) { v1->elast = e3; if (i < bet2) { e3->profile_index = 0; @@ -2987,13 +2939,15 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } } else { /* construct == false. */ - ang_kind = edges_angle_kind(e, e2, bv->v); + int ang_kind = edges_angle_kind(e, e2, bv->v); if ((miter_outer != BEVEL_MITER_SHARP && !emiter && ang_kind == ANGLE_LARGER) || (miter_inner != BEVEL_MITER_SHARP && ang_kind == ANGLE_SMALLER)) { if (ang_kind == ANGLE_LARGER) { emiter = e; } - v1 = e->rightv; + BoundVert *v1 = e->rightv; + BoundVert *v2; + BoundVert *v3; if (ang_kind == ANGLE_LARGER && miter_outer == BEVEL_MITER_PATCH) { v2 = v1->next; v3 = v2->next; @@ -3047,28 +3001,21 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) #ifdef DEBUG_ADJUST static void print_adjust_stats(BoundVert *vstart) { - BoundVert *v; - EdgeHalf *eleft, *eright; - double even_residual2, spec_residual2; - double max_even_r, max_even_r_pct; - double max_spec_r, max_spec_r_pct; - double delta, delta_pct; - printf("\nSolution analysis\n"); - even_residual2 = 0.0; - spec_residual2 = 0.0; - max_even_r = 0.0; - max_even_r_pct = 0.0; - max_spec_r = 0.0; - max_spec_r_pct = 0.0; + double even_residual2 = 0.0; + double spec_residual2 = 0.0; + double max_even_r = 0.0; + double max_even_r_pct = 0.0; + double max_spec_r = 0.0; + double max_spec_r_pct = 0.0; printf("width matching\n"); - v = vstart; + BoundVert *v = vstart; do { if (v->adjchain != NULL) { - eright = v->efirst; - eleft = v->adjchain->elast; - delta = fabs(eright->offset_r - eleft->offset_l); - delta_pct = 100.0 * delta / eright->offset_r_spec; + EdgeHalf *eright = v->efirst; + EdgeHalf *eleft = v->adjchain->elast; + double delta = fabs(eright->offset_r - eleft->offset_l); + double delta_pct = 100.0 * delta / eright->offset_r_spec; printf("e%d r(%f) vs l(%f): abs(delta)=%f, delta_pct=%f\n", BM_elem_index_get(eright->e), eright->offset_r, @@ -3090,10 +3037,10 @@ static void print_adjust_stats(BoundVert *vstart) v = vstart; do { if (v->adjchain != NULL) { - eright = v->efirst; - eleft = v->adjchain->elast; - delta = eright->offset_r - eright->offset_r_spec; - delta_pct = 100.0 * delta / eright->offset_r_spec; + EdgeHalf *eright = v->efirst; + EdgeHalf *eleft = v->adjchain->elast; + double delta = eright->offset_r - eright->offset_r_spec; + double delta_pct = 100.0 * delta / eright->offset_r_spec; printf("e%d r(%f) vs r spec(%f): delta=%f, delta_pct=%f\n", BM_elem_index_get(eright->e), eright->offset_r, @@ -3149,19 +3096,12 @@ static void print_adjust_stats(BoundVert *vstart) * But keep it here for a while in case performance issues demand that it be used sometimes. */ static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscycle) { - BoundVert *v; - EdgeHalf *eleft, *eright; - float *g; - float *g_prod; - float gprod, gprod_sum, spec_sum, p; - int i; - - g = MEM_mallocN(np * sizeof(float), "beveladjust"); - g_prod = MEM_mallocN(np * sizeof(float), "beveladjust"); + float *g = MEM_mallocN(np * sizeof(float), "beveladjust"); + float *g_prod = MEM_mallocN(np * sizeof(float), "beveladjust"); - v = vstart; - spec_sum = 0.0f; - i = 0; + BoundVert *v = vstart; + float spec_sum = 0.0f; + int i = 0; do { g[i] = v->sinratio; if (iscycle || v->adjchain != NULL) { @@ -3174,8 +3114,8 @@ static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscyc v = v->adjchain; } while (v && v != vstart); - gprod = 1.00f; - gprod_sum = 1.0f; + float gprod = 1.00f; + float gprod_sum = 1.0f; for (i = np - 1; i > 0; i--) { gprod *= g[i]; g_prod[i] = gprod; @@ -3196,15 +3136,15 @@ static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscyc MEM_freeN(g_prod); return false; } - p = spec_sum / gprod_sum; + float p = spec_sum / gprod_sum; /* Apply the new offsets. */ v = vstart; i = 0; do { if (iscycle || v->adjchain != NULL) { - eright = v->efirst; - eleft = v->elast; + EdgeHalf *eright = v->efirst; + EdgeHalf *eleft = v->elast; eright->offset_r = g_prod[(i + 1) % np] * p; if (iscycle || v != vstart) { eleft->offset_l = v->sinratio * eright->offset_r; @@ -3212,7 +3152,7 @@ static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscyc } else { /* Not a cycle, and last of chain. */ - eleft = v->elast; + EdgeHalf *eleft = v->elast; eleft->offset_l = p; } i++; @@ -3242,80 +3182,77 @@ static EdgeHalf *next_edgehalf_bev(BevelParams *bp, bool toward_bv, BevVert **r_bv) { - EdgeHalf *new_edge; - EdgeHalf *next_edge = NULL; - float dir_start_edge[3], dir_new_edge[3]; - float second_best_dot = 0.0f, best_dot = 0.0f; - float new_dot; + /* Case 1: The next EdgeHalf is the other side of the BMEdge. + * It's part of the same BMEdge, so we know the other EdgeHalf is also beveled. */ + if (!toward_bv) { + return find_other_end_edge_half(bp, start_edge, r_bv); + } - /* Case 1: The next EdgeHalf is across a BevVert from the current EdgeHalf. */ - if (toward_bv) { - /* Skip all the logic if there's only one beveled edge at the vertex, we're at an end. */ - if ((*r_bv)->selcount == 1) { - return NULL; /* No other edges to go to. */ - } + /* Case 2: The next EdgeHalf is across a BevVert from the current EdgeHalf. */ + /* Skip all the logic if there's only one beveled edge at the vertex, we're at an end. */ + if ((*r_bv)->selcount == 1) { + return NULL; /* No other edges to go to. */ + } - /* The case with only one other edge connected to the vertex is special too. */ - if ((*r_bv)->selcount == 2) { - /* Just find the next beveled edge, that's the only other option. */ - new_edge = start_edge; - do { - new_edge = new_edge->next; - } while (!new_edge->is_bev); + /* The case with only one other edge connected to the vertex is special too. */ + if ((*r_bv)->selcount == 2) { + /* Just find the next beveled edge, that's the only other option. */ + EdgeHalf *new_edge = start_edge; + do { + new_edge = new_edge->next; + } while (!new_edge->is_bev); - return new_edge; - } + return new_edge; + } - /* Find the direction vector of the current edge (pointing INTO the BevVert). - * v1 and v2 don't necessarily have an order, so we need to check which is closer to bv. */ - if (start_edge->e->v1 == (*r_bv)->v) { - sub_v3_v3v3(dir_start_edge, start_edge->e->v1->co, start_edge->e->v2->co); + /* Find the direction vector of the current edge (pointing INTO the BevVert). + * v1 and v2 don't necessarily have an order, so we need to check which is closer to bv. */ + float dir_start_edge[3]; + if (start_edge->e->v1 == (*r_bv)->v) { + sub_v3_v3v3(dir_start_edge, start_edge->e->v1->co, start_edge->e->v2->co); + } + else { + sub_v3_v3v3(dir_start_edge, start_edge->e->v2->co, start_edge->e->v1->co); + } + normalize_v3(dir_start_edge); + + /* Find the beveled edge coming out of the BevVert that's most parallel to the current edge. */ + EdgeHalf *new_edge = start_edge->next; + float second_best_dot = 0.0f, best_dot = 0.0f; + EdgeHalf *next_edge = NULL; + while (new_edge != start_edge) { + if (!new_edge->is_bev) { + new_edge = new_edge->next; + continue; + } + /* Find direction vector of the possible next edge (pointing OUT of the BevVert). */ + float dir_new_edge[3]; + if (new_edge->e->v2 == (*r_bv)->v) { + sub_v3_v3v3(dir_new_edge, new_edge->e->v1->co, new_edge->e->v2->co); } else { - sub_v3_v3v3(dir_start_edge, start_edge->e->v2->co, start_edge->e->v1->co); + sub_v3_v3v3(dir_new_edge, new_edge->e->v2->co, new_edge->e->v1->co); } - normalize_v3(dir_start_edge); - - /* Find the beveled edge coming out of the BevVert that's most parallel to the current edge. */ - new_edge = start_edge->next; - while (new_edge != start_edge) { - if (!new_edge->is_bev) { - new_edge = new_edge->next; - continue; - } - /* Find direction vector of the possible next edge (pointing OUT of the BevVert). */ - if (new_edge->e->v2 == (*r_bv)->v) { - sub_v3_v3v3(dir_new_edge, new_edge->e->v1->co, new_edge->e->v2->co); - } - else { - sub_v3_v3v3(dir_new_edge, new_edge->e->v2->co, new_edge->e->v1->co); - } - normalize_v3(dir_new_edge); + normalize_v3(dir_new_edge); - /* Use this edge if it is the most parallel to the orignial so far. */ - new_dot = dot_v3v3(dir_new_edge, dir_start_edge); - if (new_dot > best_dot) { - second_best_dot = best_dot; /* For remembering if the choice was too close. */ - best_dot = new_dot; - next_edge = new_edge; - } - else if (new_dot > second_best_dot) { - second_best_dot = new_dot; - } - - new_edge = new_edge->next; + /* Use this edge if it is the most parallel to the orignial so far. */ + float new_dot = dot_v3v3(dir_new_edge, dir_start_edge); + if (new_dot > best_dot) { + second_best_dot = best_dot; /* For remembering if the choice was too close. */ + best_dot = new_dot; + next_edge = new_edge; } - - /* Only return a new Edge if one was found and if the choice of next edge was not too close. */ - if ((next_edge != NULL) && compare_ff(best_dot, second_best_dot, BEVEL_SMALL_ANG_DOT)) { - return NULL; + else if (new_dot > second_best_dot) { + second_best_dot = new_dot; } - return next_edge; + + new_edge = new_edge->next; } - /* Case 2: The next EdgeHalf is the other side of the BMEdge. - * It's part of the same BMEdge, so we know the other EdgeHalf is also beveled. */ - next_edge = find_other_end_edge_half(bp, start_edge, r_bv); + /* Only return a new Edge if one was found and if the choice of next edge was not too close. */ + if ((next_edge != NULL) && compare_ff(best_dot, second_best_dot, BEVEL_SMALL_ANG_DOT)) { + return NULL; + } return next_edge; } @@ -3340,13 +3277,10 @@ static void regularize_profile_orientation(BevelParams *bp, BMEdge *bme) start_edgehalf->visited_rpo = true; /* First loop starts in the away from BevVert direction and the second starts toward it. */ - bool toward_bv; - BevVert *bv; - EdgeHalf *edgehalf; for (int i = 0; i < 2; i++) { - edgehalf = start_edgehalf; - bv = start_bv; - toward_bv = (i == 0); + EdgeHalf *edgehalf = start_edgehalf; + BevVert *bv = start_bv; + bool toward_bv = (i == 0); edgehalf = next_edgehalf_bev(bp, edgehalf, toward_bv, &bv); /* Keep traveling until there is no unvisited beveled edgehalf to visit next. */ @@ -3381,17 +3315,11 @@ static void regularize_profile_orientation(BevelParams *bp, BMEdge *bme) */ static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) { - BoundVert *v; - EdgeHalf *eleft, *eright, *enextleft; - LinearSolver *solver; - double weight, val; - int i, np, nrows, row; - - np = 0; + int np = 0; #ifdef DEBUG_ADJUST printf("\nadjust the %s (with eigen)\n", iscycle ? "cycle" : "chain"); #endif - v = vstart; + BoundVert *v = vstart; do { #ifdef DEBUG_ADJUST eleft = v->elast; @@ -3411,13 +3339,15 @@ static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) } #endif - nrows = iscycle ? 3 * np : 3 * np - 3; + int nrows = iscycle ? 3 * np : 3 * np - 3; - solver = EIG_linear_least_squares_solver_new(nrows, np, 1); + LinearSolver *solver = EIG_linear_least_squares_solver_new(nrows, np, 1); v = vstart; - i = 0; - weight = BEVEL_MATCH_SPEC_WEIGHT; /* Sqrt of factor to weight down importance of spec match. */ + int i = 0; + /* Sqrt of factor to weight down importance of spec match. */ + double weight = BEVEL_MATCH_SPEC_WEIGHT; + EdgeHalf *eleft, *eright, *enextleft; do { /* Except at end of chain, v's indep variable is offset_r of v->efirst. */ if (iscycle || i < np - 1) { @@ -3448,7 +3378,7 @@ static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) /* Residue np + 2*i (if cycle) else np - 1 + 2*i: * right offset for parm i matches its spec; weighted. */ - row = iscycle ? np + 2 * i : np - 1 + 2 * i; + int row = iscycle ? np + 2 * i : np - 1 + 2 * i; EIG_linear_solver_matrix_add(solver, row, i, weight); EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eright->offset_r); #ifdef DEBUG_ADJUST @@ -3499,7 +3429,7 @@ static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) v = vstart; i = 0; do { - val = EIG_linear_solver_variable_get(solver, 0, i); + double val = EIG_linear_solver_variable_get(solver, 0, i); if (iscycle || i < np - 1) { eright = v->efirst; eleft = v->elast; @@ -3547,25 +3477,20 @@ static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) */ static void adjust_offsets(BevelParams *bp, BMesh *bm) { - BMVert *bmv; - BevVert *bv, *bvcur; - BoundVert *v, *vanchor, *vchainstart, *vchainend, *vnext; - EdgeHalf *enext; - BMIter iter; - bool iscycle; - int chainlen; - /* Find and process chains and cycles of unvisited BoundVerts that have eon set. */ /* Note: for repeatability, iterate over all verts of mesh rather than over ghash'ed BMVerts. */ + BMIter iter; + BMVert *bmv; BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(bmv, BM_ELEM_TAG)) { continue; } - bv = bvcur = find_bevvert(bp, bmv); + BevVert *bv = find_bevvert(bp, bmv); + BevVert *bvcur = bv; if (!bv) { continue; } - vanchor = bv->vmesh->boundstart; + BoundVert *vanchor = bv->vmesh->boundstart; do { if (vanchor->visited || !vanchor->eon) { continue; @@ -3582,20 +3507,22 @@ static void adjust_offsets(BevelParams *bp, BMesh *bm) * pairs with the right side of the next edge in the cycle or chain. */ /* First follow paired edges in left->right direction. */ + BoundVert *v, *vchainstart, *vchainend; v = vchainstart = vchainend = vanchor; - iscycle = false; - chainlen = 1; + + bool iscycle = false; + int chainlen = 1; while (v->eon && !v->visited && !iscycle) { v->visited = true; if (!v->efirst) { break; } - enext = find_other_end_edge_half(bp, v->efirst, &bvcur); + EdgeHalf *enext = find_other_end_edge_half(bp, v->efirst, &bvcur); if (!enext) { break; } BLI_assert(enext != NULL); - vnext = enext->leftv; + BoundVert *vnext = enext->leftv; v->adjchain = vnext; vchainend = vnext; chainlen++; @@ -3618,11 +3545,11 @@ static void adjust_offsets(BevelParams *bp, BMesh *bm) if (!v->elast) { break; } - enext = find_other_end_edge_half(bp, v->elast, &bvcur); + EdgeHalf *enext = find_other_end_edge_half(bp, v->elast, &bvcur); if (!enext) { break; } - vnext = enext->rightv; + BoundVert *vnext = enext->rightv; vnext->adjchain = v; chainlen++; vchainstart = vnext; @@ -3638,7 +3565,7 @@ static void adjust_offsets(BevelParams *bp, BMesh *bm) /* Rebuild boundaries with new width specs. */ BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(bmv, BM_ELEM_TAG)) { - bv = find_bevvert(bp, bmv); + BevVert *bv = find_bevvert(bp, bmv); if (bv) { build_boundary(bp, bv, false); } @@ -3657,22 +3584,18 @@ static void adjust_offsets(BevelParams *bp, BMesh *bm) */ static BoundVert *pipe_test(BevVert *bv) { - EdgeHalf *e, *epipe; - VMesh *vm; - BoundVert *v1, *v2, *v3; - float dir1[3], dir3[3]; - - vm = bv->vmesh; + VMesh *vm = bv->vmesh; if (vm->count < 3 || vm->count > 4 || bv->selcount < 3 || bv->selcount > 4) { return NULL; } /* Find v1, v2, v3 all with beveled edges, where v1 and v3 have collinear edges. */ - epipe = NULL; - v1 = vm->boundstart; + EdgeHalf *epipe = NULL; + BoundVert *v1 = vm->boundstart; + float dir1[3], dir3[3]; do { - v2 = v1->next; - v3 = v2->next; + BoundVert *v2 = v1->next; + BoundVert *v3 = v2->next; if (v1->ebev && v2->ebev && v3->ebev) { sub_v3_v3v3(dir1, bv->v->co, BM_edge_other_vert(v1->ebev->e, bv->v)->co); sub_v3_v3v3(dir3, BM_edge_other_vert(v3->ebev->e, bv->v)->co, bv->v->co); @@ -3690,7 +3613,7 @@ static BoundVert *pipe_test(BevVert *bv) } /* Check face planes: all should have normals perpendicular to epipe. */ - for (e = &bv->edges[0]; e != &bv->edges[bv->edgecount]; e++) { + for (EdgeHalf *e = &bv->edges[0]; e != &bv->edges[bv->edgecount]; e++) { if (e->fnext) { if (fabsf(dot_v3v3(dir1, e->fnext->no)) > BEVEL_EPSILON_BIG) { return NULL; @@ -3702,14 +3625,12 @@ static BoundVert *pipe_test(BevVert *bv) static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert *bounds) { - VMesh *vm; - - vm = (VMesh *)BLI_memarena_alloc(mem_arena, sizeof(VMesh)); + VMesh *vm = (VMesh *)BLI_memarena_alloc(mem_arena, sizeof(VMesh)); vm->count = count; vm->seg = seg; vm->boundstart = bounds; - vm->mesh = (NewVert *)BLI_memarena_alloc( - mem_arena, (size_t)(count * (1 + seg / 2) * (1 + seg)) * sizeof(NewVert)); + vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena, + sizeof(NewVert) * count * (1 + seg / 2) * (1 + seg)); vm->mesh_kind = M_ADJ; return vm; } @@ -3726,28 +3647,22 @@ static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert * */ static NewVert *mesh_vert_canon(VMesh *vm, int i, int j, int k) { - int n, ns, ns2, odd; - NewVert *ans; - - n = vm->count; - ns = vm->seg; - ns2 = ns / 2; - odd = ns % 2; + int n = vm->count; + int ns = vm->seg; + int ns2 = ns / 2; + int odd = ns % 2; BLI_assert(0 <= i && i <= n && 0 <= j && j <= ns && 0 <= k && k <= ns); if (!odd && j == ns2 && k == ns2) { - ans = mesh_vert(vm, 0, j, k); + return mesh_vert(vm, 0, j, k); } - else if (j <= ns2 - 1 + odd && k <= ns2) { - ans = mesh_vert(vm, i, j, k); + if (j <= ns2 - 1 + odd && k <= ns2) { + return mesh_vert(vm, i, j, k); } - else if (k <= ns2) { - ans = mesh_vert(vm, (i + n - 1) % n, k, ns - j); + if (k <= ns2) { + return mesh_vert(vm, (i + n - 1) % n, k, ns - j); } - else { - ans = mesh_vert(vm, (i + 1) % n, ns - k, j); - } - return ans; + return mesh_vert(vm, (i + 1) % n, ns - k, j); } static bool is_canon(VMesh *vm, int i, int j, int k) @@ -3763,20 +3678,17 @@ static bool is_canon(VMesh *vm, int i, int j, int k) /* Copy the vertex data to all of vm verts from canonical ones. */ static void vmesh_copy_equiv_verts(VMesh *vm) { - int n, ns, ns2, i, j, k; - NewVert *v0, *v1; - - n = vm->count; - ns = vm->seg; - ns2 = ns / 2; - for (i = 0; i < n; i++) { - for (j = 0; j <= ns2; j++) { - for (k = 0; k <= ns; k++) { + int n = vm->count; + int ns = vm->seg; + int ns2 = ns / 2; + for (int i = 0; i < n; i++) { + for (int j = 0; j <= ns2; j++) { + for (int k = 0; k <= ns; k++) { if (is_canon(vm, i, j, k)) { continue; } - v1 = mesh_vert(vm, i, j, k); - v0 = mesh_vert_canon(vm, i, j, k); + NewVert *v1 = mesh_vert(vm, i, j, k); + NewVert *v0 = mesh_vert_canon(vm, i, j, k); copy_v3_v3(v1->co, v0->co); v1->v = v0->v; } @@ -3787,13 +3699,11 @@ static void vmesh_copy_equiv_verts(VMesh *vm) /* Calculate and return in r_cent the centroid of the center poly. */ static void vmesh_center(VMesh *vm, float r_cent[3]) { - int n, ns2, i; - - n = vm->count; - ns2 = vm->seg / 2; + int n = vm->count; + int ns2 = vm->seg / 2; if (vm->seg % 2) { zero_v3(r_cent); - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { add_v3_v3(r_cent, mesh_vert(vm, i, ns2, ns2)->co); } mul_v3_fl(r_cent, 1.0f / (float)n); @@ -3815,53 +3725,47 @@ static void avg4( /* Gamma needed for smooth Catmull-Clark, Sabin modification. */ static float sabin_gamma(int n) { - double ans, k, k2, k4, k6, x, y; - /* pPrecalculated for common cases of n. */ if (n < 3) { return 0.0f; } if (n == 3) { - ans = 0.065247584f; - } - else if (n == 4) { - ans = 0.25f; - } - else if (n == 5) { - ans = 0.401983447f; - } - else if (n == 6) { - ans = 0.523423277f; - } - else { - k = cos(M_PI / (double)n); - /* Need x, real root of x^3 + (4k^2 - 3)x - 2k = 0. - * Answer calculated via Wolfram Alpha. */ - k2 = k * k; - k4 = k2 * k2; - k6 = k4 * k2; - y = pow(M_SQRT3 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k, 1.0 / 3.0); - x = 0.480749856769136 * y - (0.231120424783545 * (12.0 * k2 - 9.0)) / y; - ans = (k * x + 2.0 * k2 - 1.0) / (x * x * (k * x + 1.0)); - } - return (float)ans; + return 0.065247584f; + } + if (n == 4) { + return 0.25f; + } + if (n == 5) { + return 0.401983447f; + } + if (n == 6) { + return 0.523423277f; + } + double k = cos(M_PI / (double)n); + /* Need x, real root of x^3 + (4k^2 - 3)x - 2k = 0. + * Answer calculated via Wolfram Alpha. */ + double k2 = k * k; + double k4 = k2 * k2; + double k6 = k4 * k2; + double y = pow(M_SQRT3 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k, 1.0 / 3.0); + double x = 0.480749856769136 * y - (0.231120424783545 * (12.0 * k2 - 9.0)) / y; + return (k * x + 2.0 * k2 - 1.0) / (x * x * (k * x + 1.0)); } /* Fill frac with fractions of the way along ring 0 for vertex i, for use with interp_range * function. */ static void fill_vmesh_fracs(VMesh *vm, float *frac, int i) { - int k, ns; float total = 0.0f; - ns = vm->seg; + int ns = vm->seg; frac[0] = 0.0f; - for (k = 0; k < ns; k++) { + for (int k = 0; k < ns; k++) { total += len_v3v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm, i, 0, k + 1)->co); frac[k + 1] = total; } if (total > 0.0f) { - for (k = 1; k <= ns; k++) { + for (int k = 1; k <= ns; k++) { frac[k] /= total; } } @@ -3873,20 +3777,19 @@ static void fill_vmesh_fracs(VMesh *vm, float *frac, int i) /* Like fill_vmesh_fracs but want fractions for profile points of bndv, with ns segments. */ static void fill_profile_fracs(BevelParams *bp, BoundVert *bndv, float *frac, int ns) { - int k; float co[3], nextco[3]; float total = 0.0f; frac[0] = 0.0f; copy_v3_v3(co, bndv->nv.co); - for (k = 0; k < ns; k++) { + for (int k = 0; k < ns; k++) { get_profile_point(bp, &bndv->profile, k + 1, ns, nextco); total += len_v3v3(co, nextco); frac[k + 1] = total; copy_v3_v3(co, nextco); } if (total > 0.0f) { - for (k = 1; k <= ns; k++) { + for (int k = 1; k <= ns; k++) { frac[k] /= total; } } @@ -3899,13 +3802,10 @@ static void fill_profile_fracs(BevelParams *bp, BoundVert *bndv, float *frac, in * and put fraction of rest of way between frac[i] and frac[i + 1] into r_rest. */ static int interp_range(const float *frac, int n, const float f, float *r_rest) { - int i; - float rest; - /* Could binary search in frac, but expect n to be reasonably small. */ - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { if (f <= frac[i + 1]) { - rest = f - frac[i]; + float rest = f - frac[i]; if (rest == 0) { *r_rest = 0.0f; } @@ -3929,39 +3829,34 @@ static int interp_range(const float *frac, int n, const float f, float *r_rest) * neighbors. */ static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm_in, int nseg) { - int n_bndv, ns_in, nseg2, odd, i, j, k, j_in, k_in, k_in_prev, j0inc, k0inc; - float *prev_frac, *frac, *new_frac, *prev_new_frac; - float fraction, restj, restk, restkprev; - float quad[4][3], co[3], center[3]; - VMesh *vm_out; - BoundVert *bndv; - - n_bndv = vm_in->count; - ns_in = vm_in->seg; - nseg2 = nseg / 2; - odd = nseg % 2; - vm_out = new_adj_vmesh(bp->mem_arena, n_bndv, nseg, vm_in->boundstart); - - prev_frac = BLI_array_alloca(prev_frac, (ns_in + 1)); - frac = BLI_array_alloca(frac, (ns_in + 1)); - new_frac = BLI_array_alloca(new_frac, (nseg + 1)); - prev_new_frac = BLI_array_alloca(prev_new_frac, (nseg + 1)); + int n_bndv = vm_in->count; + int ns_in = vm_in->seg; + int nseg2 = nseg / 2; + int odd = nseg % 2; + VMesh *vm_out = new_adj_vmesh(bp->mem_arena, n_bndv, nseg, vm_in->boundstart); + + float *prev_frac = BLI_array_alloca(prev_frac, (ns_in + 1)); + float *frac = BLI_array_alloca(frac, (ns_in + 1)); + float *new_frac = BLI_array_alloca(new_frac, (nseg + 1)); + float *prev_new_frac = BLI_array_alloca(prev_new_frac, (nseg + 1)); fill_vmesh_fracs(vm_in, prev_frac, n_bndv - 1); - bndv = vm_in->boundstart; + BoundVert *bndv = vm_in->boundstart; fill_profile_fracs(bp, bndv->prev, prev_new_frac, nseg); - for (i = 0; i < n_bndv; i++) { + for (int i = 0; i < n_bndv; i++) { fill_vmesh_fracs(vm_in, frac, i); fill_profile_fracs(bp, bndv, new_frac, nseg); - for (j = 0; j <= nseg2 - 1 + odd; j++) { - for (k = 0; k <= nseg2; k++) { + for (int j = 0; j <= nseg2 - 1 + odd; j++) { + for (int k = 0; k <= nseg2; k++) { /* Finding the locations where "fraction" fits into previous and current "frac". */ - fraction = new_frac[k]; - k_in = interp_range(frac, ns_in, fraction, &restk); + float fraction = new_frac[k]; + float restk; + float restkprev; + int k_in = interp_range(frac, ns_in, fraction, &restk); fraction = prev_new_frac[nseg - j]; - k_in_prev = interp_range(prev_frac, ns_in, fraction, &restkprev); - j_in = ns_in - k_in_prev; - restj = -restkprev; + int k_in_prev = interp_range(prev_frac, ns_in, fraction, &restkprev); + int j_in = ns_in - k_in_prev; + float restj = -restkprev; if (restj > -BEVEL_EPSILON) { restj = 0.0f; } @@ -3970,12 +3865,14 @@ static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm_in, int nseg) restj = 1.0f + restj; } /* Use bilinear interpolation within the source quad; could be smarter here. */ + float co[3]; if (restj < BEVEL_EPSILON && restk < BEVEL_EPSILON) { copy_v3_v3(co, mesh_vert_canon(vm_in, i, j_in, k_in)->co); } else { - j0inc = (restj < BEVEL_EPSILON || j_in == ns_in) ? 0 : 1; - k0inc = (restk < BEVEL_EPSILON || k_in == ns_in) ? 0 : 1; + int j0inc = (restj < BEVEL_EPSILON || j_in == ns_in) ? 0 : 1; + int k0inc = (restk < BEVEL_EPSILON || k_in == ns_in) ? 0 : 1; + float quad[4][3]; copy_v3_v3(quad[0], mesh_vert_canon(vm_in, i, j_in, k_in)->co); copy_v3_v3(quad[1], mesh_vert_canon(vm_in, i, j_in, k_in + k0inc)->co); copy_v3_v3(quad[2], mesh_vert_canon(vm_in, i, j_in + j0inc, k_in + k0inc)->co); @@ -3986,10 +3883,11 @@ static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm_in, int nseg) } } bndv = bndv->next; - memcpy(prev_frac, frac, (size_t)(ns_in + 1) * sizeof(float)); - memcpy(prev_new_frac, new_frac, (size_t)(nseg + 1) * sizeof(float)); + memcpy(prev_frac, frac, sizeof(float) * (ns_in + 1)); + memcpy(prev_new_frac, new_frac, sizeof(float) * (nseg + 1)); } if (!odd) { + float center[3]; vmesh_center(vm_in, center); copy_v3_v3(mesh_vert(vm_out, 0, nseg2, nseg2)->co, center); } @@ -4003,28 +3901,24 @@ static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm_in, int nseg) * See Levin 1999 paper: "Filling an N-sided hole using combined subdivision schemes". */ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) { - int n_boundary, ns_in, ns_in2, ns_out; - int i, j, k, inext; - float co[3], co1[3], co2[3], acc[3]; - float beta, gamma; - VMesh *vm_out; - BoundVert *bndv; - - n_boundary = vm_in->count; - ns_in = vm_in->seg; - ns_in2 = ns_in / 2; + float co[3]; + + int n_boundary = vm_in->count; + int ns_in = vm_in->seg; + int ns_in2 = ns_in / 2; BLI_assert(ns_in % 2 == 0); - ns_out = 2 * ns_in; - vm_out = new_adj_vmesh(bp->mem_arena, n_boundary, ns_out, vm_in->boundstart); + int ns_out = 2 * ns_in; + VMesh *vm_out = new_adj_vmesh(bp->mem_arena, n_boundary, ns_out, vm_in->boundstart); /* First we adjust the boundary vertices of the input mesh, storing in output mesh. */ - for (i = 0; i < n_boundary; i++) { + for (int i = 0; i < n_boundary; i++) { copy_v3_v3(mesh_vert(vm_out, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 0)->co); - for (k = 1; k < ns_in; k++) { + for (int k = 1; k < ns_in; k++) { copy_v3_v3(co, mesh_vert(vm_in, i, 0, k)->co); /* Smooth boundary rule. Custom profiles shouldn't be smoothed. */ if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { + float co1[3], co2[3], acc[3]; copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co); copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co); @@ -4037,13 +3931,14 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) } } /* Now adjust odd boundary vertices in output mesh, based on even ones. */ - bndv = vm_out->boundstart; - for (i = 0; i < n_boundary; i++) { - for (k = 1; k < ns_out; k += 2) { + BoundVert *bndv = vm_out->boundstart; + for (int i = 0; i < n_boundary; i++) { + for (int k = 1; k < ns_out; k += 2) { get_profile_point(bp, &bndv->profile, k, ns_out, co); /* Smooth if using a non-custom profile. */ if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { + float co1[3], co2[3], acc[3]; copy_v3_v3(co1, mesh_vert_canon(vm_out, i, 0, k - 1)->co); copy_v3_v3(co2, mesh_vert_canon(vm_out, i, 0, k + 1)->co); @@ -4059,8 +3954,8 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) vmesh_copy_equiv_verts(vm_out); /* Copy adjusted verts back into vm_in. */ - for (i = 0; i < n_boundary; i++) { - for (k = 0; k < ns_in; k++) { + for (int i = 0; i < n_boundary; i++) { + for (int k = 0; k < ns_in; k++) { copy_v3_v3(mesh_vert(vm_in, i, 0, k)->co, mesh_vert(vm_out, i, 0, 2 * k)->co); } } @@ -4071,9 +3966,9 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) * and assuming all boundary vertices have valence 4. */ /* The new face vertices. */ - for (i = 0; i < n_boundary; i++) { - for (j = 0; j < ns_in2; j++) { - for (k = 0; k < ns_in2; k++) { + for (int i = 0; i < n_boundary; i++) { + for (int j = 0; j < ns_in2; j++) { + for (int k = 0; k < ns_in2; k++) { /* Face up and right from (j, k). */ avg4(co, mesh_vert(vm_in, i, j, k), @@ -4086,9 +3981,9 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) } /* The new vertical edge vertices. */ - for (i = 0; i < n_boundary; i++) { - for (j = 0; j < ns_in2; j++) { - for (k = 1; k <= ns_in2; k++) { + for (int i = 0; i < n_boundary; i++) { + for (int j = 0; j < ns_in2; j++) { + for (int k = 1; k <= ns_in2; k++) { /* Vertical edge between (j, k) and (j+1, k). */ avg4(co, mesh_vert(vm_in, i, j, k), @@ -4101,9 +3996,9 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) } /* The new horizontal edge vertices. */ - for (i = 0; i < n_boundary; i++) { - for (j = 1; j < ns_in2; j++) { - for (k = 0; k < ns_in2; k++) { + for (int i = 0; i < n_boundary; i++) { + for (int j = 1; j < ns_in2; j++) { + for (int k = 0; k < ns_in2; k++) { /* Horizontal edge between (j, k) and (j, k+1). */ avg4(co, mesh_vert(vm_in, i, j, k), @@ -4116,11 +4011,12 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) } /* The new vertices, not on border. */ - gamma = 0.25f; - beta = -gamma; - for (i = 0; i < n_boundary; i++) { - for (j = 1; j < ns_in2; j++) { - for (k = 1; k <= ns_in2; k++) { + float gamma = 0.25f; + float beta = -gamma; + for (int i = 0; i < n_boundary; i++) { + for (int j = 1; j < ns_in2; j++) { + for (int k = 1; k <= ns_in2; k++) { + float co1[3], co2[3]; /* co1 = centroid of adjacent new edge verts. */ avg4(co1, mesh_vert_canon(vm_out, i, 2 * j, 2 * k - 1), @@ -4148,9 +4044,10 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) gamma = sabin_gamma(n_boundary); beta = -gamma; /* Accumulate edge verts in co1, face verts in co2. */ + float co1[3], co2[3]; zero_v3(co1); zero_v3(co2); - for (i = 0; i < n_boundary; i++) { + for (int i = 0; i < n_boundary; i++) { add_v3_v3(co1, mesh_vert(vm_out, i, ns_in, ns_in - 1)->co); add_v3_v3(co2, mesh_vert(vm_out, i, ns_in - 1, ns_in - 1)->co); add_v3_v3(co2, mesh_vert(vm_out, i, ns_in - 1, ns_in + 1)->co); @@ -4159,15 +4056,15 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) mul_v3_fl(co, 1.0f / (float)n_boundary); madd_v3_v3fl(co, co2, beta / (2.0f * (float)n_boundary)); madd_v3_v3fl(co, mesh_vert(vm_in, 0, ns_in2, ns_in2)->co, gamma); - for (i = 0; i < n_boundary; i++) { + for (int i = 0; i < n_boundary; i++) { copy_v3_v3(mesh_vert(vm_out, i, ns_in, ns_in)->co, co); } /* Final step: Copy the profile vertices to the VMesh's boundary. */ bndv = vm_out->boundstart; - for (i = 0; i < n_boundary; i++) { - inext = (i + 1) % n_boundary; - for (k = 0; k <= ns_out; k++) { + for (int i = 0; i < n_boundary; i++) { + int inext = (i + 1) % n_boundary; + for (int k = 0; k <= ns_out; k++) { get_profile_point(bp, &bndv->profile, k, ns_out, co); copy_v3_v3(mesh_vert(vm_out, i, 0, k)->co, co); if (k >= ns_in && k < ns_out) { @@ -4183,24 +4080,21 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in) /* Special case for cube corner, when r is PRO_SQUARE_R, meaning straight sides. */ static VMesh *make_cube_corner_square(MemArena *mem_arena, int nseg) { - VMesh *vm; - float co[3]; - int i, j, k, ns2; - - ns2 = nseg / 2; - vm = new_adj_vmesh(mem_arena, 3, nseg, NULL); + int ns2 = nseg / 2; + VMesh *vm = new_adj_vmesh(mem_arena, 3, nseg, NULL); vm->count = 0; /* Reset, so the following loop will end up with correct count. */ - for (i = 0; i < 3; i++) { - zero_v3(co); + for (int i = 0; i < 3; i++) { + float co[3] = {0.0f, 0.0f, 0.0f}; co[i] = 1.0f; add_new_bound_vert(mem_arena, vm, co); } - for (i = 0; i < 3; i++) { - for (j = 0; j <= ns2; j++) { - for (k = 0; k <= ns2; k++) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j <= ns2; j++) { + for (int k = 0; k <= ns2; k++) { if (!is_canon(vm, i, j, k)) { continue; } + float co[3]; co[i] = 1.0f; co[(i + 1) % 3] = (float)k * 2.0f / (float)nseg; co[(i + 2) % 3] = (float)j * 2.0f / (float)nseg; @@ -4220,28 +4114,26 @@ static VMesh *make_cube_corner_square(MemArena *mem_arena, int nseg) */ static VMesh *make_cube_corner_square_in(MemArena *mem_arena, int nseg) { - VMesh *vm; - float co[3]; - float b; - int i, k, ns2, odd; - - ns2 = nseg / 2; - odd = nseg % 2; - vm = new_adj_vmesh(mem_arena, 3, nseg, NULL); + int ns2 = nseg / 2; + int odd = nseg % 2; + VMesh *vm = new_adj_vmesh(mem_arena, 3, nseg, NULL); vm->count = 0; /* Reset, so following loop will end up with correct count. */ - for (i = 0; i < 3; i++) { - zero_v3(co); + for (int i = 0; i < 3; i++) { + float co[3] = {0.0f, 0.0f, 0.0f}; co[i] = 1.0f; add_new_bound_vert(mem_arena, vm, co); } + + float b; if (odd) { b = 2.0f / (2.0f * (float)ns2 + (float)M_SQRT2); } else { b = 2.0f / (float)nseg; } - for (i = 0; i < 3; i++) { - for (k = 0; k <= ns2; k++) { + for (int i = 0; i < 3; i++) { + for (int k = 0; k <= ns2; k++) { + float co[3]; co[i] = 1.0f - (float)k * b; co[(i + 1) % 3] = 0.0f; co[(i + 2) % 3] = 0.0f; @@ -4266,10 +4158,6 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) MemArena *mem_arena = bp->mem_arena; int nseg = bp->seg; float r = bp->pro_super_r; - VMesh *vm0, *vm1; - BoundVert *bndv; - int i, j, k, ns2; - float co[3], coc[3]; if (bp->profile_type != BEVEL_PROFILE_CUSTOM) { if (r == PRO_SQUARE_R) { @@ -4281,15 +4169,16 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) } /* Initial mesh has 3 sides and 2 segments on each side. */ - vm0 = new_adj_vmesh(mem_arena, 3, 2, NULL); + VMesh *vm0 = new_adj_vmesh(mem_arena, 3, 2, NULL); vm0->count = 0; /* Reset, so the following loop will end up with correct count. */ - for (i = 0; i < 3; i++) { - zero_v3(co); + for (int i = 0; i < 3; i++) { + float co[3] = {0.0f, 0.0f, 0.0f}; co[i] = 1.0f; add_new_bound_vert(mem_arena, vm0, co); } - bndv = vm0->boundstart; - for (i = 0; i < 3; i++) { + BoundVert *bndv = vm0->boundstart; + for (int i = 0; i < 3; i++) { + float coc[3]; /* Get point, 1/2 of the way around profile, on arc between this and next. */ coc[i] = 1.0f; coc[(i + 1) % 3] = 1.0f; @@ -4311,6 +4200,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) bndv = bndv->next; } /* Center vertex. */ + float co[3]; copy_v3_fl(co, (float)M_SQRT1_3); if (nseg > 2) { @@ -4325,7 +4215,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) vmesh_copy_equiv_verts(vm0); - vm1 = vm0; + VMesh *vm1 = vm0; while (vm1->seg < nseg) { vm1 = cubic_subdiv(bp, vm1); } @@ -4334,10 +4224,10 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) } /* Now snap each vertex to the superellipsoid. */ - ns2 = nseg / 2; - for (i = 0; i < 3; i++) { - for (j = 0; j <= ns2; j++) { - for (k = 0; k <= nseg; k++) { + int ns2 = nseg / 2; + for (int i = 0; i < 3; i++) { + for (int j = 0; j <= ns2; j++) { + for (int k = 0; k <= nseg; k++) { snap_to_superellipsoid(mesh_vert(vm1, i, j, k)->co, r, false); } } @@ -4349,9 +4239,6 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) /* Is this a good candidate for using tri_corner_adj_vmesh? */ static int tri_corner_test(BevelParams *bp, BevVert *bv) { - float ang, absang, totang, angdiff; - EdgeHalf *e; - int i; int in_plane_e = 0; /* The superellipse snapping of this case isn't helpful with custom profiles enabled. */ @@ -4365,11 +4252,11 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv) /* Only use the tri-corner special case if the offset is the same for every edge. */ float offset = bv->edges[0].offset_l; - totang = 0.0f; - for (i = 0; i < bv->edgecount; i++) { - e = &bv->edges[i]; - ang = BM_edge_calc_face_angle_signed_ex(e->e, 0.0f); - absang = fabsf(ang); + float totang = 0.0f; + for (int i = 0; i < bv->edgecount; i++) { + EdgeHalf *e = &bv->edges[i]; + float ang = BM_edge_calc_face_angle_signed_ex(e->e, 0.0f); + float absang = fabsf(ang); if (absang <= M_PI_4) { in_plane_e++; } @@ -4386,7 +4273,7 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv) if (in_plane_e != bv->edgecount - 3) { return -1; } - angdiff = fabsf(fabsf(totang) - 3.0f * (float)M_PI_2); + float angdiff = fabsf(fabsf(totang) - 3.0f * (float)M_PI_2); if ((bp->pro_super_r == PRO_SQUARE_R && angdiff > (float)M_PI / 16.0f) || (angdiff > (float)M_PI_4)) { return -1; @@ -4399,25 +4286,24 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv) static VMesh *tri_corner_adj_vmesh(BevelParams *bp, BevVert *bv) { - int i, j, k, ns, ns2; - float co0[3], co1[3], co2[3]; - float mat[4][4], v[4]; - VMesh *vm; - BoundVert *bndv; + BoundVert *bndv = bv->vmesh->boundstart; - bndv = bv->vmesh->boundstart; + float co0[3], co1[3], co2[3]; copy_v3_v3(co0, bndv->nv.co); bndv = bndv->next; copy_v3_v3(co1, bndv->nv.co); bndv = bndv->next; copy_v3_v3(co2, bndv->nv.co); + + float mat[4][4]; make_unit_cube_map(co0, co1, co2, bv->v->co, mat); - ns = bp->seg; - ns2 = ns / 2; - vm = make_cube_corner_adj_vmesh(bp); - for (i = 0; i < 3; i++) { - for (j = 0; j <= ns2; j++) { - for (k = 0; k <= ns; k++) { + int ns = bp->seg; + int ns2 = ns / 2; + VMesh *vm = make_cube_corner_adj_vmesh(bp); + for (int i = 0; i < 3; i++) { + for (int j = 0; j <= ns2; j++) { + for (int k = 0; k <= ns; k++) { + float v[4]; copy_v3_v3(v, mesh_vert(vm, i, j, k)->co); v[3] = 1.0f; mul_m4_v4(mat, v); @@ -4432,14 +4318,9 @@ static VMesh *tri_corner_adj_vmesh(BevelParams *bp, BevVert *bv) /* Makes the mesh that replaces the original vertex, bounded by the profiles on the sides. */ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) { - int n_bndv, nseg, i; - VMesh *vm0, *vm1; - float boundverts_center[3], original_vertex[3], negative_fullest[3], center_direction[3]; - BoundVert *bndv; MemArena *mem_arena = bp->mem_arena; - float fullness; - n_bndv = bv->vmesh->count; + int n_bndv = bv->vmesh->count; /* Same bevel as that of 3 edges of vert in a cube. */ if (n_bndv == 3 && tri_corner_test(bp, bv) != -1 && bp->pro_super_r != PRO_SQUARE_IN_R) { @@ -4447,13 +4328,13 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) } /* First construct an initial control mesh, with nseg == 2. */ - nseg = bv->vmesh->seg; - vm0 = new_adj_vmesh(mem_arena, n_bndv, 2, bv->vmesh->boundstart); + int nseg = bv->vmesh->seg; + VMesh *vm0 = new_adj_vmesh(mem_arena, n_bndv, 2, bv->vmesh->boundstart); /* Find the center of the boundverts that make up the vmesh. */ - bndv = vm0->boundstart; - zero_v3(boundverts_center); - for (i = 0; i < n_bndv; i++) { + BoundVert *bndv = vm0->boundstart; + float boundverts_center[3] = {0.0f, 0.0f, 0.0f}; + for (int i = 0; i < n_bndv; i++) { /* Boundaries just divide input polygon edges into 2 even segments. */ copy_v3_v3(mesh_vert(vm0, i, 0, 0)->co, bndv->nv.co); get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co); @@ -4466,12 +4347,14 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) * 'negative_fullest' is the reflection of the original vertex across the boundverts' center. * 'fullness' is the fraction of the way from the boundvert's centroid to the original vertex * (if positive) or to negative_fullest (if negative). */ + float original_vertex[3], negative_fullest[3]; copy_v3_v3(original_vertex, bv->v->co); sub_v3_v3v3(negative_fullest, boundverts_center, original_vertex); add_v3_v3(negative_fullest, boundverts_center); /* Find the vertex mesh's start center with the profile's fullness. */ - fullness = bp->pro_spacing.fullness; + float fullness = bp->pro_spacing.fullness; + float center_direction[3]; sub_v3_v3v3(center_direction, original_vertex, boundverts_center); if (len_squared_v3(center_direction) > BEVEL_EPSILON_SQ) { if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { @@ -4488,7 +4371,7 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) vmesh_copy_equiv_verts(vm0); /* Do the subdivision process to go from the two segment start mesh to the final vertex mesh. */ - vm1 = vm0; + VMesh *vm1 = vm0; do { vm1 = cubic_subdiv(bp, vm1); } while (vm1->seg < nseg); @@ -4506,35 +4389,38 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) */ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3]) { - float va[3], vb[3], edir[3], va0[3], vb0[3], vmid0[3]; - float plane[4], m[4][4], minv[4][4], p[3], snap[3]; Profile *pro = &vpipe->profile; EdgeHalf *e = vpipe->ebev; - copy_v3_v3(va, pro->start); - copy_v3_v3(vb, pro->end); - if (compare_v3v3(va, vb, BEVEL_EPSILON_D)) { - copy_v3_v3(co, va); + if (compare_v3v3(pro->start, pro->end, BEVEL_EPSILON_D)) { + copy_v3_v3(co, pro->start); return; } /* Get a plane with the normal pointing along the beveled edge. */ + float edir[3], plane[4]; sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co); plane_from_point_normal_v3(plane, co, edir); - closest_to_plane_v3(va0, plane, va); - closest_to_plane_v3(vb0, plane, vb); + float va0[3], vb0[3], vmid0[3]; + closest_to_plane_v3(va0, plane, pro->start); + closest_to_plane_v3(vb0, plane, pro->end); closest_to_plane_v3(vmid0, plane, pro->middle); + + float m[4][4], minv[4][4]; if (make_unit_square_map(va0, vmid0, vb0, m) && invert_m4_m4(minv, m)) { /* Transform co and project it onto superellipse. */ + float p[3]; mul_v3_m4v3(p, minv, co); snap_to_superellipsoid(p, pro->super_r, midline); + float snap[3]; mul_v3_m4v3(snap, m, p); copy_v3_v3(co, snap); } else { /* Planar case: just snap to line va0--vb0. */ + float p[3]; closest_to_line_segment_v3(p, co, va0, vb0); copy_v3_v3(co, p); } @@ -4547,35 +4433,30 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3]) */ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) { - int i, j, k, n_bndv, ns, half_ns, ipipe1, ipipe2, ring; - VMesh *vm; - bool even, midline; - float *profile_point_pipe1, *profile_point_pipe2, f; - /* Some unnecessary overhead running this subdivision with custom profile snapping later on. */ - vm = adj_vmesh(bp, bv); + VMesh *vm = adj_vmesh(bp, bv); /* Now snap all interior coordinates to be on the epipe profile. */ - n_bndv = bv->vmesh->count; - ns = bv->vmesh->seg; - half_ns = ns / 2; - even = (ns % 2) == 0; - ipipe1 = vpipe->index; - ipipe2 = vpipe->next->next->index; - - for (i = 0; i < n_bndv; i++) { - for (j = 1; j <= half_ns; j++) { - for (k = 0; k <= half_ns; k++) { + int n_bndv = bv->vmesh->count; + int ns = bv->vmesh->seg; + int half_ns = ns / 2; + int ipipe1 = vpipe->index; + int ipipe2 = vpipe->next->next->index; + + for (int i = 0; i < n_bndv; i++) { + for (int j = 1; j <= half_ns; j++) { + for (int k = 0; k <= half_ns; k++) { if (!is_canon(vm, i, j, k)) { continue; } /* With a custom profile just copy the shape of the profile at each ring. */ if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Find both profile vertices that correspond to this point. */ + float *profile_point_pipe1, *profile_point_pipe2, f; if (i == ipipe1 || i == ipipe2) { if (n_bndv == 3 && i == ipipe1) { /* This part of the vmesh is the triangular corner between the two pipe profiles. */ - ring = max_ii(j, k); + int ring = max_ii(j, k); profile_point_pipe2 = mesh_vert(vm, i, 0, ring)->co; profile_point_pipe1 = mesh_vert(vm, i, ring, 0)->co; /* End profile index increases with k on one side and j on the other. */ @@ -4601,8 +4482,9 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) else { /* A tricky case is for the 'square' profiles and an even nseg: we want certain * vertices to snap to the midline on the pipe, not just to one plane or the other. */ - midline = even && k == half_ns && - ((i == 0 && j == half_ns) || (i == ipipe1 || i == ipipe2)); + bool even = (ns % 2) == 0; + bool midline = even && k == half_ns && + ((i == 0 && j == half_ns) || (i == ipipe1 || i == ipipe2)); snap_to_pipe_profile(vpipe, midline, mesh_vert(vm, i, j, k)->co); } } @@ -4613,14 +4495,14 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) static void get_incident_edges(BMFace *f, BMVert *v, BMEdge **r_e1, BMEdge **r_e2) { - BMIter iter; - BMEdge *e; - *r_e1 = NULL; *r_e2 = NULL; if (!f) { return; } + + BMIter iter; + BMEdge *e; BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) { if (e->v1 == v || e->v2 == v) { if (*r_e1 == NULL) { @@ -4635,11 +4517,9 @@ static void get_incident_edges(BMFace *f, BMVert *v, BMEdge **r_e1, BMEdge **r_e static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2) { - float dsq1, dsq2; - BLI_assert(e1 != NULL && e2 != NULL); - dsq1 = dist_squared_to_line_segment_v3(co, e1->v1->co, e1->v2->co); - dsq2 = dist_squared_to_line_segment_v3(co, e2->v1->co, e2->v2->co); + float dsq1 = dist_squared_to_line_segment_v3(co, e1->v1->co, e1->v2->co); + float dsq2 = dist_squared_to_line_segment_v3(co, e2->v1->co, e2->v2->co); if (dsq1 < dsq2) { return e1; } @@ -4651,16 +4531,14 @@ static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2) * and the distance squared to the snap point as function return */ static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, float *r_snap_co) { - BMIter iter; BMEdge *beste = NULL; - float d2, beste_d2; + float beste_d2 = 1e20f; + BMIter iter; BMEdge *e; - float closest[3]; - - beste_d2 = 1e20f; BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) { + float closest[3]; closest_to_line_segment_v3(closest, co, e->v1->co, e->v2->co); - d2 = len_squared_v3v3(closest, co); + float d2 = len_squared_v3v3(closest, co); if (d2 < beste_d2) { beste_d2 = d2; beste = e; @@ -4675,23 +4553,19 @@ static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, flo */ static float interp_poly_area(BevVert *bv, BMFace *frep) { - BoundVert *v; VMesh *vm = bv->vmesh; - BMEdge *snape; - int n; - float(*uv_co)[3] = NULL; - float area; BLI_assert(vm != NULL); - uv_co = BLI_array_alloca(uv_co, vm->count); - v = vm->boundstart; - n = 0; + float(*uv_co)[3] = BLI_array_alloca(uv_co, vm->count); + BoundVert *v = vm->boundstart; + int n = 0; do { BLI_assert(n < vm->count); + BMEdge *snape; snap_face_dist_squared(v->nv.v->co, frep, &snape, uv_co[n]); n++; } while ((v = v->next) != vm->boundstart); - area = fabsf(area_poly_v3(uv_co, n)); + float area = fabsf(area_poly_v3(uv_co, n)); return area; } @@ -4724,32 +4598,25 @@ static bool is_bad_uv_poly(BevVert *bv, BMFace *frep) */ static BMFace *frep_for_center_poly(BevelParams *bp, BevVert *bv) { - int i, j, fcount; - BMFace **fchoices, *bmf, *bmf1, *bmf2, *any_bmf; - BMFace *ftwo[2]; - bool already_there; - bool consider_all_faces; - - fcount = 0; - any_bmf = NULL; - consider_all_faces = bv->selcount == 1; + int fcount = 0; + BMFace *any_bmf = NULL; + bool consider_all_faces = bv->selcount == 1; /* Make an array that can hold maximum possible number of choices. */ - fchoices = BLI_array_alloca(fchoices, bv->edgecount); - for (i = 0; i < bv->edgecount; i++) { + BMFace **fchoices = BLI_array_alloca(fchoices, bv->edgecount); + for (int i = 0; i < bv->edgecount; i++) { if (!bv->edges[i].is_bev && !consider_all_faces) { continue; } - bmf1 = bv->edges[i].fprev; - bmf2 = bv->edges[i].fnext; - ftwo[0] = bmf1; - ftwo[1] = bmf2; - bmf = choose_rep_face(bp, ftwo, 2); + BMFace *bmf1 = bv->edges[i].fprev; + BMFace *bmf2 = bv->edges[i].fnext; + BMFace *ftwo[2] = {bmf1, bmf2}; + BMFace *bmf = choose_rep_face(bp, ftwo, 2); if (bmf != NULL) { if (any_bmf == NULL) { any_bmf = bmf; } - already_there = false; - for (j = fcount - 1; j >= 0; j--) { + bool already_there = false; + for (int j = fcount - 1; j >= 0; j--) { if (fchoices[j] == bmf) { already_there = true; break; @@ -4774,10 +4641,6 @@ static BMFace *frep_for_center_poly(BevelParams *bp, BevVert *bv) static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_nr) { VMesh *vm = bv->vmesh; - BoundVert *v; - int i, ns2; - BMFace *frep, *f; - BMEdge *frep_e1, *frep_e2, *frep_e; BMVert **vv = NULL; BMFace **vf = NULL; BMEdge **ve = NULL; @@ -4785,7 +4648,9 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE); - ns2 = vm->seg / 2; + int ns2 = vm->seg / 2; + BMFace *frep; + BMEdge *frep_e1, *frep_e2; if (bv->any_seam) { frep = frep_for_center_poly(bp, bv); get_incident_edges(frep, bv->v, &frep_e1, &frep_e2); @@ -4794,13 +4659,13 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n frep = NULL; frep_e1 = frep_e2 = NULL; } - v = vm->boundstart; + BoundVert *v = vm->boundstart; do { - i = v->index; + int i = v->index; BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v); if (frep) { BLI_array_append(vf, frep); - frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2); + BMEdge *frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2); BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e); } else { @@ -4808,7 +4673,7 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n BLI_array_append(ve, NULL); } } while ((v = v->next) != vm->boundstart); - f = bev_create_ngon(bm, vv, BLI_array_len(vv), vf, frep, ve, mat_nr, true); + BMFace *f = bev_create_ngon(bm, vv, BLI_array_len(vv), vf, frep, ve, mat_nr, true); record_face_kind(bp, f, F_VERT); BLI_array_free(vv); @@ -4824,17 +4689,14 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n */ static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh *vm1) { - int n, ns, ns2, odd, i, k; - VMesh *vm; - - vm = bv->vmesh; - n = vm->count; - ns = vm->seg; - ns2 = ns / 2; - odd = ns % 2; + VMesh *vm = bv->vmesh; + int n = vm->count; + int ns = vm->seg; + int ns2 = ns / 2; + int odd = ns % 2; - for (i = 0; i < n; i++) { - for (k = 1; k < ns; k++) { + for (int i = 0; i < n; i++) { + for (int k = 1; k < ns; k++) { copy_v3_v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm1, i, 0, k)->co); if (i > 0 && k <= ns2) { mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, i - 1, 0, ns - k)->v; @@ -4848,7 +4710,7 @@ static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh } } if (odd) { - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { mesh_vert(vm, i, ns2, ns2)->v = mesh_vert(vm, i, 0, ns2)->v; } build_center_ngon(bp, bm, bv, bp->mat_nr); @@ -4882,34 +4744,25 @@ static void closer_v3_v3v3v3(float r[3], const float a[3], const float b[3], con */ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) { - int n_bndv, ns, ns2, odd, i, j, k, ikind, im1, clstride, iprev, ang_kind; - float bndco[3], dir1[3], dir2[3], co1[3], co2[3], meet1[3], meet2[3], v1co[3], v2co[3]; - float *on_edge_cur, *on_edge_prev, *p; - float ns2inv, finalfrac, ang; - BoundVert *bndv; - EdgeHalf *e1, *e2; - VMesh *vm; - float *centerline; - bool *cset, v1set, v2set; - - n_bndv = bv->vmesh->count; - ns = bv->vmesh->seg; - ns2 = ns / 2; - odd = ns % 2; - ns2inv = 1.0f / (float)ns2; - vm = new_adj_vmesh(bp->mem_arena, n_bndv, ns, bv->vmesh->boundstart); - clstride = 3 * (ns2 + 1); - centerline = MEM_mallocN((size_t)(clstride * n_bndv) * sizeof(float), "bevel"); - cset = MEM_callocN((size_t)n_bndv * sizeof(bool), "bevel"); + int n_bndv = bv->vmesh->count; + int ns = bv->vmesh->seg; + int ns2 = ns / 2; + int odd = ns % 2; + float ns2inv = 1.0f / (float)ns2; + VMesh *vm = new_adj_vmesh(bp->mem_arena, n_bndv, ns, bv->vmesh->boundstart); + int clstride = 3 * (ns2 + 1); + float *centerline = MEM_mallocN(sizeof(float) * clstride * n_bndv, "bevel"); + bool *cset = MEM_callocN(sizeof(bool) * n_bndv, "bevel"); /* Find on_edge, place on bndv[i]'s elast where offset line would meet, * taking min-distance-to bv->v with position where next sector's offset line would meet. */ - bndv = vm->boundstart; - for (i = 0; i < n_bndv; i++) { + BoundVert *bndv = vm->boundstart; + for (int i = 0; i < n_bndv; i++) { + float bndco[3]; copy_v3_v3(bndco, bndv->nv.co); - e1 = bndv->efirst; - e2 = bndv->elast; - ang_kind = ANGLE_STRAIGHT; + EdgeHalf *e1 = bndv->efirst; + EdgeHalf *e2 = bndv->elast; + int ang_kind = ANGLE_STRAIGHT; if (e1 && e2) { ang_kind = edges_angle_kind(e1, e2, bv->v); } @@ -4934,12 +4787,16 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) /* Leave cset[i] where it was - probably false, unless i == n - 1. */ } else if (ang_kind == ANGLE_SMALLER) { + float dir1[3], dir2[3], co1[3], co2[3]; sub_v3_v3v3(dir1, e1->e->v1->co, e1->e->v2->co); sub_v3_v3v3(dir2, e2->e->v1->co, e2->e->v2->co); add_v3_v3v3(co1, bndco, dir1); add_v3_v3v3(co2, bndco, dir2); /* Intersect e1 with line through bndv parallel to e2 to get v1co. */ - ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2); + float meet1[3], meet2[3]; + int ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2); + float v1co[3]; + bool v1set; if (ikind == 0) { v1set = false; } @@ -4950,6 +4807,8 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) } /* Intersect e2 with line through bndv parallel to e1 to get v2co. */ ikind = isect_line_line_v3(e2->e->v1->co, e2->e->v2->co, bndco, co1, meet1, meet2); + float v2co[3]; + bool v2set; if (ikind == 0) { v2set = false; } @@ -4959,9 +4818,9 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) } /* We want on_edge[i] to be min dist to bv->v of v2co and the v1co of next iteration. */ - on_edge_cur = centerline + clstride * i; - iprev = (i == 0) ? n_bndv - 1 : i - 1; - on_edge_prev = centerline + clstride * iprev; + float *on_edge_cur = centerline + clstride * i; + int iprev = (i == 0) ? n_bndv - 1 : i - 1; + float *on_edge_prev = centerline + clstride * iprev; if (v2set) { if (cset[i]) { closer_v3_v3v3v3(on_edge_cur, on_edge_cur, v2co, bv->v->co); @@ -4985,15 +4844,17 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) } /* Maybe not everything was set by the previous loop. */ bndv = vm->boundstart; - for (i = 0; i < n_bndv; i++) { + for (int i = 0; i < n_bndv; i++) { if (!cset[i]) { - on_edge_cur = centerline + clstride * i; - e1 = bndv->next->efirst; + float *on_edge_cur = centerline + clstride * i; + EdgeHalf *e1 = bndv->next->efirst; + float co1[3], co2[3]; copy_v3_v3(co1, bndv->nv.co); copy_v3_v3(co2, bndv->next->nv.co); if (e1) { if (bndv->prev->is_arc_start && bndv->next->is_arc_start) { - ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, co1, co2, meet1, meet2); + float meet1[3], meet2[3]; + int ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, co1, co2, meet1, meet2); if (ikind != 0) { copy_v3_v3(on_edge_cur, meet1); cset[i] = true; @@ -5018,11 +4879,13 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) } /* Fill in rest of center-lines by interpolation. */ + float co1[3], co2[3]; copy_v3_v3(co2, bv->v->co); bndv = vm->boundstart; - for (i = 0; i < n_bndv; i++) { + for (int i = 0; i < n_bndv; i++) { if (odd) { - ang = 0.5f * angle_v3v3v3(bndv->nv.co, co1, bndv->next->nv.co); + float ang = 0.5f * angle_v3v3v3(bndv->nv.co, co1, bndv->next->nv.co); + float finalfrac; if (ang > BEVEL_SMALL_ANG) { /* finalfrac is the length along arms of isosceles triangle with top angle 2*ang * such that the base of the triangle is 1. @@ -5039,10 +4902,10 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) ns2inv = 1.0f / (ns2 + finalfrac); } - p = centerline + clstride * i; + float *p = centerline + clstride * i; copy_v3_v3(co1, p); p += 3; - for (j = 1; j <= ns2; j++) { + for (int j = 1; j <= ns2; j++) { interp_v3_v3v3(p, co1, co2, j * ns2inv); p += 3; } @@ -5051,14 +4914,14 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) /* Coords of edges and mid or near-mid line. */ bndv = vm->boundstart; - for (i = 0; i < n_bndv; i++) { + for (int i = 0; i < n_bndv; i++) { copy_v3_v3(co1, bndv->nv.co); copy_v3_v3(co2, centerline + clstride * (i == 0 ? n_bndv - 1 : i - 1)); - for (j = 0; j < ns2 + odd; j++) { + for (int j = 0; j < ns2 + odd; j++) { interp_v3_v3v3(mesh_vert(vm, i, j, 0)->co, co1, co2, j * ns2inv); } copy_v3_v3(co2, centerline + clstride * i); - for (k = 1; k <= ns2; k++) { + for (int k = 1; k <= ns2; k++) { interp_v3_v3v3(mesh_vert(vm, i, 0, k)->co, co1, co2, k * ns2inv); } bndv = bndv->next; @@ -5070,16 +4933,17 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) /* Fill in interior points by interpolation from edges to center-lines. */ bndv = vm->boundstart; - for (i = 0; i < n_bndv; i++) { - im1 = (i == 0) ? n_bndv - 1 : i - 1; - for (j = 1; j < ns2 + odd; j++) { - for (k = 1; k <= ns2; k++) { - ikind = isect_line_line_v3(mesh_vert(vm, i, 0, k)->co, - centerline + clstride * im1 + 3 * k, - mesh_vert(vm, i, j, 0)->co, - centerline + clstride * i + 3 * j, - meet1, - meet2); + for (int i = 0; i < n_bndv; i++) { + int im1 = (i == 0) ? n_bndv - 1 : i - 1; + for (int j = 1; j < ns2 + odd; j++) { + for (int k = 1; k <= ns2; k++) { + float meet1[3], meet2[3]; + int ikind = isect_line_line_v3(mesh_vert(vm, i, 0, k)->co, + centerline + clstride * im1 + 3 * k, + mesh_vert(vm, i, j, 0)->co, + centerline + clstride * i + 3 * j, + meet1, + meet2); if (ikind == 0) { /* How can this happen? fall back on interpolation in one direction if it does. */ interp_v3_v3v3(mesh_vert(vm, i, j, k)->co, @@ -5112,22 +4976,15 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv) */ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert *vpipe) { - int n_bndv, ns, ns2, odd, i, j, k, ring; - VMesh *vm1, *vm; - BoundVert *bndv; - BMVert *bmv1, *bmv2, *bmv3, *bmv4; - BMFace *f, *f2, *r_f, *fc; - BMFace *fchoices[2]; - BMEdge *bme, *bme1, *bme2, *bme3; - EdgeHalf *e; int mat_nr = bp->mat_nr; - n_bndv = bv->vmesh->count; - ns = bv->vmesh->seg; - ns2 = ns / 2; - odd = ns % 2; + int n_bndv = bv->vmesh->count; + int ns = bv->vmesh->seg; + int ns2 = ns / 2; + int odd = ns % 2; BLI_assert(n_bndv >= 3 && ns > 1); + VMesh *vm1; if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd && bp->profile_type != BEVEL_PROFILE_CUSTOM) { vm1 = square_out_adj_vmesh(bp, bv); @@ -5149,10 +5006,10 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert } /* Copy final vmesh into bv->vmesh, make BMVerts and BMFaces. */ - vm = bv->vmesh; - for (i = 0; i < n_bndv; i++) { - for (j = 0; j <= ns2; j++) { - for (k = 0; k <= ns; k++) { + VMesh *vm = bv->vmesh; + for (int i = 0; i < n_bndv; i++) { + for (int j = 0; j <= ns2; j++) { + for (int k = 0; k <= ns; k++) { if (j == 0 && (k == 0 || k == ns)) { continue; /* Boundary corners already made. */ } @@ -5166,26 +5023,16 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert } vmesh_copy_equiv_verts(vm); /* Make the polygons. */ - bndv = vm->boundstart; + BoundVert *bndv = vm->boundstart; do { - i = bndv->index; - f = boundvert_rep_face(bndv, NULL); - f2 = boundvert_rep_face(bndv->next, NULL); - fchoices[0] = f; - fchoices[1] = f2; - if (odd) { - fc = choose_rep_face(bp, fchoices, 2); - } - else { - fc = NULL; - } - if (bp->affect_type == BEVEL_AFFECT_VERTICES) { - e = bndv->efirst; - } - else { - e = bndv->ebev; - } - bme = e ? e->e : NULL; + int i = bndv->index; + BMFace *f = boundvert_rep_face(bndv, NULL); + BMFace *f2 = boundvert_rep_face(bndv->next, NULL); + BMFace *fchoices[2] = {f, f2}; + BMFace *fc = odd ? choose_rep_face(bp, fchoices, 2) : NULL; + + EdgeHalf *e = (bp->affect_type == BEVEL_AFFECT_VERTICES) ? bndv->efirst : bndv->ebev; + BMEdge *bme = e ? e->e : NULL; /* For odd ns, make polys with lower left corner at (i,j,k) for * j in [0, ns2-1], k in [0, ns2]. And then the center ngon. * For even ns, @@ -5193,13 +5040,14 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert * * Recall: j is ring index, k is segment index. */ - for (j = 0; j < ns2; j++) { - for (k = 0; k < ns2 + odd; k++) { - bmv1 = mesh_vert(vm, i, j, k)->v; - bmv2 = mesh_vert(vm, i, j, k + 1)->v; - bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v; - bmv4 = mesh_vert(vm, i, j + 1, k)->v; + for (int j = 0; j < ns2; j++) { + for (int k = 0; k < ns2 + odd; k++) { + BMVert *bmv1 = mesh_vert(vm, i, j, k)->v; + BMVert *bmv2 = mesh_vert(vm, i, j, k + 1)->v; + BMVert *bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v; + BMVert *bmv4 = mesh_vert(vm, i, j + 1, k)->v; BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); + BMFace *r_f; if (bp->affect_type == BEVEL_AFFECT_VERTICES) { if (j < k) { if (k == ns2 && j == ns2 - 1) { @@ -5255,12 +5103,12 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert } } else { - bme1 = k == ns2 - 1 ? bme : NULL; - bme3 = NULL; + BMEdge *bme1 = k == ns2 - 1 ? bme : NULL; + BMEdge *bme3 = NULL; if (j == ns2 - 1 && bndv->prev->ebev) { bme3 = bndv->prev->ebev->e; } - bme2 = bme1 != NULL ? bme1 : bme3; + BMEdge *bme2 = bme1 != NULL ? bme1 : bme3; r_f = bev_create_quad_ex( bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme1, bme2, bme3, f, mat_nr); } @@ -5274,9 +5122,9 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert if (!odd) { bndv = vm->boundstart; do { - i = bndv->index; + int i = bndv->index; if (!bndv->any_seam) { - for (ring = 1; ring < ns2; ring++) { + for (int ring = 1; ring < ns2; ring++) { BMVert *v_uv = mesh_vert(vm, i, ring, ns2)->v; if (v_uv) { bev_merge_uvs(bm, v_uv); @@ -5284,9 +5132,9 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert } } } while ((bndv = bndv->next) != vm->boundstart); - bmv1 = mesh_vert(vm, 0, ns2, ns2)->v; + BMVert *bmv = mesh_vert(vm, 0, ns2, ns2)->v; if (bp->affect_type == BEVEL_AFFECT_VERTICES || count_bound_vert_seams(bv) <= 1) { - bev_merge_uvs(bm, bmv1); + bev_merge_uvs(bm, bmv); } } @@ -5312,33 +5160,27 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF printf("BEVEL BUILD CUTOFF\n"); # define F3(v) (v)[0], (v)[1], (v)[2] - int j; #endif - int i; int n_bndv = bv->vmesh->count; - BoundVert *bndv; - float length; - float down_direction[3], new_vert[3]; - bool build_center_face; - /* BMFace *repface; */ - BMVert **face_bmverts = NULL; - BMEdge **bmedges = NULL; - BMFace **bmfaces = NULL; /* Find the locations for the corner vertices at the bottom of the cutoff faces. */ - bndv = bv->vmesh->boundstart; + BoundVert *bndv = bv->vmesh->boundstart; do { - i = bndv->index; + int i = bndv->index; /* Find the "down" direction for this side of the cutoff face. */ /* Find the direction along the intersection of the two adjacent profile normals. */ + float down_direction[3]; cross_v3_v3v3(down_direction, bndv->profile.plane_no, bndv->prev->profile.plane_no); if (dot_v3v3(down_direction, bv->v->no) > 0.0f) { negate_v3(down_direction); } /* Move down from the boundvert by average profile height from the two adjacent profiles. */ - length = (bndv->profile.height / sqrtf(2.0f) + bndv->prev->profile.height / sqrtf(2.0f)) / 2; + float length = (bndv->profile.height / sqrtf(2.0f) + + bndv->prev->profile.height / sqrtf(2.0f)) / + 2; + float new_vert[3]; madd_v3_v3v3fl(new_vert, bndv->nv.co, down_direction, length); /* Use this location for this profile's first corner vert and the last profile's second. */ @@ -5349,13 +5191,13 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF printf("Corner vertices:\n"); - for (j = 0; j < n_bndv; j++) { + for (int j = 0; j < n_bndv; j++) { printf(" (%.3f, %.3f, %.3f)\n", F3(mesh_vert(bv->vmesh, j, 1, 0)->co)); } #endif /* Disable the center face if the corner vertices share the same location. */ - build_center_face = true; + bool build_center_face = true; if (n_bndv == 3) { /* Vertices only collapse with a 3-way VMesh. */ build_center_face &= len_squared_v3v3(mesh_vert(bv->vmesh, 0, 1, 0)->co, mesh_vert(bv->vmesh, 1, 1, 0)->co) > BEVEL_EPSILON; @@ -5371,7 +5213,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) /* Create the corner vertex BMVerts. */ if (build_center_face) { do { - i = bndv->index; + int i = bndv->index; create_mesh_bmvert(bm, bv->vmesh, i, 1, 0, bv->v); /* The second corner vertex for the previous profile shares this BMVert. */ mesh_vert(bv->vmesh, bndv->prev->index, 1, 1)->v = mesh_vert(bv->vmesh, i, 1, 0)->v; @@ -5381,7 +5223,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) else { /* Use the same BMVert for all of the corner vertices. */ create_mesh_bmvert(bm, bv->vmesh, 0, 1, 0, bv->v); - for (i = 1; i < n_bndv; i++) { + for (int i = 1; i < n_bndv; i++) { mesh_vert(bv->vmesh, i, 1, 0)->v = mesh_vert(bv->vmesh, 0, 1, 0)->v; } } @@ -5392,11 +5234,13 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF printf("Building profile cutoff faces.\n"); #endif - face_bmverts = BLI_memarena_alloc( - bp->mem_arena, ((size_t)max_ii(bp->seg + 2 + build_center_face, n_bndv) * sizeof(BMVert *))); + BMVert **face_bmverts = BLI_memarena_alloc( + bp->mem_arena, sizeof(BMVert *) * max_ii(bp->seg + 2 + build_center_face, n_bndv)); bndv = bv->vmesh->boundstart; do { - i = bndv->index; + int i = bndv->index; + BMEdge **bmedges = NULL; + BMFace **bmfaces = NULL; BLI_array_staticdeclare(bmedges, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(bmfaces, BM_DEFAULT_NGON_STACK_SIZE); @@ -5444,11 +5288,13 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) /* Create the bottom face if it should be built, reusing previous face_bmverts allocation. */ if (build_center_face) { + BMEdge **bmedges = NULL; + BMFace **bmfaces = NULL; BLI_array_staticdeclare(bmedges, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(bmfaces, BM_DEFAULT_NGON_STACK_SIZE); /* Add all of the corner vertices to this face. */ - for (i = 0; i < n_bndv; i++) { + for (int i = 0; i < n_bndv; i++) { /* Add verts from each cutoff face. */ face_bmverts[i] = mesh_vert(bv->vmesh, i, 1, 0)->v; } @@ -5462,11 +5308,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) { - BMFace *f, *repface; - int n, k; VMesh *vm = bv->vmesh; - BoundVert *bndv; - BMEdge *repface_e1, *repface_e2, *frep_e; BMVert **bmverts = NULL; BMEdge **bmedges = NULL; BMFace **bmfaces = NULL; @@ -5474,6 +5316,8 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) BLI_array_staticdeclare(bmedges, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(bmfaces, BM_DEFAULT_NGON_STACK_SIZE); + BMFace *repface; + BMEdge *repface_e1, *repface_e2; if (bv->any_seam) { repface = frep_for_center_poly(bp, bv); get_incident_edges(repface, bv->v, &repface_e1, &repface_e2); @@ -5482,15 +5326,15 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) repface = NULL; repface_e1 = repface_e2 = NULL; } - bndv = vm->boundstart; - n = 0; + BoundVert *bndv = vm->boundstart; + int n = 0; do { /* Accumulate vertices for vertex ngon. */ /* Also accumulate faces in which uv interpolation is to happen for each. */ BLI_array_append(bmverts, bndv->nv.v); if (repface) { BLI_array_append(bmfaces, repface); - frep_e = find_closer_edge(bndv->nv.v->co, repface_e1, repface_e2); + BMEdge *frep_e = find_closer_edge(bndv->nv.v->co, repface_e1, repface_e2); BLI_array_append(bmedges, n > 0 ? frep_e : NULL); } else { @@ -5499,11 +5343,11 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) } n++; if (bndv->ebev && bndv->ebev->seg > 1) { - for (k = 1; k < bndv->ebev->seg; k++) { + for (int k = 1; k < bndv->ebev->seg; k++) { BLI_array_append(bmverts, mesh_vert(vm, bndv->index, 0, k)->v); if (repface) { BLI_array_append(bmfaces, repface); - frep_e = find_closer_edge( + BMEdge *frep_e = find_closer_edge( mesh_vert(vm, bndv->index, 0, k)->v->co, repface_e1, repface_e2); BLI_array_append(bmedges, k < bndv->ebev->seg / 2 ? NULL : frep_e); } @@ -5515,6 +5359,8 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) } } } while ((bndv = bndv->next) != vm->boundstart); + + BMFace *f; if (n > 2) { f = bev_create_ngon(bm, bmverts, n, bmfaces, repface, bmedges, bp->mat_nr, true); record_face_kind(bp, f, F_VERT); @@ -5530,53 +5376,54 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv) { - BMFace *f; BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1); - f = bevel_build_poly(bp, bm, bv); + BMFace *f = bevel_build_poly(bp, bm, bv); - if (f) { - /* We have a polygon which we know starts at the previous vertex, make it into a fan. */ - BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev; - BMVert *v_fan = l_fan->v; - - while (f->len > 3) { - BMLoop *l_new; - BMFace *f_new; - BLI_assert(v_fan == l_fan->v); - f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, false); - flag_out_edge(bm, l_new->e); - - if (f_new->len > f->len) { - f = f_new; - if (l_new->v == v_fan) { - l_fan = l_new; - } - else if (l_new->next->v == v_fan) { - l_fan = l_new->next; - } - else if (l_new->prev->v == v_fan) { - l_fan = l_new->prev; - } - else { - BLI_assert(0); - } + if (f == NULL) { + return; + } + + /* We have a polygon which we know starts at the previous vertex, make it into a fan. */ + BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev; + BMVert *v_fan = l_fan->v; + + while (f->len > 3) { + BMLoop *l_new; + BMFace *f_new; + BLI_assert(v_fan == l_fan->v); + f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, false); + flag_out_edge(bm, l_new->e); + + if (f_new->len > f->len) { + f = f_new; + if (l_new->v == v_fan) { + l_fan = l_new; + } + else if (l_new->next->v == v_fan) { + l_fan = l_new->next; + } + else if (l_new->prev->v == v_fan) { + l_fan = l_new->prev; } else { - if (l_fan->v == v_fan) { /* l_fan = l_fan. */ - } - else if (l_fan->next->v == v_fan) { - l_fan = l_fan->next; - } - else if (l_fan->prev->v == v_fan) { - l_fan = l_fan->prev; - } - else { - BLI_assert(0); - } + BLI_assert(0); } - record_face_kind(bp, f_new, F_VERT); } + else { + if (l_fan->v == v_fan) { /* l_fan = l_fan. */ + } + else if (l_fan->next->v == v_fan) { + l_fan = l_fan->next; + } + else if (l_fan->prev->v == v_fan) { + l_fan = l_fan->prev; + } + else { + BLI_assert(0); + } + } + record_face_kind(bp, f_new, F_VERT); } } @@ -5588,23 +5435,17 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv) static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) { VMesh *vm = bv->vmesh; - BMVert *v1, *v2; - BMEdge *e_eg, *bme; - Profile *pro; - float co[3]; - BoundVert *bndv; - int ns, k; BLI_assert(vm->count == 2 && bp->affect_type == BEVEL_AFFECT_VERTICES); - v1 = mesh_vert(vm, 0, 0, 0)->v; - v2 = mesh_vert(vm, 1, 0, 0)->v; + BMVert *v1 = mesh_vert(vm, 0, 0, 0)->v; + BMVert *v2 = mesh_vert(vm, 1, 0, 0)->v; - ns = vm->seg; + int ns = vm->seg; if (ns > 1) { /* Set up profile parameters. */ - bndv = vm->boundstart; - pro = &bndv->profile; + BoundVert *bndv = vm->boundstart; + Profile *pro = &bndv->profile; pro->super_r = bp->pro_super_r; copy_v3_v3(pro->start, v1->co); copy_v3_v3(pro->end, v2->co); @@ -5614,25 +5455,26 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) zero_v3(pro->plane_no); zero_v3(pro->proj_dir); - for (k = 1; k < ns; k++) { + for (int k = 1; k < ns; k++) { + float co[3]; get_profile_point(bp, pro, k, ns, co); copy_v3_v3(mesh_vert(vm, 0, 0, k)->co, co); create_mesh_bmvert(bm, vm, 0, 0, k, bv->v); } copy_v3_v3(mesh_vert(vm, 0, 0, ns)->co, v2->co); - for (k = 1; k < ns; k++) { + for (int k = 1; k < ns; k++) { copy_mesh_vert(vm, 1, 0, ns - k, 0, 0, k); } } if (BM_vert_face_check(bv->v) == false) { - e_eg = bv->edges[0].e; + BMEdge *e_eg = bv->edges[0].e; BLI_assert(e_eg != NULL); - for (k = 0; k < ns; k++) { + for (int k = 0; k < ns; k++) { v1 = mesh_vert(vm, 0, 0, k)->v; v2 = mesh_vert(vm, 0, 0, k + 1)->v; BLI_assert(v1 != NULL && v2 != NULL); - bme = BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE); + BMEdge *bme = BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE); if (bme) { flag_out_edge(bm, bme); } @@ -5645,25 +5487,24 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) { VMesh *vm = bv->vmesh; - BoundVert *bndv, *weld1, *weld2, *vpipe; - int n, ns, ns2, i, k, weld; - float *v_weld1, *v_weld2, co[3]; + float co[3]; - n = vm->count; - ns = vm->seg; - ns2 = ns / 2; + int n = vm->count; + int ns = vm->seg; + int ns2 = ns / 2; vm->mesh = (NewVert *)BLI_memarena_alloc(bp->mem_arena, - (size_t)(n * (ns2 + 1) * (ns + 1)) * sizeof(NewVert)); + sizeof(NewVert) * n * (ns2 + 1) * (ns + 1)); /* Special case: just two beveled edges welded together. */ - weld = (bv->selcount == 2) && (vm->count == 2); - weld1 = weld2 = NULL; /* Will hold two BoundVerts involved in weld. */ + const bool weld = (bv->selcount == 2) && (vm->count == 2); + BoundVert *weld1 = NULL; /* Will hold two BoundVerts involved in weld. */ + BoundVert *weld2 = NULL; /* Make (i, 0, 0) mesh verts for all i boundverts. */ - bndv = vm->boundstart; + BoundVert *bndv = vm->boundstart; do { - i = bndv->index; + int i = bndv->index; copy_v3_v3(mesh_vert(vm, i, 0, 0)->co, bndv->nv.co); /* Mesh NewVert to boundary NewVert. */ create_mesh_bmvert(bm, vm, i, 0, 0, bv->v); /* Create BMVert for that NewVert. */ bndv->nv.v = mesh_vert(vm, i, 0, 0)->v; /* Use the BMVert for the BoundVert's NewVert. */ @@ -5690,12 +5531,12 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) /* Copy other ends to (i, 0, ns) for all i, and fill in profiles for edges. */ bndv = vm->boundstart; do { - i = bndv->index; + int i = bndv->index; /* bndv's last vert along the boundary arc is the first of the next BoundVert's arc. */ copy_mesh_vert(vm, i, 0, ns, bndv->next->index, 0, 0); if (vm->mesh_kind != M_ADJ) { - for (k = 1; k < ns; k++) { + for (int k = 1; k < ns; k++) { if (bndv->ebev) { get_profile_point(bp, &bndv->profile, k, ns, co); copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co); @@ -5716,9 +5557,9 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) /* Build the profile for the weld case (just a connection between the two boundverts). */ if (weld) { bv->vmesh->mesh_kind = M_NONE; - for (k = 1; k < ns; k++) { - v_weld1 = mesh_vert(bv->vmesh, weld1->index, 0, k)->co; - v_weld2 = mesh_vert(bv->vmesh, weld2->index, 0, ns - k)->co; + for (int k = 1; k < ns; k++) { + float *v_weld1 = mesh_vert(bv->vmesh, weld1->index, 0, k)->co; + float *v_weld2 = mesh_vert(bv->vmesh, weld2->index, 0, ns - k)->co; if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Don't bother with special case profile check from below. */ mid_v3_v3v3(co, v_weld1, v_weld2); @@ -5739,13 +5580,13 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) copy_v3_v3(mesh_vert(bv->vmesh, weld1->index, 0, k)->co, co); create_mesh_bmvert(bm, bv->vmesh, weld1->index, 0, k, bv->v); } - for (k = 1; k < ns; k++) { + for (int k = 1; k < ns; k++) { copy_mesh_vert(bv->vmesh, weld2->index, 0, ns - k, weld1->index, 0, k); } } /* Make sure the pipe case ADJ mesh is used for both the "Grid Fill" (ADJ) and cutoff options. */ - vpipe = NULL; + BoundVert *vpipe = NULL; if ((vm->count == 3 || vm->count == 4) && bp->seg > 1) { /* Result is passed to bevel_build_rings to avoid overhead. */ vpipe = pipe_test(bv); @@ -5801,44 +5642,43 @@ static float edge_face_angle(EdgeHalf *e) */ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i) { - BMEdge *bme, *bme2, *nextbme; - BMLoop *l; - BMIter iter; - int j, tryj, bestj, nsucs, sucindex, k; BMEdge **sucs = NULL; BMEdge **save_path = NULL; BLI_array_staticdeclare(sucs, 4); /* Likely very few faces attached to same edge. */ BLI_array_staticdeclare(save_path, BM_DEFAULT_NGON_STACK_SIZE); - bme = bv->edges[i].e; /* Fill sucs with all unmarked edges of bmesh. */ + BMEdge *bme = bv->edges[i].e; + BMIter iter; + BMLoop *l; BM_ITER_ELEM (l, &iter, bme, BM_LOOPS_OF_EDGE) { - bme2 = (l->v == bv->v) ? l->prev->e : l->next->e; + BMEdge *bme2 = (l->v == bv->v) ? l->prev->e : l->next->e; if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) { BLI_array_append(sucs, bme2); } } - nsucs = BLI_array_len(sucs); + int nsucs = BLI_array_len(sucs); - bestj = j = i; - for (sucindex = 0; sucindex < nsucs; sucindex++) { - nextbme = sucs[sucindex]; + int bestj = i; + int j = i; + for (int sucindex = 0; sucindex < nsucs; sucindex++) { + BMEdge *nextbme = sucs[sucindex]; BLI_assert(nextbme != NULL); BLI_assert(!BM_BEVEL_EDGE_TAG_TEST(nextbme)); BLI_assert(j + 1 < bv->edgecount); bv->edges[j + 1].e = nextbme; BM_BEVEL_EDGE_TAG_ENABLE(nextbme); - tryj = bevel_edge_order_extend(bm, bv, j + 1); + int tryj = bevel_edge_order_extend(bm, bv, j + 1); if (tryj > bestj || (tryj == bestj && edges_face_connected_at_vert(bv->edges[tryj].e, bv->edges[0].e))) { bestj = tryj; BLI_array_clear(save_path); - for (k = j + 1; k <= bestj; k++) { + for (int k = j + 1; k <= bestj; k++) { BLI_array_append(save_path, bv->edges[k].e); } } /* Now reset to path only-going-to-j state. */ - for (k = j + 1; k <= tryj; k++) { + for (int k = j + 1; k <= tryj; k++) { BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e); bv->edges[k].e = NULL; } @@ -5847,7 +5687,7 @@ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i) if (bestj > j) { /* Save_path should have from j + 1 to bestj inclusive. * Edges to add to edges[] before returning. */ - for (k = j + 1; k <= bestj; k++) { + for (int k = j + 1; k <= bestj; k++) { BLI_assert(save_path[k - (j + 1)] != NULL); bv->edges[k].e = save_path[k - (j + 1)]; BM_BEVEL_EDGE_TAG_ENABLE(bv->edges[k].e); @@ -5873,17 +5713,14 @@ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i) * so for now will continue to use the legacy code. */ static bool fast_bevel_edge_order(BevVert *bv) { - int j, k, nsucs; - BMEdge *bme, *bme2, *bmenext; - BMIter iter; - BMLoop *l; - - for (j = 1; j < bv->edgecount; j++) { - bme = bv->edges[j - 1].e; - bmenext = NULL; - nsucs = 0; + for (int j = 1; j < bv->edgecount; j++) { + BMEdge *bme = bv->edges[j - 1].e; + BMEdge *bmenext = NULL; + int nsucs = 0; + BMIter iter; + BMLoop *l; BM_ITER_ELEM (l, &iter, bme, BM_LOOPS_OF_EDGE) { - bme2 = (l->v == bv->v) ? l->prev->e : l->next->e; + BMEdge *bme2 = (l->v == bv->v) ? l->prev->e : l->next->e; if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) { nsucs++; if (bmenext == NULL) { @@ -5893,7 +5730,7 @@ static bool fast_bevel_edge_order(BevVert *bv) } if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 || (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e))) { - for (k = 1; k < j; k++) { + for (int k = 1; k < j; k++) { BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e); bv->edges[k].e = NULL; } @@ -5907,29 +5744,29 @@ static bool fast_bevel_edge_order(BevVert *bv) #else static bool fast_bevel_edge_order(BevVert *bv) { - BMEdge *bme, *bme2, *first_suc; - BMIter iter, iter2; - BMFace *f; - EdgeHalf *e; - int i, k, ntot, num_shared_face; - - ntot = bv->edgecount; + int ntot = bv->edgecount; /* Add edges to bv->edges in order that keeps adjacent edges sharing * a unique face, if possible. */ - e = &bv->edges[0]; - bme = e->e; + EdgeHalf *e = &bv->edges[0]; + BMEdge *bme = e->e; if (!bme->l) { return false; } - for (i = 1; i < ntot; i++) { + + for (int i = 1; i < ntot; i++) { /* Find an unflagged edge bme2 that shares a face f with previous bme. */ - num_shared_face = 0; - first_suc = NULL; /* Keep track of first successor to match legacy behavior. */ + int num_shared_face = 0; + BMEdge *first_suc = NULL; /* Keep track of first successor to match legacy behavior. */ + BMIter iter; + BMEdge *bme2; BM_ITER_ELEM (bme2, &iter, bv->v, BM_EDGES_OF_VERT) { if (BM_BEVEL_EDGE_TAG_TEST(bme2)) { continue; } + + BMIter iter2; + BMFace *f; BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) { if (BM_face_edge_share_loop(f, bme)) { num_shared_face++; @@ -5948,7 +5785,7 @@ static bool fast_bevel_edge_order(BevVert *bv) BM_BEVEL_EDGE_TAG_ENABLE(bme); } else { - for (k = 1; k < i; k++) { + for (int k = 1; k < i; k++) { BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e); bv->edges[k].e = NULL; } @@ -5964,17 +5801,8 @@ static bool fast_bevel_edge_order(BevVert *bv) * first_bme is a good edge to start with. */ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) { - BMEdge *bme, *bme2; - BMIter iter; - BMFace *f, *bestf; - EdgeHalf *e; - EdgeHalf *e2; - BMLoop *l; - int i, ntot; - - ntot = bv->edgecount; - i = 0; - for (;;) { + int ntot = bv->edgecount; + for (int i = 0;;) { BLI_assert(first_bme != NULL); bv->edges[i].e = first_bme; BM_BEVEL_EDGE_TAG_ENABLE(first_bme); @@ -5988,6 +5816,8 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) } /* Not done yet: find a new first_bme. */ first_bme = NULL; + BMIter iter; + BMEdge *bme; BM_ITER_ELEM (bme, &iter, bv->v, BM_EDGES_OF_VERT) { if (BM_BEVEL_EDGE_TAG_TEST(bme)) { continue; @@ -6002,11 +5832,11 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) } } /* Now fill in the faces. */ - for (i = 0; i < ntot; i++) { - e = &bv->edges[i]; - e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1]; - bme = e->e; - bme2 = e2->e; + for (int i = 0; i < ntot; i++) { + EdgeHalf *e = &bv->edges[i]; + EdgeHalf *e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1]; + BMEdge *bme = e->e; + BMEdge *bme2 = e2->e; BLI_assert(bme != NULL); if (e->fnext != NULL || e2->fprev != NULL) { continue; @@ -6014,9 +5844,11 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) /* Which faces have successive loops that are for bme and bme2? * There could be more than one. E.g., in manifold ntot==2 case. * Prefer one that has loop in same direction as e. */ - bestf = NULL; + BMFace *bestf = NULL; + BMIter iter; + BMLoop *l; BM_ITER_ELEM (l, &iter, bme, BM_LOOPS_OF_EDGE) { - f = l->f; + BMFace *f = l->f; if ((l->prev->e == bme2 || l->next->e == bme2)) { if (!bestf || l->v == bv->v) { bestf = f; @@ -6032,19 +5864,6 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) /* Construction around the vertex. */ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) { - BMEdge *bme; - BevVert *bv; - BMEdge *first_bme; - BMVert *v1, *v2; - BMIter iter; - EdgeHalf *e; - float weight, z; - float vert_axis[3] = {0, 0, 0}; - int i, ccw_test_sum; - int nsel = 0; - int tot_edges = 0; - int tot_wire = 0; - /* Gather input selected edges. * Only bevel selected edges that have exactly two incident faces. * Want edges to be ordered so that they share faces. @@ -6053,7 +5872,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) * Want to ignore wire edges completely for edge beveling. * TODO: make following work when more than one gap. */ - first_bme = NULL; + int nsel = 0; + int tot_edges = 0; + int tot_wire = 0; + BMEdge *first_bme = NULL; + BMIter iter; + BMEdge *bme; BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { int face_count = BM_edge_face_count(bme); BM_BEVEL_EDGE_TAG_DISABLE(bme); @@ -6091,15 +5915,15 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) return NULL; } - bv = (BevVert *)BLI_memarena_alloc(bp->mem_arena, (sizeof(BevVert))); + BevVert *bv = (BevVert *)BLI_memarena_alloc(bp->mem_arena, sizeof(BevVert)); bv->v = v; bv->edgecount = tot_edges; bv->selcount = nsel; bv->wirecount = tot_wire; bv->offset = bp->offset; - bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, tot_edges * sizeof(EdgeHalf)); + bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, sizeof(EdgeHalf) * tot_edges); if (tot_wire) { - bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, tot_wire * sizeof(BMEdge *)); + bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, sizeof(BMEdge *) * tot_wire); } else { bv->wire_edges = NULL; @@ -6112,8 +5936,8 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) find_bevel_edge_order(bm, bv, first_bme); /* Fill in other attributes of EdgeHalfs. */ - for (i = 0; i < tot_edges; i++) { - e = &bv->edges[i]; + for (int i = 0; i < tot_edges; i++) { + EdgeHalf *e = &bv->edges[i]; bme = e->e; if (BM_elem_flag_test(bme, BM_ELEM_TAG) && bp->affect_type != BEVEL_AFFECT_VERTICES) { e->is_bev = true; @@ -6136,24 +5960,26 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) /* If edge array doesn't go CCW around vertex from average normal side, * reverse the array, being careful to reverse face pointers too. */ if (tot_edges > 1) { - ccw_test_sum = 0; - for (i = 0; i < tot_edges; i++) { + int ccw_test_sum = 0; + for (int i = 0; i < tot_edges; i++) { ccw_test_sum += bev_ccw_test( bv->edges[i].e, bv->edges[(i + 1) % tot_edges].e, bv->edges[i].fnext); } if (ccw_test_sum < 0) { - for (i = 0; i <= (tot_edges / 2) - 1; i++) { + for (int i = 0; i <= (tot_edges / 2) - 1; i++) { SWAP(EdgeHalf, bv->edges[i], bv->edges[tot_edges - i - 1]); SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); SWAP(BMFace *, bv->edges[tot_edges - i - 1].fprev, bv->edges[tot_edges - i - 1].fnext); } if (tot_edges % 2 == 1) { - i = tot_edges / 2; + int i = tot_edges / 2; SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); } } } + float weight; + float vert_axis[3] = {0, 0, 0}; if (bp->affect_type == BEVEL_AFFECT_VERTICES) { /* Modify the offset by the vertex group or bevel weight if they are specified. */ if (bp->dvert != NULL && bp->vertex_group != -1) { @@ -6167,8 +5993,9 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) /* Find center axis. Note: Don't use vert normal, can give unwanted results. */ if (ELEM(bp->offset_type, BEVEL_AMT_WIDTH, BEVEL_AMT_DEPTH)) { float edge_dir[3]; - for (i = 0, e = bv->edges; i < tot_edges; i++, e++) { - v2 = BM_edge_other_vert(e->e, bv->v); + EdgeHalf *e = bv->edges; + for (int i = 0; i < tot_edges; i++, e++) { + BMVert *v2 = BM_edge_other_vert(e->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, v2->co); normalize_v3(edge_dir); add_v3_v3v3(vert_axis, vert_axis, edge_dir); @@ -6177,7 +6004,8 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } /* Set offsets for each beveled edge. */ - for (i = 0, e = bv->edges; i < tot_edges; i++, e++) { + EdgeHalf *e = bv->edges; + for (int i = 0; i < tot_edges; i++, e++) { e->next = &bv->edges[(i + 1) % tot_edges]; e->prev = &bv->edges[(i + tot_edges - 1) % tot_edges]; @@ -6187,11 +6015,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) * Except for percent method, offset will be same on each side. */ switch (bp->offset_type) { - case BEVEL_AMT_OFFSET: + case BEVEL_AMT_OFFSET: { e->offset_l_spec = bp->offset; break; - case BEVEL_AMT_WIDTH: - z = fabsf(2.0f * sinf(edge_face_angle(e) / 2.0f)); + } + case BEVEL_AMT_WIDTH: { + float z = fabsf(2.0f * sinf(edge_face_angle(e) / 2.0f)); if (z < BEVEL_EPSILON) { e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */ } @@ -6199,8 +6028,9 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) e->offset_l_spec = bp->offset / z; } break; - case BEVEL_AMT_DEPTH: - z = fabsf(cosf(edge_face_angle(e) / 2.0f)); + } + case BEVEL_AMT_DEPTH: { + float z = fabsf(cosf(edge_face_angle(e) / 2.0f)); if (z < BEVEL_EPSILON) { e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */ } @@ -6208,32 +6038,36 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) e->offset_l_spec = bp->offset / z; } break; - case BEVEL_AMT_PERCENT: + } + case BEVEL_AMT_PERCENT: { /* Offset needs to meet adjacent edges at percentage of their lengths. */ - v1 = BM_edge_other_vert(e->prev->e, v); - v2 = BM_edge_other_vert(e->e, v); - z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); + BMVert *v1 = BM_edge_other_vert(e->prev->e, v); + BMVert *v2 = BM_edge_other_vert(e->e, v); + float z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); e->offset_l_spec = BM_edge_calc_length(e->prev->e) * bp->offset * z / 100.0f; v1 = BM_edge_other_vert(e->e, v); v2 = BM_edge_other_vert(e->next->e, v); z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); e->offset_r_spec = BM_edge_calc_length(e->next->e) * bp->offset * z / 100.0f; break; - case BEVEL_AMT_ABSOLUTE: + } + case BEVEL_AMT_ABSOLUTE: { /* Like Percent, but the amount gives the absolute distance along adjacent edges. */ - v1 = BM_edge_other_vert(e->prev->e, v); - v2 = BM_edge_other_vert(e->e, v); - z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); + BMVert *v1 = BM_edge_other_vert(e->prev->e, v); + BMVert *v2 = BM_edge_other_vert(e->e, v); + float z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); e->offset_l_spec = bp->offset * z; v1 = BM_edge_other_vert(e->e, v); v2 = BM_edge_other_vert(e->next->e, v); z = sinf(angle_v3v3v3(v1->co, v->co, v2->co)); e->offset_r_spec = bp->offset * z; break; - default: + } + default: { BLI_assert(!"bad bevel offset kind"); e->offset_l_spec = bp->offset; break; + } } if (bp->offset_type != BEVEL_AMT_PERCENT && bp->offset_type != BEVEL_AMT_ABSOLUTE) { e->offset_r_spec = e->offset_l_spec; @@ -6254,9 +6088,9 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) break; } case BEVEL_AMT_WIDTH: { - v2 = BM_edge_other_vert(e->e, bv->v); + BMVert *v2 = BM_edge_other_vert(e->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, v2->co); - z = fabsf(2.0f * sinf(angle_v3v3(vert_axis, edge_dir))); + float z = fabsf(2.0f * sinf(angle_v3v3(vert_axis, edge_dir))); if (z < BEVEL_EPSILON) { e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */ } @@ -6266,9 +6100,9 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) break; } case BEVEL_AMT_DEPTH: { - v2 = BM_edge_other_vert(e->e, bv->v); + BMVert *v2 = BM_edge_other_vert(e->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, v2->co); - z = fabsf(cosf(angle_v3v3(vert_axis, edge_dir))); + float z = fabsf(cosf(angle_v3v3(vert_axis, edge_dir))); if (z < BEVEL_EPSILON) { e->offset_l_spec = 0.01f * bp->offset; /* Undefined behavior, so tiny bevel. */ } @@ -6303,8 +6137,8 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } /* Collect wire edges if we found any earlier. */ - if (tot_wire) { - i = 0; + if (tot_wire != 0) { + int i = 0; BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_wire(bme)) { BLI_assert(i < bv->wirecount); @@ -6320,18 +6154,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) /* Face f has at least one beveled vertex. Rebuild f. */ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) { - BMIter liter, eiter, fiter; - BMLoop *l, *lprev; - BevVert *bv; - BoundVert *v, *vstart, *vend; - EdgeHalf *e, *eprev; - VMesh *vm; - int i, k, n, kstart, kend; bool do_rebuild = false; - bool go_ccw, corner3special, keep, on_profile_start; - BMVert *bmv; - BMEdge *bme, *bme_new, *bme_prev; - BMFace *f_new, *f_other; BMVert **vv = NULL; BMVert **vv_fix = NULL; BMEdge **ee = NULL; @@ -6339,18 +6162,21 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) BLI_array_staticdeclare(vv_fix, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(ee, BM_DEFAULT_NGON_STACK_SIZE); + BMIter liter; + BMLoop *l; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - lprev = l->prev; - bv = find_bevvert(bp, l->v); - vm = bv->vmesh; - e = find_edge_half(bv, l->e); + BMLoop *lprev = l->prev; + BevVert *bv = find_bevvert(bp, l->v); + VMesh *vm = bv->vmesh; + EdgeHalf *e = find_edge_half(bv, l->e); BLI_assert(e != NULL); - bme = e->e; - eprev = find_edge_half(bv, lprev->e); + BMEdge *bme = e->e; + EdgeHalf *eprev = find_edge_half(bv, lprev->e); BLI_assert(eprev != NULL); /* Which direction around our vertex do we travel to match orientation of f? */ + bool go_ccw; if (e->prev == eprev) { if (eprev->prev == e) { /* Valence 2 vertex: use f is one of e->fnext or e->fprev to break tie. */ @@ -6375,7 +6201,9 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) go_ccw = false; } } - on_profile_start = false; + bool on_profile_start = false; + BoundVert *vstart; + BoundVert *vend; if (go_ccw) { vstart = eprev->rightv; vend = e->leftv; @@ -6393,16 +6221,17 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) } } BLI_assert(vstart != NULL && vend != NULL); - v = vstart; + BoundVert *v = vstart; if (!on_profile_start) { BLI_array_append(vv, v->nv.v); BLI_array_append(ee, bme); } while (v != vend) { /* Check for special case: multisegment 3rd face opposite a beveled edge with no vmesh. */ - corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev); + bool corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev); if (go_ccw) { - i = v->index; + int i = v->index; + int kstart, kend; if (on_profile_start) { kstart = e->profile_index; on_profile_start = false; @@ -6416,8 +6245,8 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) else { kend = vm->seg; } - for (k = kstart; k <= kend; k++) { - bmv = mesh_vert(vm, i, 0, k)->v; + for (int k = kstart; k <= kend; k++) { + BMVert *bmv = mesh_vert(vm, i, 0, k)->v; if (bmv) { BLI_array_append(vv, bmv); BLI_array_append(ee, bme); /* TODO: Maybe better edge here. */ @@ -6430,7 +6259,8 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) } else { /* Going cw. */ - i = v->prev->index; + int i = v->prev->index; + int kstart, kend; if (on_profile_start) { kstart = eprev->profile_index; on_profile_start = false; @@ -6444,8 +6274,8 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) else { kend = 0; } - for (k = kstart; k >= kend; k--) { - bmv = mesh_vert(vm, i, 0, k)->v; + for (int k = kstart; k >= kend; k--) { + BMVert *bmv = mesh_vert(vm, i, 0, k)->v; if (bmv) { BLI_array_append(vv, bmv); BLI_array_append(ee, bme); @@ -6465,18 +6295,18 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) } } if (do_rebuild) { - n = BLI_array_len(vv); - f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true); + int n = BLI_array_len(vv); + BMFace *f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true); - for (k = 0; k < BLI_array_len(vv_fix); k++) { + for (int k = 0; k < BLI_array_len(vv_fix); k++) { bev_merge_uvs(bm, vv_fix[k]); } /* Copy attributes from old edges. */ BLI_assert(n == BLI_array_len(ee)); - bme_prev = ee[n - 1]; - for (k = 0; k < n; k++) { - bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]); + BMEdge *bme_prev = ee[n - 1]; + for (int k = 0; k < n; k++) { + BMEdge *bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]); BLI_assert(ee[k] && bme_new); if (ee[k] != bme_new) { BM_elem_attrs_copy(bm, bm, ee[k], bme_new); @@ -6504,8 +6334,12 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) record_face_kind(bp, f_new, F_RECON); BM_elem_flag_disable(f_new, BM_ELEM_TAG); /* Also don't want new edges that aren't part of a new bevel face. */ + BMIter eiter; + BMEdge *bme; BM_ITER_ELEM (bme, &eiter, f_new, BM_EDGES_OF_FACE) { - keep = false; + bool keep = false; + BMIter fiter; + BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, bme, BM_FACES_OF_EDGE) { if (BM_elem_flag_test(f_other, BM_ELEM_TAG)) { keep = true; @@ -6550,38 +6384,31 @@ static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert * /* If there were any wire edges, they need to be reattached somewhere. */ static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v) { - BMEdge *e; - BMVert *vclosest, *vother, *votherclosest; - BevVert *bv, *bvother; - BoundVert *bndv, *bndvother; - float d, dclosest; - int i; - - bv = find_bevvert(bp, v); + BevVert *bv = find_bevvert(bp, v); if (!bv || bv->wirecount == 0 || !bv->vmesh) { return; } - for (i = 0; i < bv->wirecount; i++) { - e = bv->wire_edges[i]; + for (int i = 0; i < bv->wirecount; i++) { + BMEdge *e = bv->wire_edges[i]; /* Look for the new vertex closest to the other end of e. */ - vclosest = NULL; - dclosest = FLT_MAX; - votherclosest = NULL; - vother = BM_edge_other_vert(e, v); - bvother = NULL; + BMVert *vclosest = NULL; + float dclosest = FLT_MAX; + BMVert *votherclosest = NULL; + BMVert *vother = BM_edge_other_vert(e, v); + BevVert *bvother = NULL; if (BM_elem_flag_test(vother, BM_ELEM_TAG)) { bvother = find_bevvert(bp, vother); if (!bvother || !bvother->vmesh) { return; /* Shouldn't happen. */ } } - bndv = bv->vmesh->boundstart; + BoundVert *bndv = bv->vmesh->boundstart; do { if (bvother) { - bndvother = bvother->vmesh->boundstart; + BoundVert *bndvother = bvother->vmesh->boundstart; do { - d = len_squared_v3v3(bndvother->nv.co, bndv->nv.co); + float d = len_squared_v3v3(bndvother->nv.co, bndv->nv.co); if (d < dclosest) { vclosest = bndv->nv.v; votherclosest = bndvother->nv.v; @@ -6590,7 +6417,7 @@ static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v) } while ((bndvother = bndvother->next) != bvother->vmesh->boundstart); } else { - d = len_squared_v3v3(vother->co, bndv->nv.co); + float d = len_squared_v3v3(vother->co, bndv->nv.co); if (d < dclosest) { vclosest = bndv->nv.v; votherclosest = vother; @@ -6607,11 +6434,10 @@ static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v) static void bev_merge_end_uvs(BMesh *bm, BevVert *bv, EdgeHalf *e) { VMesh *vm = bv->vmesh; - int i, k, nseg; - nseg = e->seg; - i = e->leftv->index; - for (k = 1; k < nseg; k++) { + int nseg = e->seg; + int i = e->leftv->index; + for (int k = 1; k < nseg; k++) { bev_merge_uvs(bm, mesh_vert(vm, i, 0, k)->v); } } @@ -6648,12 +6474,9 @@ static bool bevvert_is_weld_cross(BevVert *bv) */ static void weld_cross_attrs_copy(BMesh *bm, BevVert *bv, VMesh *vm, int vmindex, EdgeHalf *e) { - BMEdge *bme_prev, *bme_next, *bme; - int i, nseg; - bool disable_seam, enable_smooth; - - bme_prev = bme_next = NULL; - for (i = 0; i < 4; i++) { + BMEdge *bme_prev = NULL; + BMEdge *bme_next = NULL; + for (int i = 0; i < 4; i++) { if (&bv->edges[i] == e) { bme_prev = bv->edges[(i + 3) % 4].e; bme_next = bv->edges[(i + 1) % 4].e; @@ -6663,14 +6486,15 @@ static void weld_cross_attrs_copy(BMesh *bm, BevVert *bv, VMesh *vm, int vmindex BLI_assert(bme_prev && bme_next); /* Want seams and sharp edges to cross only if that way on both sides. */ - disable_seam = BM_elem_flag_test(bme_prev, BM_ELEM_SEAM) != - BM_elem_flag_test(bme_next, BM_ELEM_SEAM); - enable_smooth = BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH) != - BM_elem_flag_test(bme_next, BM_ELEM_SMOOTH); - - nseg = e->seg; - for (i = 0; i < nseg; i++) { - bme = BM_edge_exists(mesh_vert(vm, vmindex, 0, i)->v, mesh_vert(vm, vmindex, 0, i + 1)->v); + bool disable_seam = BM_elem_flag_test(bme_prev, BM_ELEM_SEAM) != + BM_elem_flag_test(bme_next, BM_ELEM_SEAM); + bool enable_smooth = BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH) != + BM_elem_flag_test(bme_next, BM_ELEM_SMOOTH); + + int nseg = e->seg; + for (int i = 0; i < nseg; i++) { + BMEdge *bme = BM_edge_exists(mesh_vert(vm, vmindex, 0, i)->v, + mesh_vert(vm, vmindex, 0, i + 1)->v); BLI_assert(bme); BM_elem_attrs_copy(bm, bm, bme_prev, bme); if (disable_seam) { @@ -6687,31 +6511,19 @@ static void weld_cross_attrs_copy(BMesh *bm, BevVert *bv, VMesh *vm, int vmindex */ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) { - BevVert *bv1, *bv2; - BMVert *bmv1, *bmv2, *bmv3, *bmv4; - VMesh *vm1, *vm2; - EdgeHalf *e1, *e2; - BMEdge *bme1, *bme2, *center_bme; - BMFace *f1, *f2, *f, *r_f, *f_choice; - BMVert *verts[4]; - BMFace *faces[4]; - BMEdge *edges[4]; - BMLoop *l; - BMIter iter; - int k, nseg, i1, i2, odd, mid; int mat_nr = bp->mat_nr; if (!BM_edge_is_manifold(bme)) { return; } - bv1 = find_bevvert(bp, bme->v1); - bv2 = find_bevvert(bp, bme->v2); + BevVert *bv1 = find_bevvert(bp, bme->v1); + BevVert *bv2 = find_bevvert(bp, bme->v2); BLI_assert(bv1 && bv2); - e1 = find_edge_half(bv1, bme); - e2 = find_edge_half(bv2, bme); + EdgeHalf *e1 = find_edge_half(bv1, bme); + EdgeHalf *e2 = find_edge_half(bv2, bme); BLI_assert(e1 && e2); @@ -6725,40 +6537,43 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) * \ | / * bme->v2 */ - nseg = e1->seg; + int nseg = e1->seg; BLI_assert(nseg > 0 && nseg == e2->seg); - bmv1 = e1->leftv->nv.v; - bmv4 = e1->rightv->nv.v; - bmv2 = e2->rightv->nv.v; - bmv3 = e2->leftv->nv.v; + BMVert *bmv1 = e1->leftv->nv.v; + BMVert *bmv4 = e1->rightv->nv.v; + BMVert *bmv2 = e2->rightv->nv.v; + BMVert *bmv3 = e2->leftv->nv.v; BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); - f1 = e1->fprev; - f2 = e1->fnext; - faces[0] = faces[1] = f1; - faces[2] = faces[3] = f2; - i1 = e1->leftv->index; - i2 = e2->leftv->index; - vm1 = bv1->vmesh; - vm2 = bv2->vmesh; + BMFace *f1 = e1->fprev; + BMFace *f2 = e1->fnext; + BMFace *faces[4] = {f1, f1, f2, f2}; + + int i1 = e1->leftv->index; + int i2 = e2->leftv->index; + VMesh *vm1 = bv1->vmesh; + VMesh *vm2 = bv2->vmesh; + BMVert *verts[4]; verts[0] = bmv1; verts[1] = bmv2; - odd = nseg % 2; - mid = nseg / 2; - center_bme = NULL; - for (k = 1; k <= nseg; k++) { + int odd = nseg % 2; + int mid = nseg / 2; + BMEdge *center_bme = NULL; + for (int k = 1; k <= nseg; k++) { verts[3] = mesh_vert(vm1, i1, 0, k)->v; verts[2] = mesh_vert(vm2, i2, 0, nseg - k)->v; + BMFace *r_f; if (odd && k == mid + 1) { BMFace *fchoices[2] = {f1, f2}; - f_choice = choose_rep_face(bp, fchoices, 2); + BMFace *f_choice = choose_rep_face(bp, fchoices, 2); if (e1->is_seam) { /* Straddles a seam: choose to interpolate in f_choice and snap the loops whose verts * are in the non-chosen face to bme for interpolation purposes. */ + BMEdge *edges[4]; if (f_choice == f1) { edges[0] = edges[1] = NULL; edges[2] = edges[3] = bme; @@ -6776,25 +6591,25 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) } else if (!odd && k == mid) { /* Left poly that touches an even center line on right. */ - edges[0] = edges[1] = NULL; - edges[2] = edges[3] = bme; + BMEdge *edges[4] = {NULL, NULL, bme, bme}; r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true); center_bme = BM_edge_exists(verts[2], verts[3]); BLI_assert(center_bme != NULL); } else if (!odd && k == mid + 1) { /* Right poly that touches an even center line on left. */ - edges[0] = edges[1] = bme; - edges[2] = edges[3] = NULL; + BMEdge *edges[4] = {bme, bme, NULL, NULL}; r_f = bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true); } else { /* Doesn't cross or touch the center line, so interpolate in appropriate f1 or f2. */ - f = (k <= mid) ? f1 : f2; + BMFace *f = (k <= mid) ? f1 : f2; r_f = bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true); } record_face_kind(bp, r_f, F_EDGE); /* Tag the long edges: those out of verts[0] and verts[2]. */ + BMIter iter; + BMLoop *l; BM_ITER_ELEM (l, &iter, r_f, BM_LOOPS_OF_FACE) { if (l->v == verts[0] || l->v == verts[2]) { BM_elem_flag_enable(l, BM_ELEM_LONG_TAG); @@ -6822,8 +6637,8 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) } /* Copy edge data to first and last edge. */ - bme1 = BM_edge_exists(bmv1, bmv2); - bme2 = BM_edge_exists(bmv3, bmv4); + BMEdge *bme1 = BM_edge_exists(bmv1, bmv2); + BMEdge *bme2 = BM_edge_exists(bmv3, bmv4); BLI_assert(bme1 && bme2); BM_elem_attrs_copy(bm, bm, bme, bme1); BM_elem_attrs_copy(bm, bm, bme, bme2); @@ -6843,34 +6658,32 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) * Assumes that the gradient is always between 1 and -1 for x in [x0, x0+dtarget]. */ static double find_superellipse_chord_endpoint(double x0, double dtarget, float r, bool rbig) { - double xmin, xmax, ymin, ymax, dmaxerr, dminerr, dnewerr, xnew, ynew; double y0 = superellipse_co(x0, r, rbig); const double tol = 1e-13; /* accumulates for many segments so use low value. */ const int maxiter = 10; - bool lastupdated_upper; /* For gradient between -1 and 1, xnew can only be in [x0 + sqrt(2)/2*dtarget, x0 + dtarget]. */ - xmin = x0 + M_SQRT2 / 2.0 * dtarget; + double xmin = x0 + M_SQRT2 / 2.0 * dtarget; if (xmin > 1.0) { xmin = 1.0; } - xmax = x0 + dtarget; + double xmax = x0 + dtarget; if (xmax > 1.0) { xmax = 1.0; } - ymin = superellipse_co(xmin, r, rbig); - ymax = superellipse_co(xmax, r, rbig); + double ymin = superellipse_co(xmin, r, rbig); + double ymax = superellipse_co(xmax, r, rbig); /* Note: using distance**2 (no sqrt needed) does not converge that well. */ - dmaxerr = sqrt(pow((xmax - x0), 2) + pow((ymax - y0), 2)) - dtarget; - dminerr = sqrt(pow((xmin - x0), 2) + pow((ymin - y0), 2)) - dtarget; + double dmaxerr = sqrt(pow((xmax - x0), 2) + pow((ymax - y0), 2)) - dtarget; + double dminerr = sqrt(pow((xmin - x0), 2) + pow((ymin - y0), 2)) - dtarget; - xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr); - lastupdated_upper = true; + double xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr); + bool lastupdated_upper = true; for (int iter = 0; iter < maxiter; iter++) { - ynew = superellipse_co(xnew, r, rbig); - dnewerr = sqrt(pow((xnew - x0), 2) + pow((ynew - y0), 2)) - dtarget; + double ynew = superellipse_co(xnew, r, rbig); + double dnewerr = sqrt(pow((xnew - x0), 2) + pow((ynew - y0), 2)) - dtarget; if (fabs(dnewerr) < tol) { break; } @@ -6915,19 +6728,12 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval { const int smoothitermax = 10; const double error_tol = 1e-7; - int i; int imax = (seg + 1) / 2 - 1; /* Ceiling division - 1. */ - double d, dmin, dmax; - double davg; - double mx; - double sum; - double temp; - - bool precision_reached = true; bool seg_odd = seg % 2; - bool rbig; + bool rbig; + double mx; if (r > 1.0f) { rbig = true; mx = pow(0.5, 1.0 / r); @@ -6938,7 +6744,7 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval } /* Initial positions, linear spacing along x axis. */ - for (i = 0; i <= imax; i++) { + for (int i = 0; i <= imax; i++) { xvals[i] = i * mx / seg * 2; yvals[i] = superellipse_co(xvals[i], r, rbig); } @@ -6946,14 +6752,14 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval /* Smooth distance loop. */ for (int iter = 0; iter < smoothitermax; iter++) { - sum = 0.0; - dmin = 2.0; - dmax = 0.0; + double sum = 0.0; + double dmin = 2.0; + double dmax = 0.0; /* Update distances between neighbor points. Store the highest and * lowest to see if the maximum error to average distance (which isn't * known yet) is below required precision. */ - for (i = 0; i < imax; i++) { - d = sqrt(pow((xvals[i + 1] - xvals[i]), 2) + pow((yvals[i + 1] - yvals[i]), 2)); + for (int i = 0; i < imax; i++) { + double d = sqrt(pow((xvals[i + 1] - xvals[i]), 2) + pow((yvals[i + 1] - yvals[i]), 2)); sum += d; if (d > dmax) { dmax = d; @@ -6963,6 +6769,7 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval } } /* For last distance, weight with 1/2 if seg_odd. */ + double davg; if (seg_odd) { sum += M_SQRT2 / 2 * (yvals[imax] - xvals[imax]); davg = sum / (imax + 0.5); @@ -6972,6 +6779,7 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval davg = sum / (imax + 1.0); } /* Max error in tolerance? -> Quit. */ + bool precision_reached = true; if (dmax - davg > error_tol) { precision_reached = false; } @@ -6983,7 +6791,7 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval } /* Update new coordinates. */ - for (i = 1; i <= imax; i++) { + for (int i = 1; i <= imax; i++) { xvals[i] = find_superellipse_chord_endpoint(xvals[i - 1], davg, r, rbig); yvals[i] = superellipse_co(xvals[i], r, rbig); } @@ -6994,14 +6802,14 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval xvals[imax + 1] = mx; yvals[imax + 1] = mx; } - for (i = imax + 1; i <= seg; i++) { + for (int i = imax + 1; i <= seg; i++) { yvals[i] = xvals[seg - i]; xvals[i] = yvals[seg - i]; } if (!rbig) { - for (i = 0; i <= seg; i++) { - temp = xvals[i]; + for (int i = 0; i <= seg; i++) { + double temp = xvals[i]; xvals[i] = 1.0 - yvals[i]; yvals[i] = 1.0 - temp; } @@ -7018,25 +6826,22 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval */ static void find_even_superellipse_chords(int n, float r, double *xvals, double *yvals) { - int i, n2; - double temp; bool seg_odd = n % 2; - - n2 = n / 2; + int n2 = n / 2; /* Special cases. */ if (r == PRO_LINE_R) { /* Linear spacing. */ - for (i = 0; i <= n; i++) { + for (int i = 0; i <= n; i++) { xvals[i] = (double)i / n; yvals[i] = 1.0 - (double)i / n; } return; } if (r == PRO_CIRCLE_R) { - temp = (M_PI / 2) / n; + double temp = (M_PI / 2) / n; /* Angle spacing. */ - for (i = 0; i <= n; i++) { + for (int i = 0; i <= n; i++) { xvals[i] = sin(i * temp); yvals[i] = cos(i * temp); } @@ -7045,7 +6850,7 @@ static void find_even_superellipse_chords(int n, float r, double *xvals, double if (r == PRO_SQUARE_IN_R) { /* n is even, distribute first and second half linear. */ if (!seg_odd) { - for (i = 0; i <= n2; i++) { + for (int i = 0; i <= n2; i++) { xvals[i] = 0.0; yvals[i] = 1.0 - (double)i / n2; xvals[n - i] = yvals[i]; @@ -7054,8 +6859,8 @@ static void find_even_superellipse_chords(int n, float r, double *xvals, double } /* n is odd, so get one corner-cut chord. */ else { - temp = 1.0 / (n2 + M_SQRT2 / 2.0); - for (i = 0; i <= n2; i++) { + double temp = 1.0 / (n2 + M_SQRT2 / 2.0); + for (int i = 0; i <= n2; i++) { xvals[i] = 0.0; yvals[i] = 1.0 - (double)i * temp; xvals[n - i] = yvals[i]; @@ -7067,7 +6872,7 @@ static void find_even_superellipse_chords(int n, float r, double *xvals, double if (r == PRO_SQUARE_R) { /* n is even, distribute first and second half linear. */ if (!seg_odd) { - for (i = 0; i <= n2; i++) { + for (int i = 0; i <= n2; i++) { xvals[i] = (double)i / n2; yvals[i] = 1.0; xvals[n - i] = yvals[i]; @@ -7076,8 +6881,8 @@ static void find_even_superellipse_chords(int n, float r, double *xvals, double } /* n is odd, so get one corner-cut chord. */ else { - temp = 1.0 / (n2 + M_SQRT2 / 2); - for (i = 0; i <= n2; i++) { + double temp = 1.0 / (n2 + M_SQRT2 / 2); + for (int i = 0; i <= n2; i++) { xvals[i] = (double)i * temp; yvals[i] = 1.0; xvals[n - i] = yvals[i]; @@ -7097,7 +6902,6 @@ static void find_even_superellipse_chords(int n, float r, double *xvals, double */ static float find_profile_fullness(BevelParams *bp) { - float fullness; int nseg = bp->seg; /* Precalculated fullness for circle profile radius and more common low seg values. */ @@ -7116,6 +6920,7 @@ static float find_profile_fullness(BevelParams *bp) 0.647f, /* 11 */ }; + float fullness; if (bp->profile_type == BEVEL_PROFILE_CUSTOM) { /* Set fullness to the average "height" of the profile's sampled points. */ fullness = 0.0f; @@ -7244,19 +7049,15 @@ static void set_profile_spacing(BevelParams *bp, ProfileSpacing *pro_spacing, bo */ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) { - EdgeHalf *ea, *ec, *ebother; - BevVert *bvc; - BMLoop *lb; - BMVert *va, *vb, *vc, *vd; - float ka, kb, kc, g, h, t, den, no_collide_offset, th1, th2, sin1, sin2, tan1, tan2, limit; - - limit = no_collide_offset = bp->offset + 1e6; + float no_collide_offset = bp->offset + 1e6; + float limit = no_collide_offset; if (bp->offset == 0.0f) { return no_collide_offset; } - kb = eb->offset_l_spec; - ea = eb->next; /* Note: this is in direction b --> a. */ - ka = ea->offset_r_spec; + float kb = eb->offset_l_spec; + EdgeHalf *ea = eb->next; /* Note: this is in direction b --> a. */ + float ka = ea->offset_r_spec; + BMVert *vb, *vc; if (eb->is_rev) { vc = eb->e->v1; vb = eb->e->v2; @@ -7265,9 +7066,12 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) vb = eb->e->v1; vc = eb->e->v2; } - va = ea->is_rev ? ea->e->v1 : ea->e->v2; - bvc = NULL; - ebother = find_other_end_edge_half(bp, eb, &bvc); + BMVert *va = ea->is_rev ? ea->e->v1 : ea->e->v2; + BevVert *bvc = NULL; + EdgeHalf *ebother = find_other_end_edge_half(bp, eb, &bvc); + EdgeHalf *ec; + BMVert *vd; + float kc; if (ebother != NULL) { ec = ebother->prev; /* Note: this is in direction c --> d. */ vc = bvc->v; @@ -7279,7 +7083,7 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) kc = 0.0f; ec = NULL; /* Find an edge from c that has same face. */ - lb = BM_face_edge_share_loop(eb->fnext, eb->e); + BMLoop *lb = BM_face_edge_share_loop(eb->fnext, eb->e); if (!lb) { return no_collide_offset; } @@ -7299,22 +7103,22 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) ka = ka / bp->offset; kb = kb / bp->offset; kc = kc / bp->offset; - th1 = angle_v3v3v3(va->co, vb->co, vc->co); - th2 = angle_v3v3v3(vb->co, vc->co, vd->co); + float th1 = angle_v3v3v3(va->co, vb->co, vc->co); + float th2 = angle_v3v3v3(vb->co, vc->co, vd->co); /* First calculate offset at which edge B collapses, which happens * when advancing clones of A, B, C all meet at a point. * This only happens if at least two of those three edges have non-zero k's. */ - sin1 = sinf(th1); - sin2 = sinf(th2); + float sin1 = sinf(th1); + float sin2 = sinf(th2); if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) { - tan1 = tanf(th1); - tan2 = tanf(th2); - g = tan1 * tan2; - h = sin1 * sin2; - den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2); + float tan1 = tanf(th1); + float tan2 = tanf(th2); + float g = tan1 * tan2; + float h = sin1 * sin2; + float den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2); if (den != 0.0f) { - t = BM_edge_calc_length(eb->e); + float t = BM_edge_calc_length(eb->e); t *= g * h / den; if (t >= 0.0f) { limit = t; @@ -7324,14 +7128,14 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) /* Now check edge slide cases. */ if (kb > 0.0f && ka == 0.0f /*&& bvb->selcount == 1 && bvb->edgecount > 2 */) { - t = BM_edge_calc_length(ea->e); + float t = BM_edge_calc_length(ea->e); t *= sin1 / kb; if (t >= 0.0f && t < limit) { limit = t; } } if (kb > 0.0f && kc == 0.0f /* && bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2 */) { - t = BM_edge_calc_length(ec->e); + float t = BM_edge_calc_length(ec->e); t *= sin2 / kb; if (t >= 0.0f && t < limit) { limit = t; @@ -7347,18 +7151,16 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) */ static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea) { - float limit, ka, kb, no_collide_offset, la, kab; - EdgeHalf *eb; - - limit = no_collide_offset = bp->offset + 1e6; + float no_collide_offset = bp->offset + 1e6; + float limit = no_collide_offset; if (bp->offset == 0.0f) { return no_collide_offset; } - ka = ea->offset_l_spec / bp->offset; - eb = find_other_end_edge_half(bp, ea, NULL); - kb = eb ? eb->offset_l_spec / bp->offset : 0.0f; - kab = ka + kb; - la = BM_edge_calc_length(ea->e); + float ka = ea->offset_l_spec / bp->offset; + EdgeHalf *eb = find_other_end_edge_half(bp, ea, NULL); + float kb = eb ? eb->offset_l_spec / bp->offset : 0.0f; + float kab = ka + kb; + float la = BM_edge_calc_length(ea->e); if (kab <= 0.0f) { return no_collide_offset; } @@ -7373,32 +7175,27 @@ static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea) */ static void bevel_limit_offset(BevelParams *bp, BMesh *bm) { - BevVert *bv; - EdgeHalf *eh; + float limited_offset = bp->offset; BMIter iter; BMVert *bmv; - float limited_offset, offset_factor, collision_offset; - int i; - - limited_offset = bp->offset; BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(bmv, BM_ELEM_TAG)) { continue; } - bv = find_bevvert(bp, bmv); + BevVert *bv = find_bevvert(bp, bmv); if (!bv) { continue; } - for (i = 0; i < bv->edgecount; i++) { - eh = &bv->edges[i]; + for (int i = 0; i < bv->edgecount; i++) { + EdgeHalf *eh = &bv->edges[i]; if (bp->affect_type == BEVEL_AFFECT_VERTICES) { - collision_offset = vertex_collide_offset(bp, eh); + float collision_offset = vertex_collide_offset(bp, eh); if (collision_offset < limited_offset) { limited_offset = collision_offset; } } else { - collision_offset = geometry_collide_offset(bp, eh); + float collision_offset = geometry_collide_offset(bp, eh); if (collision_offset < limited_offset) { limited_offset = collision_offset; } @@ -7412,17 +7209,17 @@ static void bevel_limit_offset(BevelParams *bp, BMesh *bm) * of the offset to have the effect of recalculating the specs * with the new limited_offset. */ - offset_factor = limited_offset / bp->offset; + float offset_factor = limited_offset / bp->offset; BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(bmv, BM_ELEM_TAG)) { continue; } - bv = find_bevvert(bp, bmv); + BevVert *bv = find_bevvert(bp, bmv); if (!bv) { continue; } - for (i = 0; i < bv->edgecount; i++) { - eh = &bv->edges[i]; + for (int i = 0; i < bv->edgecount; i++) { + EdgeHalf *eh = &bv->edges[i]; eh->offset_l_spec *= offset_factor; eh->offset_r_spec *= offset_factor; eh->offset_l *= offset_factor; @@ -7475,34 +7272,38 @@ void BM_mesh_bevel(BMesh *bm, BMFace *f; BMLoop *l; BevVert *bv; - BevelParams bp = {NULL}; - - bp.offset = offset; - bp.offset_type = offset_type; - bp.seg = segments; - bp.profile = profile; - bp.pro_super_r = -logf(2.0) / logf(sqrtf(profile)); /* Convert to superellipse exponent. */ - bp.affect_type = affect_type; - bp.use_weights = use_weights; - bp.loop_slide = loop_slide; - bp.limit_offset = limit_offset; - bp.offset_adjust = bp.affect_type != BEVEL_AFFECT_VERTICES && - !ELEM(offset_type, BEVEL_AMT_PERCENT, BEVEL_AMT_ABSOLUTE); - bp.dvert = dvert; - bp.vertex_group = vertex_group; - bp.mat_nr = mat; - bp.mark_seam = mark_seam; - bp.mark_sharp = mark_sharp; - bp.harden_normals = harden_normals; - bp.face_strength_mode = face_strength_mode; - bp.miter_outer = miter_outer; - bp.miter_inner = miter_inner; - bp.spread = spread; - bp.smoothresh = smoothresh; - bp.face_hash = NULL; - bp.profile_type = profile_type; - bp.custom_profile = custom_profile; - bp.vmesh_method = vmesh_method; + BevelParams bp = { + .offset = offset, + .offset_type = offset_type, + .seg = max_ii(segments, 1), + .profile = profile, + .pro_super_r = -logf(2.0) / logf(sqrtf(profile)), /* Convert to superellipse exponent. */ + .affect_type = affect_type, + .use_weights = use_weights, + .loop_slide = loop_slide, + .limit_offset = limit_offset, + .offset_adjust = (bp.affect_type != BEVEL_AFFECT_VERTICES) && + !ELEM(offset_type, BEVEL_AMT_PERCENT, BEVEL_AMT_ABSOLUTE), + .dvert = dvert, + .vertex_group = vertex_group, + .mat_nr = mat, + .mark_seam = mark_seam, + .mark_sharp = mark_sharp, + .harden_normals = harden_normals, + .face_strength_mode = face_strength_mode, + .miter_outer = miter_outer, + .miter_inner = miter_inner, + .spread = spread, + .smoothresh = smoothresh, + .face_hash = NULL, + .profile_type = profile_type, + .custom_profile = custom_profile, + .vmesh_method = vmesh_method, + }; + + if (bp.offset <= 0) { + return; + } #ifdef BEVEL_DEBUG_TIME double start_time = PIL_check_seconds_timer(); @@ -7514,10 +7315,6 @@ void BM_mesh_bevel(BMesh *bm, bp.miter_inner = BEVEL_MITER_SHARP; } - if (bp.seg <= 1) { - bp.seg = 1; - } - if (profile >= 0.950f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */ bp.pro_super_r = PRO_SQUARE_R; } @@ -7531,151 +7328,150 @@ void BM_mesh_bevel(BMesh *bm, bp.pro_super_r = PRO_SQUARE_IN_R; } - if (bp.offset > 0) { - /* Primary alloc. */ - bp.vert_hash = BLI_ghash_ptr_new(__func__); - bp.mem_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__); - BLI_memarena_use_calloc(bp.mem_arena); - - /* Get the 2D profile point locations from either the superellipse or the custom profile. */ - set_profile_spacing(&bp, &bp.pro_spacing, bp.profile_type == BEVEL_PROFILE_CUSTOM); + /* Primary alloc. */ + bp.vert_hash = BLI_ghash_ptr_new(__func__); + bp.mem_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__); + BLI_memarena_use_calloc(bp.mem_arena); - /* Get the 'fullness' of the profile for the ADJ vertex mesh method. */ - if (bp.seg > 1) { - bp.pro_spacing.fullness = find_profile_fullness(&bp); - } - - /* Get separate non-custom profile samples for the miter profiles if they are needed */ - if (bp.profile_type == BEVEL_PROFILE_CUSTOM && - (bp.miter_inner != BEVEL_MITER_SHARP || bp.miter_outer != BEVEL_MITER_SHARP)) { - set_profile_spacing(&bp, &bp.pro_spacing_miter, false); - } + /* Get the 2D profile point locations from either the superellipse or the custom profile. */ + set_profile_spacing(&bp, &bp.pro_spacing, bp.profile_type == BEVEL_PROFILE_CUSTOM); - bp.face_hash = BLI_ghash_ptr_new(__func__); - BLI_ghash_flag_set(bp.face_hash, GHASH_FLAG_ALLOW_DUPES); + /* Get the 'fullness' of the profile for the ADJ vertex mesh method. */ + if (bp.seg > 1) { + bp.pro_spacing.fullness = find_profile_fullness(&bp); + } - math_layer_info_init(&bp, bm); + /* Get separate non-custom profile samples for the miter profiles if they are needed */ + if (bp.profile_type == BEVEL_PROFILE_CUSTOM && + (bp.miter_inner != BEVEL_MITER_SHARP || bp.miter_outer != BEVEL_MITER_SHARP)) { + set_profile_spacing(&bp, &bp.pro_spacing_miter, false); + } - /* Analyze input vertices, sorting edges and assigning initial new vertex positions. */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - bv = bevel_vert_construct(bm, &bp, v); - if (!limit_offset && bv) { - build_boundary(&bp, bv, true); - } - } - } + bp.face_hash = BLI_ghash_ptr_new(__func__); + BLI_ghash_flag_set(bp.face_hash, GHASH_FLAG_ALLOW_DUPES); - /* Perhaps clamp offset to avoid geometry colliisions. */ - if (limit_offset) { - bevel_limit_offset(&bp, bm); + math_layer_info_init(&bp, bm); - /* Assign initial new vertex positions. */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - bv = find_bevvert(&bp, v); - if (bv) { - build_boundary(&bp, bv, true); - } - } + /* Analyze input vertices, sorting edges and assigning initial new vertex positions. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + bv = bevel_vert_construct(bm, &bp, v); + if (!limit_offset && bv) { + build_boundary(&bp, bv, true); } } + } - /* Perhaps do a pass to try to even out widths. */ - if (bp.offset_adjust) { - adjust_offsets(&bp, bm); - } - - /* Maintain consistent orientations for the asymmetrical custom profiles. */ - if (bp.profile_type == BEVEL_PROFILE_CUSTOM) { - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - regularize_profile_orientation(&bp, e); - } - } - } + /* Perhaps clamp offset to avoid geometry colliisions. */ + if (limit_offset) { + bevel_limit_offset(&bp, bm); - /* Build the meshes around vertices, now that positions are final. */ + /* Assign initial new vertex positions. */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { bv = find_bevvert(&bp, v); if (bv) { - build_vmesh(&bp, bm, bv); + build_boundary(&bp, bv, true); } } } + } - /* Build polygons for edges. */ - if (bp.affect_type != BEVEL_AFFECT_VERTICES) { - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - bevel_build_edge_polygons(bm, &bp, e); - } + /* Perhaps do a pass to try to even out widths. */ + if (bp.offset_adjust) { + adjust_offsets(&bp, bm); + } + + /* Maintain consistent orientations for the asymmetrical custom profiles. */ + if (bp.profile_type == BEVEL_PROFILE_CUSTOM) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + regularize_profile_orientation(&bp, e); } } + } - /* Extend edge data like sharp edges and precompute normals for harden. */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - bv = find_bevvert(&bp, v); - if (bv) { - bevel_extend_edge_data(bv); - } + /* Build the meshes around vertices, now that positions are final. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + bv = find_bevvert(&bp, v); + if (bv) { + build_vmesh(&bp, bm, bv); } } + } - /* Rebuild face polygons around affected vertices. */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - bevel_rebuild_existing_polygons(bm, &bp, v); - bevel_reattach_wires(bm, &bp, v); + /* Build polygons for edges. */ + if (bp.affect_type != BEVEL_AFFECT_VERTICES) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + bevel_build_edge_polygons(bm, &bp, e); } } + } - BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BLI_assert(find_bevvert(&bp, v) != NULL); - BM_vert_kill(bm, v); + /* Extend edge data like sharp edges and precompute normals for harden. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + bv = find_bevvert(&bp, v); + if (bv) { + bevel_extend_edge_data(bv); } } + } - if (bp.harden_normals) { - bevel_harden_normals(&bp, bm); - } - if (bp.face_strength_mode != BEVEL_FACE_STRENGTH_NONE) { - bevel_set_weighted_normal_face_strength(bm, &bp); + /* Rebuild face polygons around affected vertices. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + bevel_rebuild_existing_polygons(bm, &bp, v); + bevel_reattach_wires(bm, &bp, v); } + } - /* When called from operator (as opposed to modifier), bm->use_toolflags - * will be set, and we need to transfer the oflags to BM_ELEM_TAGs. */ - if (bm->use_toolflags) { - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_vert_flag_test(bm, v, VERT_OUT)) { - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - } - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_edge_flag_test(bm, e, EDGE_OUT)) { - BM_elem_flag_enable(e, BM_ELEM_TAG); - } - } + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BLI_assert(find_bevvert(&bp, v) != NULL); + BM_vert_kill(bm, v); } + } - /* Clear the BM_ELEM_LONG_TAG tags, which were only set on some edges in F_EDGE faces. */ - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (get_face_kind(&bp, f) != F_EDGE) { - continue; + if (bp.harden_normals) { + bevel_harden_normals(&bp, bm); + } + if (bp.face_strength_mode != BEVEL_FACE_STRENGTH_NONE) { + bevel_set_weighted_normal_face_strength(bm, &bp); + } + + /* When called from operator (as opposed to modifier), bm->use_toolflags + * will be set, and we need to transfer the oflags to BM_ELEM_TAGs. */ + if (bm->use_toolflags) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm, v, VERT_OUT)) { + BM_elem_flag_enable(v, BM_ELEM_TAG); } - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_elem_flag_disable(l, BM_ELEM_LONG_TAG); + } + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test(bm, e, EDGE_OUT)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); } } + } - /* Primary free. */ - BLI_ghash_free(bp.vert_hash, NULL, NULL); - BLI_ghash_free(bp.face_hash, NULL, NULL); - BLI_memarena_free(bp.mem_arena); + /* Clear the BM_ELEM_LONG_TAG tags, which were only set on some edges in F_EDGE faces. */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (get_face_kind(&bp, f) != F_EDGE) { + continue; + } + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l, BM_ELEM_LONG_TAG); + } } + + /* Primary free. */ + BLI_ghash_free(bp.vert_hash, NULL, NULL); + BLI_ghash_free(bp.face_hash, NULL, NULL); + BLI_memarena_free(bp.mem_arena); + #ifdef BEVEL_DEBUG_TIME double end_time = PIL_check_seconds_timer(); printf("BMESH BEVEL TIME = %.3f\n", end_time - start_time); diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp index 7a308ac47b9..38db080a154 100644 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp @@ -82,17 +82,32 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter, converter.addOperation(rotateOperation); converter.addOperation(psoperation); - converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0)); converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1)); converter.addLink(scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2)); - converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); converter.addLink(angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1)); - converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); converter.addLink(xAttribute->getOutputSocket(), translateOperation->getInputSocket(1)); converter.addLink(yAttribute->getOutputSocket(), translateOperation->getInputSocket(2)); - converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(), psoperation->getOutputSocket()); + + if (invert) { + // Translate -> Rotate -> Scale. + converter.mapInputSocket(imageInput, translateOperation->getInputSocket(0)); + + converter.addLink(translateOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); + converter.addLink(rotateOperation->getOutputSocket(), scaleOperation->getInputSocket(0)); + + converter.addLink(scaleOperation->getOutputSocket(), psoperation->getInputSocket(0)); + } + else { + // Scale -> Rotate -> Translate. + converter.mapInputSocket(imageInput, scaleOperation->getInputSocket(0)); + + converter.addLink(scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); + converter.addLink(rotateOperation->getOutputSocket(), translateOperation->getInputSocket(0)); + + converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0)); + } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h index b853ecd8e56..cab20dadc50 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h @@ -127,7 +127,7 @@ Relation *DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_ return nullptr; } -static bool rigidbody_object_depends_on_evaluated_geometry(const RigidBodyOb *rbo) +static inline bool rigidbody_object_depends_on_evaluated_geometry(const RigidBodyOb *rbo) { if (rbo == nullptr) { return false; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index ec18b429c2e..18b24179edf 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -311,7 +311,11 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, contains(prop_identifier, "rotation_axis_angle") || contains(prop_identifier, "rotation_euler") || contains(prop_identifier, "rotation_mode") || - contains(prop_identifier, "rotation_quaternion") || contains(prop_identifier, "scale")) { + contains(prop_identifier, "rotation_quaternion") || contains(prop_identifier, "scale") || + contains(prop_identifier, "delta_location") || + contains(prop_identifier, "delta_rotation_euler") || + contains(prop_identifier, "delta_rotation_quaternion") || + contains(prop_identifier, "delta_scale")) { node_identifier.type = NodeType::TRANSFORM; return node_identifier; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index d76f5991dac..0bf6c38bc89 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -292,7 +292,7 @@ bool id_copy_inplace_no_main(const ID *id, ID *newid) const ID_Type id_type = GS(id_for_copy->name); if (id_type == ID_OB) { const Object *object = reinterpret_cast<const Object *>(id_for_copy); - BKE_pose_check_uuids_unique_and_report(object->pose); + BKE_object_check_uuids_unique_and_report(object); } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc index 934403674a9..25bcf2bfe72 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc @@ -23,28 +23,14 @@ #include "intern/eval/deg_eval_runtime_backup_modifier.h" +#include "DNA_modifier_types.h" + namespace blender { namespace deg { -ModifierDataBackupID::ModifierDataBackupID(const Depsgraph * /*depsgraph*/) - : ModifierDataBackupID(nullptr, eModifierType_None) -{ -} - -ModifierDataBackupID::ModifierDataBackupID(ModifierData *modifier_data, ModifierType type) - : modifier_data(modifier_data), type(type) -{ -} - -bool operator==(const ModifierDataBackupID &a, const ModifierDataBackupID &b) -{ - return a.modifier_data == b.modifier_data && a.type == b.type; -} - -uint64_t ModifierDataBackupID::hash() const +ModifierDataBackup::ModifierDataBackup(ModifierData *modifier_data) + : type(static_cast<ModifierType>(modifier_data->type)), runtime(modifier_data->runtime) { - uintptr_t ptr = (uintptr_t)modifier_data; - return (ptr >> 4) ^ (uintptr_t)type; } } // namespace deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h index a5bdf2359ee..f02dc73c392 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h @@ -25,38 +25,18 @@ #include "BKE_modifier.h" -#include "intern/depsgraph_type.h" - struct ModifierData; namespace blender { namespace deg { -struct Depsgraph; - -/* Identifier used to match modifiers to backup/restore their runtime data. - * Identification is happening using original modifier data pointer and the - * modifier type. - * It is not enough to only pointer, since it's possible to have a situation - * when modifier is removed and a new one added, and due to memory allocation - * policy they might have same pointer. - * By adding type into matching we are at least ensuring that modifier will not - * try to interpret runtime data created by another modifier type. */ -class ModifierDataBackupID { +class ModifierDataBackup { public: - ModifierDataBackupID(const Depsgraph *depsgraph); - ModifierDataBackupID(ModifierData *modifier_data, ModifierType type); - - friend bool operator==(const ModifierDataBackupID &a, const ModifierDataBackupID &b); + explicit ModifierDataBackup(ModifierData *modifier_data); - uint64_t hash() const; - - ModifierData *modifier_data; ModifierType type; + void *runtime; }; -/* Storage for backed up runtime modifier data. */ -typedef Map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup; - } // namespace deg } // namespace blender diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc index 88334e41192..addee3dc539 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc @@ -62,21 +62,18 @@ void ObjectRuntimeBackup::init_from_object(Object *object) backup_pose_channel_runtime_data(object); } -inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data) -{ - return ModifierDataBackupID(modifier_data->orig_modifier_data, - static_cast<ModifierType>(modifier_data->type)); -} - void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object) { LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { if (modifier_data->runtime == nullptr) { continue; } + + const SessionUUID &session_uuid = modifier_data->session_uuid; + BLI_assert(BLI_session_uuid_is_generated(&session_uuid)); + BLI_assert(modifier_data->orig_modifier_data != nullptr); - ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); - modifier_runtime_data.add(modifier_data_id, modifier_data->runtime); + modifier_runtime_data.add(session_uuid, ModifierDataBackup(modifier_data)); modifier_data->runtime = nullptr; } } @@ -153,17 +150,17 @@ void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) { LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { BLI_assert(modifier_data->orig_modifier_data != nullptr); - ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); - void *runtime = modifier_runtime_data.pop_default(modifier_data_id, nullptr); - if (runtime != nullptr) { - modifier_data->runtime = runtime; + const SessionUUID &session_uuid = modifier_data->session_uuid; + optional<ModifierDataBackup> backup = modifier_runtime_data.pop_try(session_uuid); + if (backup.has_value()) { + modifier_data->runtime = backup->runtime; } } - for (ModifierRuntimeDataBackup::Item item : modifier_runtime_data.items()) { - const ModifierTypeInfo *modifier_type_info = BKE_modifier_get_info(item.key.type); + for (ModifierDataBackup &backup : modifier_runtime_data.values()) { + const ModifierTypeInfo *modifier_type_info = BKE_modifier_get_info(backup.type); BLI_assert(modifier_type_info != nullptr); - modifier_type_info->freeRuntimeData(item.value); + modifier_type_info->freeRuntimeData(backup.runtime); } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h index a10f15634ce..5f6b443a2b2 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h @@ -36,6 +36,8 @@ struct Object; namespace blender { namespace deg { +struct Depsgraph; + class ObjectRuntimeBackup { public: ObjectRuntimeBackup(const Depsgraph *depsgraph); @@ -56,7 +58,7 @@ class ObjectRuntimeBackup { Object_Runtime runtime; short base_flag; unsigned short base_local_view_bits; - ModifierRuntimeDataBackup modifier_runtime_data; + Map<SessionUUID, ModifierDataBackup> modifier_runtime_data; Map<SessionUUID, bPoseChannel_Runtime> pose_channel_runtime_data; }; diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index c475e5287c2..e18c43fc643 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -29,6 +29,7 @@ #include "BKE_duplilist.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "DEG_depsgraph_query.h" @@ -42,15 +43,20 @@ static void eevee_motion_blur_mesh_data_free(void *val) { EEVEE_GeometryMotionData *geom_mb = (EEVEE_GeometryMotionData *)val; + EEVEE_HairMotionData *hair_mb = (EEVEE_HairMotionData *)val; switch (geom_mb->type) { - case EEVEE_HAIR_GEOM_MOTION_DATA: - for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { - GPU_VERTBUF_DISCARD_SAFE(geom_mb->hair_pos[i]); - DRW_TEXTURE_FREE_SAFE(geom_mb->hair_pos_tx[i]); + case EEVEE_MOTION_DATA_HAIR: + for (int j = 0; j < hair_mb->psys_len; j++) { + for (int i = 0; i < ARRAY_SIZE(hair_mb->psys[0].hair_pos); i++) { + GPU_VERTBUF_DISCARD_SAFE(hair_mb->psys[j].hair_pos[i]); + } + for (int i = 0; i < ARRAY_SIZE(hair_mb->psys[0].hair_pos); i++) { + DRW_TEXTURE_FREE_SAFE(hair_mb->psys[j].hair_pos_tx[i]); + } } break; - case EEVEE_MESH_GEOM_MOTION_DATA: + case EEVEE_MOTION_DATA_MESH: for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { GPU_VERTBUF_DISCARD_SAFE(geom_mb->vbo[i]); } @@ -64,7 +70,7 @@ static uint eevee_object_key_hash(const void *key) EEVEE_ObjectKey *ob_key = (EEVEE_ObjectKey *)key; uint hash = BLI_ghashutil_ptrhash(ob_key->ob); hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_ptrhash(ob_key->parent)); - for (int i = 0; i < 16; i++) { + for (int i = 0; i < MAX_DUPLI_RECUR; i++) { if (ob_key->id[i] != 0) { hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_inthash(ob_key->id[i])); } @@ -148,18 +154,40 @@ EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData * return ob_step; } -static EEVEE_GeometryMotionData *motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, - void *key, - bool hair) +static void *motion_blur_deform_data_get(EEVEE_MotionBlurData *mb, Object *ob, bool hair) { if (mb->geom == NULL) { return NULL; } + DupliObject *dup = DRW_object_get_dupli(ob); + void *key; + if (dup) { + key = dup->ob; + } + else { + key = ob; + } + /* Only use data for object that have no modifiers. */ + if (!BKE_object_is_modified(DRW_context_state_get()->scene, ob)) { + key = ob->data; + } key = (char *)key + (int)hair; EEVEE_GeometryMotionData *geom_step = BLI_ghash_lookup(mb->geom, key); if (geom_step == NULL) { - geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__); - geom_step->type = hair ? EEVEE_HAIR_GEOM_MOTION_DATA : EEVEE_MESH_GEOM_MOTION_DATA; + if (hair) { + EEVEE_HairMotionData *hair_step; + /* Ugly, we allocate for each modifiers and just fill based on modifier index in the list. */ + int psys_len = (ob->type != OB_HAIR) ? BLI_listbase_count(&ob->modifiers) : 1; + hair_step = MEM_callocN(sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]) * psys_len, + __func__); + hair_step->psys_len = psys_len; + geom_step = (EEVEE_GeometryMotionData *)hair_step; + geom_step->type = EEVEE_MOTION_DATA_HAIR; + } + else { + geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__); + geom_step->type = EEVEE_MOTION_DATA_MESH; + } BLI_ghash_insert(mb->geom, key, geom_step); } return geom_step; @@ -167,25 +195,12 @@ static EEVEE_GeometryMotionData *motion_blur_geometry_data_get(EEVEE_MotionBlurD EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, Object *ob) { - /* Use original data as key to ensure matching accross update. */ - return motion_blur_geometry_data_get(mb, DEG_get_original_object(ob)->data, false); + return motion_blur_deform_data_get(mb, ob, false); } -EEVEE_GeometryMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_MotionBlurData *mb, - Object *ob, - ModifierData *md) +EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_MotionBlurData *mb, Object *ob) { - void *key; - if (md) { - /* Particle system. */ - key = BKE_modifier_get_original(md); - } - else { - /* Hair object. */ - key = DEG_get_original_object(ob)->data; - } - - return motion_blur_geometry_data_get(mb, key, true); + return motion_blur_deform_data_get(mb, ob, true); } /* View Layer data. */ diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 365ba0afaac..4a03ef69d45 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -147,6 +147,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, if (!stl->effects) { stl->effects = MEM_callocN(sizeof(EEVEE_EffectsInfo), "EEVEE_EffectsInfo"); + stl->effects->taa_render_sample = 1; } effects = stl->effects; diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index 2a315927015..fa517e2d5c9 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -289,8 +289,14 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), /* Store transform */ DRW_hair_duplimat_get(ob, psys, md, mb_data->obmat[mb_step]); - EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_hair_data_get( - &effects->motion_blur, ob, md); + EEVEE_HairMotionData *mb_hair = EEVEE_motion_blur_hair_data_get(&effects->motion_blur, ob); + int psys_id = (md != NULL) ? BLI_findindex(&ob->modifiers, md) : 0; + + if (psys_id >= mb_hair->psys_len) { + /* This should never happen. It means the modifier list was changed by frame evaluation. */ + BLI_assert(0); + return; + } if (mb_step == MB_CURR) { /* Fill missing matrices if the object was hidden in previous or next frame. */ @@ -301,18 +307,21 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]); } + GPUTexture *tex_prev = mb_hair->psys[psys_id].hair_pos_tx[MB_PREV]; + GPUTexture *tex_next = mb_hair->psys[psys_id].hair_pos_tx[MB_NEXT]; + grp = DRW_shgroup_hair_create_sub(ob, psys, md, effects->motion_blur.hair_grp); DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]); DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); - DRW_shgroup_uniform_texture(grp, "prvBuffer", mb_geom->hair_pos_tx[MB_PREV]); - DRW_shgroup_uniform_texture(grp, "nxtBuffer", mb_geom->hair_pos_tx[MB_NEXT]); - DRW_shgroup_uniform_bool(grp, "useDeform", &mb_geom->use_deform, 1); + DRW_shgroup_uniform_texture(grp, "prvBuffer", tex_prev); + DRW_shgroup_uniform_texture(grp, "nxtBuffer", tex_next); + DRW_shgroup_uniform_bool(grp, "useDeform", &mb_hair->use_deform, 1); } else { /* Store vertex position buffer. */ - mb_geom->hair_pos[mb_step] = DRW_hair_pos_buffer_get(ob, psys, md); - mb_geom->use_deform = true; + mb_hair->psys[psys_id].hair_pos[mb_step] = DRW_hair_pos_buffer_get(ob, psys, md); + mb_hair->use_deform = true; } } } @@ -339,7 +348,8 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0; const bool object_moves = is_dupli || has_rigidbody || BKE_object_moves_in_time(ob, true); #else - /* BKE_object_moves_in_time does not work in some cases. Better */ + /* BKE_object_moves_in_time does not work in some cases. + * Better detect non moving object after evaluation. */ const bool object_moves = true; #endif const bool is_deform = BKE_object_is_deform_modified(DRW_context_state_get()->scene, ob) || @@ -375,17 +385,6 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), } if (mb_geom->use_deform) { - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); - if (!oedata->geom_update) { - /* FIXME(fclem) There can be false positive where the actual mesh is not updated. - * This avoids a crash but removes the motion blur from some object. - * Maybe an issue with depsgraph tagging. */ - mb_geom->use_deform = false; - oedata->geom_update = false; - - GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); - GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]); - } /* Keep to modify later (after init). */ mb_geom->batch = batch; } @@ -445,29 +444,36 @@ void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata) BLI_ghashIterator_done(&ghi) == false; BLI_ghashIterator_step(&ghi)) { EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + EEVEE_HairMotionData *mb_hair = (EEVEE_HairMotionData *)mb_geom; if (!mb_geom->use_deform) { continue; } switch (mb_geom->type) { - case EEVEE_HAIR_GEOM_MOTION_DATA: + case EEVEE_MOTION_DATA_HAIR: if (mb_step == MB_CURR) { /* TODO(fclem) Check if vertex count mismatch. */ - mb_geom->use_deform = true; + mb_hair->use_deform = true; } else { - mb_geom->hair_pos[mb_step] = GPU_vertbuf_duplicate(mb_geom->hair_pos[mb_step]); + for (int i = 0; i < mb_hair->psys_len; i++) { + if (mb_hair->psys[i].hair_pos[mb_step] == NULL) { + continue; + } + mb_hair->psys[i].hair_pos[mb_step] = GPU_vertbuf_duplicate( + mb_hair->psys[i].hair_pos[mb_step]); - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(mb_geom->hair_pos[mb_step]); + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(mb_hair->psys[i].hair_pos[mb_step]); - mb_geom->hair_pos_tx[mb_step] = GPU_texture_create_from_vertbuf( - mb_geom->hair_pos[mb_step]); + mb_hair->psys[i].hair_pos_tx[mb_step] = GPU_texture_create_from_vertbuf( + mb_hair->psys[i].hair_pos[mb_step]); + } } break; - case EEVEE_MESH_GEOM_MOTION_DATA: + case EEVEE_MOTION_DATA_MESH: if (mb_step == MB_CURR) { /* Modify batch to have data from adjacent frames. */ GPUBatch *batch = mb_geom->batch; @@ -485,15 +491,7 @@ void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata) break; } - /* Modify the batch to include the previous & next position. */ - if (i == MB_PREV) { - GPU_batch_vertbuf_add_ex(batch, vbo, true); - mb_geom->vbo[i] = NULL; - } - else { - /* This VBO can be reuse by next time step. Don't pass ownership. */ - GPU_batch_vertbuf_add_ex(batch, vbo, false); - } + GPU_batch_vertbuf_add_ex(batch, vbo, false); } } } @@ -548,16 +546,28 @@ void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata) BLI_ghashIterator_done(&ghi) == false; BLI_ghashIterator_step(&ghi)) { EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + EEVEE_HairMotionData *mb_hair = (EEVEE_HairMotionData *)mb_geom; switch (mb_geom->type) { - case EEVEE_HAIR_GEOM_MOTION_DATA: - GPU_VERTBUF_DISCARD_SAFE(mb_geom->hair_pos[MB_PREV]); - DRW_TEXTURE_FREE_SAFE(mb_geom->hair_pos_tx[MB_PREV]); - mb_geom->hair_pos[MB_PREV] = mb_geom->hair_pos[MB_NEXT]; - mb_geom->hair_pos_tx[MB_PREV] = mb_geom->hair_pos_tx[MB_NEXT]; + case EEVEE_MOTION_DATA_HAIR: + for (int i = 0; i < mb_hair->psys_len; i++) { + GPU_VERTBUF_DISCARD_SAFE(mb_hair->psys[i].hair_pos[MB_PREV]); + DRW_TEXTURE_FREE_SAFE(mb_hair->psys[i].hair_pos_tx[MB_PREV]); + mb_hair->psys[i].hair_pos[MB_PREV] = mb_hair->psys[i].hair_pos[MB_NEXT]; + mb_hair->psys[i].hair_pos_tx[MB_PREV] = mb_hair->psys[i].hair_pos_tx[MB_NEXT]; + } break; - case EEVEE_MESH_GEOM_MOTION_DATA: + case EEVEE_MOTION_DATA_MESH: + if (mb_geom->batch != NULL) { + for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN; i++) { + if (mb_geom->batch->verts[i] == mb_geom->vbo[MB_PREV] || + mb_geom->batch->verts[i] == mb_geom->vbo[MB_NEXT]) { + /* Avoid double reference of the VBOs. */ + mb_geom->batch->verts[i] = NULL; + } + } + } GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); mb_geom->vbo[MB_PREV] = mb_geom->vbo[MB_NEXT]; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 34cd22ad13c..1e2de521cdf 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -595,25 +595,30 @@ typedef struct EEVEE_ObjectMotionData { } EEVEE_ObjectMotionData; typedef enum eEEVEEMotionData { - EEVEE_MESH_GEOM_MOTION_DATA = 0, - EEVEE_HAIR_GEOM_MOTION_DATA, + EEVEE_MOTION_DATA_MESH = 0, + EEVEE_MOTION_DATA_HAIR, } eEEVEEMotionData; +typedef struct EEVEE_HairMotionData { + /** Needs to be first to ensure casting. */ + eEEVEEMotionData type; + int use_deform; + /** Allocator will alloc enough slot for all particle systems. Or 1 if it's a hair object. */ + int psys_len; + struct { + struct GPUVertBuf *hair_pos[2]; /* Position buffer for time = t +/- step. */ + struct GPUTexture *hair_pos_tx[2]; /* Buffer Texture of the corresponding VBO. */ + } psys[0]; +} EEVEE_HairMotionData; + typedef struct EEVEE_GeometryMotionData { + /** Needs to be first to ensure casting. */ eEEVEEMotionData type; - int use_deform; /* To disable deform mb if vertcount mismatch. */ - union { - struct { - /* Mesh */ - struct GPUBatch *batch; /* Batch for time = t. */ - struct GPUVertBuf *vbo[2]; /* Vbo for time = t +/- step. */ - }; - struct { - /* Hair */ - struct GPUVertBuf *hair_pos[2]; /* Position buffer for time = t +/- step. */ - struct GPUTexture *hair_pos_tx[2]; /* Buffer Texture of the corresponding VBO. */ - }; - }; + /** To disable deform mb if vertcount mismatch. */ + int use_deform; + + struct GPUBatch *batch; /* Batch for time = t. */ + struct GPUVertBuf *vbo[2]; /* Vbo for time = t +/- step. */ } EEVEE_GeometryMotionData; /* ************ EFFECTS DATA ************* */ @@ -914,6 +919,9 @@ typedef struct EEVEE_PrivateData { float camtexcofac[4]; float size_orig[2]; + /* Cached original camera when rendering for motion blur (see T79637). */ + struct Object *cam_original_ob; + /* Mist Settings */ float mist_start, mist_inv_dist, mist_falloff; @@ -971,9 +979,7 @@ EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData * bool hair); EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, Object *ob); -EEVEE_GeometryMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_MotionBlurData *mb, - Object *ob, - struct ModifierData *md); +EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_MotionBlurData *mb, Object *ob); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob); EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 62698bc5da3..21a4013e309 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -126,6 +126,9 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * GPU_framebuffer_ensure_config(&fbl->main_color_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->color)}); + /* Camera could change because of Motion blur. */ + g_data->cam_original_ob = RE_GetCamera(engine->re); + return true; } @@ -135,9 +138,10 @@ void EEVEE_render_modules_init(EEVEE_Data *vedata, { EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = vedata->stl->g_data; EEVEE_FramebufferList *fbl = vedata->fbl; /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ - struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, g_data->cam_original_ob); EEVEE_render_view_sync(vedata, engine, depsgraph); /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`. @@ -156,7 +160,7 @@ void EEVEE_render_view_sync(EEVEE_Data *vedata, RenderEngine *engine, struct Dep /* Set the pers & view matrix. */ float winmat[4][4], viewmat[4][4], viewinv[4][4]; /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ - struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, g_data->cam_original_ob); RE_GetCameraWindow(engine->re, ob_camera_eval, winmat); RE_GetCameraWindowWithOverscan(engine->re, g_data->overscan, winmat); diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index 12b50030435..5976a9505e8 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -212,7 +212,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * Reset for each "redraw". When rendering using ogl render, * we accumulate the redraw inside the drawing loop in eevee_draw_scene(). **/ - effects->taa_render_sample = 1; + if (DRW_state_is_opengl_render()) { + effects->taa_render_sample = 1; + } effects->bypass_drawing = false; EEVEE_temporal_sampling_create_view(vedata); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index e1e65c29b4f..f8c7a6e16db 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -62,6 +62,7 @@ static struct { GPUTexture *dummy_density; GPUTexture *dummy_color; GPUTexture *dummy_flame; + GPUTexture *dummy_missing; GPUTexture *dummy_scatter; GPUTexture *dummy_transmit; @@ -141,6 +142,9 @@ static void eevee_create_shader_volumes(void) const float flame = 0.0f; e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame); + + const float missing[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + e_data.dummy_missing = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, missing); } void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample) @@ -355,7 +359,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* Fix principle volumetric not working with world materials. */ ListBase gpu_grids = GPU_material_volume_grids(mat); LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, &gpu_grids) { - DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density); + DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_missing); } DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); @@ -443,7 +447,7 @@ static bool eevee_volume_object_grids_init(Object *ob, ListBase *gpu_grids, DRWS NULL; DRW_shgroup_uniform_texture( - grp, gpu_grid->sampler_name, (drw_grid) ? drw_grid->texture : e_data.dummy_density); + grp, gpu_grid->sampler_name, (drw_grid) ? drw_grid->texture : e_data.dummy_missing); if (drw_grid && multiple_transforms) { /* Specify per-volume transform matrix that is applied after the @@ -830,6 +834,7 @@ void EEVEE_volumes_free(void) DRW_TEXTURE_FREE_SAFE(e_data.dummy_density); DRW_TEXTURE_FREE_SAFE(e_data.dummy_flame); DRW_TEXTURE_FREE_SAFE(e_data.dummy_color); + DRW_TEXTURE_FREE_SAFE(e_data.dummy_missing); DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh); DRW_SHADER_FREE_SAFE(e_data.scatter_sh); diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c index ebc8a2f97ef..728b3d510fa 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c +++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c @@ -75,8 +75,6 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata) bool show_face_dots = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) != 0 || pd->edit_mesh.do_zbufclip; - pd->edit_mesh.ghost_ob = 0; - pd->edit_mesh.edit_ob = 0; pd->edit_mesh.do_faces = true; pd->edit_mesh.do_edges = true; @@ -312,9 +310,6 @@ void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob) overlay_edit_mesh_add_ob_to_pass(pd, ob, do_in_front); } - pd->edit_mesh.ghost_ob += (ob->dtx & OB_DRAW_IN_FRONT) ? 1 : 0; - pd->edit_mesh.edit_ob += 1; - if (DRW_state_show_text() && (pd->edit_mesh.flag & OVERLAY_EDIT_TEXT)) { const DRWContextState *draw_ctx = DRW_context_state_get(); DRW_text_edit_mesh_measure_stats(draw_ctx->region, draw_ctx->v3d, ob, &draw_ctx->scene->unit); @@ -375,18 +370,11 @@ void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata) DRW_draw_pass(psl->edit_mesh_verts_ps[NOT_IN_FRONT]); } else { - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - DRW_draw_pass(psl->edit_mesh_normals_ps); overlay_edit_mesh_draw_components(psl, pd, false); - if (!DRW_state_is_depth() && v3d->shading.type == OB_SOLID && pd->edit_mesh.ghost_ob == 1 && - pd->edit_mesh.edit_ob == 1) { - /* In the case of single ghost object edit (common case for retopology): - * we clear the depth buffer so that only the depth of the retopo mesh - * is occluding the edit cage. */ - GPU_framebuffer_clear_depth(fbl->overlay_default_fb, 1.0f); + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_in_front_fb); } if (!DRW_pass_is_empty(psl->edit_mesh_depth_ps[IN_FRONT])) { diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 5e5aba713f0..5cf8cb12aa0 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -309,8 +309,6 @@ typedef struct OVERLAY_PrivateData { float overlay_color[4]; } edit_text; struct { - int ghost_ob; - int edit_ob; bool do_zbufclip; bool do_faces; bool do_edges; diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl index 732e392ffe0..5818d8eca52 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl @@ -26,6 +26,7 @@ void discard_vert() #define GP_EDIT_MULTIFRAME 4u /* 1 << 2 */ #define GP_EDIT_STROKE_START 8u /* 1 << 3 */ #define GP_EDIT_STROKE_END 16u /* 1 << 4 */ +#define GP_EDIT_POINT_DIMMED 32u /* 1 << 5 */ #ifdef USE_POINTS # define colorUnselect colorGpencilVertex @@ -60,6 +61,7 @@ void main() bool is_multiframe = (vflag & GP_EDIT_MULTIFRAME) != 0u; bool is_stroke_sel = (vflag & GP_EDIT_STROKE_SELECTED) != 0u; bool is_point_sel = (vflag & GP_EDIT_POINT_SELECTED) != 0u; + bool is_point_dimmed = (vflag & GP_EDIT_POINT_DIMMED) != 0u; if (doWeightColor) { finalColor.rgb = weight_to_rgb(weight); @@ -73,6 +75,10 @@ void main() #ifdef USE_POINTS gl_PointSize = sizeVertex * 2.0; + if (is_point_dimmed) { + finalColor.rgb = clamp(colorUnselect.rgb + vec3(0.3), 0.0, 1.0); + } + if (doStrokeEndpoints && !doWeightColor) { bool is_stroke_start = (vflag & GP_EDIT_STROKE_START) != 0u; bool is_stroke_end = (vflag & GP_EDIT_STROKE_END) != 0u; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 46b7a88b2a6..4d7440a3276 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -152,18 +152,6 @@ void DRW_shape_cache_free(void) } } -void DRW_shape_cache_reset(void) -{ - uint i = sizeof(SHC) / sizeof(GPUBatch *); - GPUBatch **batch = (GPUBatch **)&SHC; - while (i--) { - if (*batch) { - GPU_batch_vao_cache_clear(*batch); - } - batch++; - } -} - /* -------------------------------------------------------------------- */ /** \name Procedural Batches * \{ */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 5f1744a7aec..8597f86f8e6 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -33,7 +33,6 @@ struct VolumeGrid; struct bGPDstroke; void DRW_shape_cache_free(void); -void DRW_shape_cache_reset(void); /* 3D cursor */ struct GPUBatch *DRW_cache_cursor_get(bool crosshair_lines); diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index c2e34b75774..c995e92d2fa 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -676,6 +676,7 @@ void DRW_cache_gpencil_sbuffer_clear(Object *ob) #define GP_EDIT_MULTIFRAME (1 << 2) #define GP_EDIT_STROKE_START (1 << 3) #define GP_EDIT_STROKE_END (1 << 4) +#define GP_EDIT_POINT_DIMMED (1 << 5) typedef struct gpEditIterData { gpEditVert *verts; @@ -696,6 +697,7 @@ static uint32_t gpencil_point_edit_flag(const bool layer_lock, SET_FLAG_FROM_TEST(sflag, (!layer_lock) && pt->flag & GP_SPOINT_SELECT, GP_EDIT_POINT_SELECTED); SET_FLAG_FROM_TEST(sflag, v == 0, GP_EDIT_STROKE_START); SET_FLAG_FROM_TEST(sflag, v == (v_len - 1), GP_EDIT_STROKE_END); + SET_FLAG_FROM_TEST(sflag, pt->runtime.pt_orig == NULL, GP_EDIT_POINT_DIMMED); return sflag; } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index d6faeb16583..0e2be993787 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -1248,7 +1248,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, saved_elem_ranges[i] = cache->surface_per_mat[i]->elem; /* Avoid deletion as the batch is owner. */ cache->surface_per_mat[i]->elem = NULL; - cache->surface_per_mat[i]->owns_flag &= ~GPU_BATCH_OWNS_INDEX; + cache->surface_per_mat[i]->flag &= ~GPU_BATCH_OWNS_INDEX; } } /* We can't discard batches at this point as they have been diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index 076d32ffe1f..5f0af06931e 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -155,7 +155,7 @@ static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob, MetaBallBat { if (cache->pos_nor_in_order == NULL) { ListBase *lb = &ob->runtime.curve_cache->disp; - cache->pos_nor_in_order = MEM_callocN(sizeof(GPUVertBuf), __func__); + cache->pos_nor_in_order = GPU_vertbuf_create(GPU_USAGE_STATIC); DRW_displist_vertbuf_create_pos_and_nor(lb, cache->pos_nor_in_order); } return cache->pos_nor_in_order; @@ -165,7 +165,7 @@ static GPUIndexBuf *mball_batch_cache_get_edges_adj_lines(Object *ob, MetaBallBa { if (cache->edges_adj_lines == NULL) { ListBase *lb = &ob->runtime.curve_cache->disp; - cache->edges_adj_lines = MEM_callocN(sizeof(GPUVertBuf), __func__); + cache->edges_adj_lines = GPU_indexbuf_calloc(); DRW_displist_indexbuf_create_edges_adjacency_lines( lb, cache->edges_adj_lines, &cache->is_manifold); } @@ -187,7 +187,7 @@ GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob) if (cache->batch == NULL) { ListBase *lb = &ob->runtime.curve_cache->disp; - GPUIndexBuf *ibo = MEM_callocN(sizeof(GPUIndexBuf), __func__); + GPUIndexBuf *ibo = GPU_indexbuf_calloc(); DRW_displist_indexbuf_create_triangles_in_order(lb, ibo); cache->batch = GPU_batch_create_ex(GPU_PRIM_TRIS, mball_batch_cache_get_pos_and_normals(ob, cache), @@ -234,10 +234,10 @@ GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(Object *ob) if (cache->face_wire.batch == NULL) { ListBase *lb = &ob->runtime.curve_cache->disp; - GPUVertBuf *vbo_wiredata = MEM_callocN(sizeof(GPUVertBuf), __func__); + GPUVertBuf *vbo_wiredata = GPU_vertbuf_create(GPU_USAGE_STATIC); DRW_displist_vertbuf_create_wiredata(lb, vbo_wiredata); - GPUIndexBuf *ibo = MEM_callocN(sizeof(GPUIndexBuf), __func__); + GPUIndexBuf *ibo = GPU_indexbuf_calloc(); DRW_displist_indexbuf_create_lines_in_order(lb, ibo); cache->face_wire.batch = GPU_batch_create_ex(GPU_PRIM_LINES, diff --git a/source/blender/draw/intern/draw_cache_impl_volume.c b/source/blender/draw/intern/draw_cache_impl_volume.c index e07f5b33d58..825fec83cf1 100644 --- a/source/blender/draw/intern/draw_cache_impl_volume.c +++ b/source/blender/draw/intern/draw_cache_impl_volume.c @@ -163,7 +163,7 @@ static void drw_volume_wireframe_cb( GPU_vertbuf_attr_fill_stride(cache->face_wire.pos_nor_in_order, nor_id, 0, &packed_normal); /* Create wiredata. */ - GPUVertBuf *vbo_wiredata = MEM_callocN(sizeof(GPUVertBuf), __func__); + GPUVertBuf *vbo_wiredata = GPU_vertbuf_create(GPU_USAGE_STATIC); DRW_vertbuf_create_wiredata(vbo_wiredata, totvert); if (volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS) { diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h index 06d6f1afc31..0f0e1785a2a 100644 --- a/source/blender/draw/intern/draw_cache_inline.h +++ b/source/blender/draw/intern/draw_cache_inline.h @@ -48,7 +48,7 @@ BLI_INLINE GPUBatch *DRW_batch_request(GPUBatch **batch) { /* XXX TODO(fclem): We are writing to batch cache here. Need to make this thread safe. */ if (*batch == NULL) { - *batch = GPU_batch_calloc(1); + *batch = GPU_batch_calloc(); } return *batch; } @@ -69,11 +69,10 @@ BLI_INLINE bool DRW_batch_requested(GPUBatch *batch, int prim_type) BLI_INLINE void DRW_ibo_request(GPUBatch *batch, GPUIndexBuf **ibo) { if (*ibo == NULL) { - *ibo = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); + *ibo = GPU_indexbuf_calloc(); } if (batch != NULL) { - GPU_batch_vao_cache_clear(batch); - batch->elem = *ibo; + GPU_batch_elembuf_set(batch, *ibo, false); } } @@ -87,13 +86,12 @@ BLI_INLINE bool DRW_ibo_requested(GPUIndexBuf *ibo) BLI_INLINE void DRW_vbo_request(GPUBatch *batch, GPUVertBuf **vbo) { if (*vbo == NULL) { - *vbo = MEM_callocN(sizeof(GPUVertBuf), "GPUVertBuf"); + *vbo = GPU_vertbuf_create(GPU_USAGE_STATIC); } if (batch != NULL) { /* HACK set first vbo if not init. */ if (batch->verts[0] == NULL) { - GPU_batch_vao_cache_clear(batch); - batch->verts[0] = *vbo; + GPU_batch_vertbuf_add(batch, *vbo); } else { /* HACK: bypass assert */ diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index 5005f38c558..4e08e6e5129 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -59,50 +59,50 @@ struct DRWInstanceDataList { }; typedef struct DRWTempBufferHandle { - /** Must be first for casting. */ - GPUVertBuf buf; + GPUVertBuf *buf; /** Format pointer for reuse. */ GPUVertFormat *format; /** Touched vertex length for resize. */ int *vert_len; } DRWTempBufferHandle; -static ListBase g_idatalists = {NULL, NULL}; +typedef struct DRWTempInstancingHandle { + /** Copy of geom but with the per-instance attributes. */ + GPUBatch *batch; + /** Batch containing instancing attributes. */ + GPUBatch *instancer; + /** Callbuffer to be used instead of instancer . */ + GPUVertBuf *buf; + /** Original non-instanced batch pointer. */ + GPUBatch *geom; +} DRWTempInstancingHandle; -/* -------------------------------------------------------------------- */ -/** \name Instance Buffer Management - * \{ */ +static ListBase g_idatalists = {NULL, NULL}; -static void instance_batch_free(GPUBatch *geom, void *UNUSED(user_data)) +static void instancing_batch_references_add(GPUBatch *batch) { - if (geom->verts[0] == NULL) { - /** XXX This is a false positive case. - * The batch has been requested but not init yet - * and there is a chance that it might become init. - */ - return; + for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN && batch->verts[i]; i++) { + GPU_vertbuf_handle_ref_add(batch->verts[i]); + } + for (int i = 0; i < GPU_BATCH_INST_VBO_MAX_LEN && batch->inst[i]; i++) { + GPU_vertbuf_handle_ref_add(batch->inst[i]); } +} - /* Free all batches that use the same vbos before they are reused. */ - /* TODO: Make it thread safe! Batch freeing can happen from another thread. */ - /* FIXME: This is not really correct. The correct way would be to check based on - * the vertex buffers. We assume the batch containing the VBO is being when it should. */ - /* PERF: This is doing a linear search. This can be very costly. */ - LISTBASE_FOREACH (DRWInstanceDataList *, data_list, &g_idatalists) { - BLI_memblock *memblock = data_list->pool_instancing; - BLI_memblock_iter iter; - BLI_memblock_iternew(memblock, &iter); - GPUBatch **batch_ptr; - while ((batch_ptr = (GPUBatch **)BLI_memblock_iterstep(&iter))) { - GPUBatch *batch = *batch_ptr; - /* Only check verts[0] that's enough. */ - if (batch->verts[0] == geom->verts[0]) { - GPU_batch_clear(batch); - } - } +static void instancing_batch_references_remove(GPUBatch *batch) +{ + for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN && batch->verts[i]; i++) { + GPU_vertbuf_handle_ref_remove(batch->verts[i]); + } + for (int i = 0; i < GPU_BATCH_INST_VBO_MAX_LEN && batch->inst[i]; i++) { + GPU_vertbuf_handle_ref_remove(batch->inst[i]); } } +/* -------------------------------------------------------------------- */ +/** \name Instance Buffer Management + * \{ */ + /** * This manager allows to distribute existing batches for instancing * attributes. This reduce the number of batches creation. @@ -119,20 +119,23 @@ GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist, BLI_assert(vert_len != NULL); DRWTempBufferHandle *handle = BLI_memblock_alloc(idatalist->pool_buffers); - GPUVertBuf *vert = &handle->buf; - handle->vert_len = vert_len; if (handle->format != format) { handle->format = format; - /* TODO/PERF: Save the allocated data from freeing to avoid reallocation. */ - GPU_vertbuf_clear(vert); + GPU_VERTBUF_DISCARD_SAFE(handle->buf); + + GPUVertBuf *vert = GPU_vertbuf_create(GPU_USAGE_DYNAMIC); GPU_vertbuf_init_with_format_ex(vert, format, GPU_USAGE_DYNAMIC); GPU_vertbuf_data_alloc(vert, DRW_BUFFER_VERTS_CHUNK); + + handle->buf = vert; } - return vert; + handle->vert_len = vert_len; + return handle->buf; } -/* NOTE: Does not return a valid drawable batch until DRW_instance_buffer_finish has run. */ +/* NOTE: Does not return a valid drawable batch until DRW_instance_buffer_finish has run. + * Initialization is delayed because instancer or geom could still not be initialized. */ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist, GPUVertBuf *buf, GPUBatch *instancer, @@ -143,17 +146,17 @@ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist, /* Only call with one of them. */ BLI_assert((instancer != NULL) != (buf != NULL)); - GPUBatch **batch_ptr = BLI_memblock_alloc(idatalist->pool_instancing); - if (*batch_ptr == NULL) { - *batch_ptr = GPU_batch_calloc(1); + DRWTempInstancingHandle *handle = BLI_memblock_alloc(idatalist->pool_instancing); + if (handle->batch == NULL) { + handle->batch = GPU_batch_calloc(); } - GPUBatch *batch = *batch_ptr; + GPUBatch *batch = handle->batch; bool instancer_compat = buf ? ((batch->inst[0] == buf) && (buf->vbo_id != 0)) : - ((batch->inst[0] == instancer->inst[0]) && - (batch->inst[1] == instancer->inst[1])); - bool is_compatible = (batch->gl_prim_type == geom->gl_prim_type) && instancer_compat && - (batch->phase == GPU_BATCH_READY_TO_DRAW) && (batch->elem == geom->elem); + ((batch->inst[0] == instancer->verts[0]) && + (batch->inst[1] == instancer->verts[1])); + bool is_compatible = (batch->prim_type == geom->prim_type) && instancer_compat && + (batch->flag & GPU_BATCH_BUILDING) == 0 && (batch->elem == geom->elem); for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN && is_compatible; i++) { if (batch->verts[i] != geom->verts[i]) { is_compatible = false; @@ -161,15 +164,13 @@ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist, } if (!is_compatible) { + instancing_batch_references_remove(batch); GPU_batch_clear(batch); - /* Save args and init later */ - batch->inst[0] = buf; - batch->inst[1] = (void *)instancer; /* HACK to save the pointer without other alloc. */ - batch->phase = GPU_BATCH_READY_TO_BUILD; - batch->verts[0] = (void *)geom; /* HACK to save the pointer without other alloc. */ - - /* Make sure to free this batch if the instance geom gets free. */ - GPU_batch_callback_free_set(geom, &instance_batch_free, NULL); + /* Save args and init later. */ + batch->flag = GPU_BATCH_BUILDING; + handle->buf = buf; + handle->instancer = instancer; + handle->geom = geom; } return batch; } @@ -179,14 +180,14 @@ GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist, GPUVertBuf *buf, GPUPrimType prim_type) { - GPUBatch **batch_ptr = BLI_memblock_alloc(idatalist->pool_instancing); + GPUBatch **batch_ptr = BLI_memblock_alloc(idatalist->pool_batching); if (*batch_ptr == NULL) { - *batch_ptr = GPU_batch_calloc(1); + *batch_ptr = GPU_batch_calloc(); } GPUBatch *batch = *batch_ptr; bool is_compatible = (batch->verts[0] == buf) && (buf->vbo_id != 0) && - (batch->gl_prim_type == convert_prim_type_to_gl(prim_type)); + (batch->prim_type == prim_type); if (!is_compatible) { GPU_batch_clear(batch); GPU_batch_init(batch, prim_type, buf, NULL); @@ -197,7 +198,13 @@ GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist, static void temp_buffer_handle_free(DRWTempBufferHandle *handle) { handle->format = NULL; - GPU_vertbuf_clear(&handle->buf); + GPU_VERTBUF_DISCARD_SAFE(handle->buf); +} + +static void temp_instancing_handle_free(DRWTempInstancingHandle *handle) +{ + instancing_batch_references_remove(handle->batch); + GPU_BATCH_DISCARD_SAFE(handle->batch); } static void temp_batch_free(GPUBatch **batch) @@ -215,23 +222,22 @@ void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist) if (handle->vert_len != NULL) { uint vert_len = *(handle->vert_len); uint target_buf_size = ((vert_len / DRW_BUFFER_VERTS_CHUNK) + 1) * DRW_BUFFER_VERTS_CHUNK; - if (target_buf_size < handle->buf.vertex_alloc) { - GPU_vertbuf_data_resize(&handle->buf, target_buf_size); + if (target_buf_size < handle->buf->vertex_alloc) { + GPU_vertbuf_data_resize(handle->buf, target_buf_size); } - GPU_vertbuf_data_len_set(&handle->buf, vert_len); - GPU_vertbuf_use(&handle->buf); /* Send data. */ + GPU_vertbuf_data_len_set(handle->buf, vert_len); + GPU_vertbuf_use(handle->buf); /* Send data. */ } } /* Finish pending instancing batches. */ - GPUBatch **batch_ptr; + DRWTempInstancingHandle *handle_inst; BLI_memblock_iternew(idatalist->pool_instancing, &iter); - while ((batch_ptr = BLI_memblock_iterstep(&iter))) { - GPUBatch *batch = *batch_ptr; - if (batch && batch->phase == GPU_BATCH_READY_TO_BUILD) { - GPUVertBuf *inst_buf = batch->inst[0]; - /* HACK see DRW_temp_batch_instance_request. */ - GPUBatch *inst_batch = (void *)batch->inst[1]; - GPUBatch *geom = (void *)batch->verts[0]; + while ((handle_inst = BLI_memblock_iterstep(&iter))) { + GPUBatch *batch = handle_inst->batch; + if (batch && batch->flag == GPU_BATCH_BUILDING) { + GPUVertBuf *inst_buf = handle_inst->buf; + GPUBatch *inst_batch = handle_inst->instancer; + GPUBatch *geom = handle_inst->geom; GPU_batch_copy(batch, geom); if (inst_batch != NULL) { for (int i = 0; i < GPU_BATCH_INST_VBO_MAX_LEN && inst_batch->verts[i]; i++) { @@ -241,11 +247,14 @@ void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist) else { GPU_batch_instbuf_add_ex(batch, inst_buf, false); } + /* Add reference to avoid comparing pointers (in DRW_temp_batch_request) that could + * potentially be the same. This will delay the freeing of the GPUVertBuf itself. */ + instancing_batch_references_add(batch); } } /* Resize pools and free unused. */ BLI_memblock_clear(idatalist->pool_buffers, (MemblockValFreeFP)temp_buffer_handle_free); - BLI_memblock_clear(idatalist->pool_instancing, (MemblockValFreeFP)temp_batch_free); + BLI_memblock_clear(idatalist->pool_instancing, (MemblockValFreeFP)temp_instancing_handle_free); BLI_memblock_clear(idatalist->pool_batching, (MemblockValFreeFP)temp_batch_free); } @@ -318,7 +327,7 @@ DRWInstanceDataList *DRW_instance_data_list_create(void) DRWInstanceDataList *idatalist = MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList"); idatalist->pool_batching = BLI_memblock_create(sizeof(GPUBatch *)); - idatalist->pool_instancing = BLI_memblock_create(sizeof(GPUBatch *)); + idatalist->pool_instancing = BLI_memblock_create(sizeof(DRWTempInstancingHandle)); idatalist->pool_buffers = BLI_memblock_create(sizeof(DRWTempBufferHandle)); BLI_addtail(&g_idatalists, idatalist); @@ -341,7 +350,7 @@ void DRW_instance_data_list_free(DRWInstanceDataList *idatalist) } BLI_memblock_destroy(idatalist->pool_buffers, (MemblockValFreeFP)temp_buffer_handle_free); - BLI_memblock_destroy(idatalist->pool_instancing, (MemblockValFreeFP)temp_batch_free); + BLI_memblock_destroy(idatalist->pool_instancing, (MemblockValFreeFP)temp_instancing_handle_free); BLI_memblock_destroy(idatalist->pool_batching, (MemblockValFreeFP)temp_batch_free); BLI_remlink(&g_idatalists, idatalist); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 4a5e07476a9..e436424b460 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2824,7 +2824,6 @@ void DRW_opengl_context_enable_ex(bool restore) if (!G.background) { immActivate(); } - BLF_batch_reset(); } } } @@ -2888,13 +2887,11 @@ void DRW_gpu_render_context_enable(void *re_gpu_context) BLI_assert(!BLI_thread_is_main()); GPU_context_active_set(re_gpu_context); - DRW_shape_cache_reset(); /* XXX fix that too. */ } /* Needs to be called BEFORE DRW_opengl_render_context_disable() */ void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context)) { - DRW_shape_cache_reset(); /* XXX fix that too. */ GPU_context_active_set(NULL); } diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 92a01cbbe04..d15a55e7bef 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -35,6 +35,7 @@ #include "GPU_batch.h" #include "GPU_context.h" +#include "GPU_drawlist.h" #include "GPU_framebuffer.h" #include "GPU_shader.h" #include "GPU_uniformbuffer.h" diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index e3860b1bfb2..b931bdd0cbe 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -54,8 +54,6 @@ typedef struct DRWCommandsState { int resource_id; int base_inst; int inst_count; - int v_first; - int v_count; bool neg_scale; /* Resource location. */ int obmats_loc; @@ -663,18 +661,9 @@ BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup, BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom) { - /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */ - if (DST.batch) { - DST.batch->program_in_use = false; - } - DST.batch = geom; - GPU_batch_set_shader_no_bind(geom, shgroup->shader); - - geom->program_in_use = true; /* XXX hacking #GPUBatch */ - - GPU_batch_bind(geom); + GPU_batch_set_shader(geom, shgroup->shader); } BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup, @@ -714,18 +703,12 @@ BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *s GPU_draw_list_submit(DST.draw_list); draw_geometry_bind(shgroup, state->batch); } - GPU_draw_list_command_add( - DST.draw_list, state->v_first, state->v_count, state->base_inst, state->inst_count); + GPU_draw_list_append(DST.draw_list, state->batch, state->base_inst, state->inst_count); } /* Fallback when unsupported */ else { - draw_geometry_execute(shgroup, - state->batch, - state->v_first, - state->v_count, - state->base_inst, - state->inst_count, - state->baseinst_loc); + draw_geometry_execute( + shgroup, state->batch, 0, 0, state->base_inst, state->inst_count, state->baseinst_loc); } } @@ -873,10 +856,10 @@ BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup, /* Batching */ if (!is_instancing) { /* FIXME: Meh a bit nasty. */ - if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) { + if (batch->prim_type == GPU_PRIM_TRIS) { count = 3; } - else if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) { + else if (batch->prim_type == GPU_PRIM_LINES) { count = 2; } } @@ -1015,8 +998,6 @@ static void draw_call_batching_start(DRWCommandsState *state) state->resource_id = -1; state->base_inst = 0; state->inst_count = 0; - state->v_first = 0; - state->v_count = 0; state->batch = NULL; state->select_id = -1; @@ -1039,15 +1020,10 @@ static void draw_call_batching_do(DRWShadingGroup *shgroup, draw_call_batching_flush(shgroup, state); state->batch = call->batch; - state->v_first = (call->batch->elem) ? call->batch->elem->index_start : 0; - state->v_count = (call->batch->elem) ? call->batch->elem->index_len : - call->batch->verts[0]->vertex_len; state->inst_count = 1; state->base_inst = id; draw_call_resource_bind(state, &call->handle); - - GPU_draw_list_init(DST.draw_list, state->batch); } /* Is the id consecutive? */ else if (id != state->base_inst + state->inst_count) { @@ -1111,10 +1087,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) } GPU_shader_bind(shgroup->shader); DST.shader = shgroup->shader; - /* XXX hacking gawain */ - if (DST.batch) { - DST.batch->program_in_use = false; - } DST.batch = NULL; } @@ -1305,7 +1277,6 @@ static void drw_draw_pass_ex(DRWPass *pass, } if (DST.batch) { - DST.batch->program_in_use = false; DST.batch = NULL; } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 8c2f4216aa9..66d4882cf9d 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -3025,8 +3025,11 @@ bool ED_autokeyframe_property( bool special; bool changed = false; + /* for entire array buttons we check the first component, it's not perfect + * but works well enough in typical cases */ + const int rnaindex_check = (rnaindex == -1) ? 0 : rnaindex; fcu = BKE_fcurve_find_by_rna_context_ui( - C, ptr, prop, rnaindex, NULL, &action, &driven, &special); + C, ptr, prop, rnaindex_check, NULL, &action, &driven, &special); if (fcu == NULL) { return changed; diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 0dcb8de37f1..b8cc704eb23 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -744,6 +744,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.pose.relax ops.sculpt.border_hide ops.sculpt.border_mask + ops.sculpt.cloth_filter ops.sculpt.lasso_mask ops.sculpt.mesh_filter ops.sequencer.blade diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index a3921791427..24943ab5318 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -78,12 +78,11 @@ typedef struct SnapGizmo3D { } SnapGizmo3D; #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK -static bool invert_snap(const wmGizmo *gz, const wmWindowManager *wm, const wmEvent *event) +static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm, const wmEvent *event) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; - wmKeyMap *keymap = WM_keymap_active(wm, gizmo_snap->keymap); + wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap); - const int snap_on = gizmo_snap->snap_on; + const int snap_on = snap_gizmo->snap_on; for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { if (kmi->flag & KMI_INACTIVE) { continue; @@ -201,29 +200,34 @@ SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene, const View3D *v3d, wmGizmo *gz) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; - if (gizmo_snap->snap_context_v3d == NULL) { - gizmo_snap->snap_context_v3d = ED_transform_snap_object_context_create_view3d( + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + if (snap_gizmo->snap_context_v3d == NULL) { + snap_gizmo->snap_context_v3d = ED_transform_snap_object_context_create_view3d( scene, 0, region, v3d); } - return gizmo_snap->snap_context_v3d; + return snap_gizmo->snap_context_v3d; } bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; - return gizmo_snap->invert_snap; +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + return snap_gizmo->invert_snap; +#else + return false; +#endif } + void ED_gizmotypes_snap_3d_toggle_set(wmGizmo *gz, bool enable) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; - gizmo_snap->use_snap_override = (int)enable; + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + snap_gizmo->use_snap_override = (int)enable; } void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; - gizmo_snap->use_snap_override = -1; + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + snap_gizmo->use_snap_override = -1; } short ED_gizmotypes_snap_3d_update(wmGizmo *gz, @@ -235,29 +239,29 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, float r_loc[3], float r_nor[3]) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; Scene *scene = DEG_get_input_scene(depsgraph); float co[3], no[3]; short snap_elem = 0; int snap_elem_index[3] = {-1, -1, -1}; int index = -1; - if (gizmo_snap->use_snap_override != -1) { - if (gizmo_snap->use_snap_override == false) { - gizmo_snap->snap_elem = 0; + if (snap_gizmo->use_snap_override != -1) { + if (snap_gizmo->use_snap_override == false) { + snap_gizmo->snap_elem = 0; return 0; } } #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK if (wm && wm->winactive) { - gizmo_snap->invert_snap = invert_snap(gz, wm, wm->winactive->eventstate); + snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm, wm->winactive->eventstate); } - if (gizmo_snap->use_snap_override == -1) { + if (snap_gizmo->use_snap_override == -1) { const ToolSettings *ts = scene->toolsettings; - if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) { - gizmo_snap->snap_elem = 0; + if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) { + snap_gizmo->snap_elem = 0; return 0; } } @@ -267,8 +271,8 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements"); int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); - if (gz_prop->prop != gizmo_snap->prop_snap_force) { - int snap_elements_force = RNA_property_enum_get(gz->ptr, gizmo_snap->prop_snap_force); + if (gz_prop->prop != snap_gizmo->prop_snap_force) { + int snap_elements_force = RNA_property_enum_get(gz->ptr, snap_gizmo->prop_snap_force); snap_elements |= snap_elements_force; } snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | @@ -276,8 +280,8 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, if (snap_elements) { float prev_co[3] = {0.0f}; - if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) { - RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_co); + if (RNA_property_is_set(gz->ptr, snap_gizmo->prop_prevpoint)) { + RNA_property_float_get_array(gz->ptr, snap_gizmo->prop_prevpoint, prev_co); } else { snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR; @@ -286,7 +290,7 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, float dist_px = 12.0f * U.pixelsize; ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz); - snap_elem = ED_transform_snap_object_project_view3d_ex(gizmo_snap->snap_context_v3d, + snap_elem = ED_transform_snap_object_project_view3d_ex(snap_gizmo->snap_context_v3d, depsgraph, snap_elements, &(const struct SnapObjectParams){ @@ -320,14 +324,15 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, snap_elem_index[2] = index; } - gizmo_snap->snap_elem = snap_elem; - RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_location, co); - RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_normal, no); - RNA_property_int_set_array(gz->ptr, gizmo_snap->prop_elem_index, snap_elem_index); + snap_gizmo->snap_elem = snap_elem; + RNA_property_float_set_array(gz->ptr, snap_gizmo->prop_location, co); + RNA_property_float_set_array(gz->ptr, snap_gizmo->prop_normal, no); + RNA_property_int_set_array(gz->ptr, snap_gizmo->prop_elem_index, snap_elem_index); if (r_loc) { copy_v3_v3(r_loc, co); } + if (r_nor) { copy_v3_v3(r_nor, no); } @@ -341,18 +346,18 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, /** \name GIZMO_GT_snap_3d * \{ */ -static void gizmo_snap_setup(wmGizmo *gz) +static void snap_gizmo_setup(wmGizmo *gz) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; /* For quick access to the props. */ - gizmo_snap->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point"); - gizmo_snap->prop_location = RNA_struct_find_property(gz->ptr, "location"); - gizmo_snap->prop_normal = RNA_struct_find_property(gz->ptr, "normal"); - gizmo_snap->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index"); - gizmo_snap->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force"); + snap_gizmo->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point"); + snap_gizmo->prop_location = RNA_struct_find_property(gz->ptr, "location"); + snap_gizmo->prop_normal = RNA_struct_find_property(gz->ptr, "normal"); + snap_gizmo->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index"); + snap_gizmo->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force"); - gizmo_snap->use_snap_override = -1; + snap_gizmo->use_snap_override = -1; /* Prop fallback. */ WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1); @@ -361,10 +366,10 @@ static void gizmo_snap_setup(wmGizmo *gz) gz->flag |= WM_GIZMO_NO_TOOLTIP; } -static void gizmo_snap_draw(const bContext *C, wmGizmo *gz) +static void snap_gizmo_draw(const bContext *C, wmGizmo *gz) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; - if (gizmo_snap->snap_elem == 0) { + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + if (snap_gizmo->snap_elem == 0) { return; } @@ -376,22 +381,22 @@ static void gizmo_snap_draw(const bContext *C, wmGizmo *gz) * And `snap_elem` is not really useful in this case. */ if ((rv3d->rflag & RV3D_NAVIGATING) || (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) { - gizmo_snap->snap_elem = 0; + snap_gizmo->snap_elem = 0; return; } float location[3], prev_point_stack[3], *prev_point = NULL; uchar color_line[4], color_point[4]; - RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_location, location); + RNA_property_float_get_array(gz->ptr, snap_gizmo->prop_location, location); UI_GetThemeColor3ubv(TH_TRANSFORM, color_line); color_line[3] = 128; rgba_float_to_uchar(color_point, gz->color); - if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) { - RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_point_stack); + if (RNA_property_is_set(gz->ptr, snap_gizmo->prop_prevpoint)) { + RNA_property_float_get_array(gz->ptr, snap_gizmo->prop_prevpoint, prev_point_stack); prev_point = prev_point_stack; } @@ -399,35 +404,36 @@ static void gizmo_snap_draw(const bContext *C, wmGizmo *gz) GPU_line_width(1.0f); ED_gizmotypes_snap_3d_draw_util( - rv3d, prev_point, location, NULL, color_line, color_point, gizmo_snap->snap_elem); + rv3d, prev_point, location, NULL, color_line, color_point, snap_gizmo->snap_elem); } -static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2]) +static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK wmWindowManager *wm = CTX_wm_manager(C); - if (gizmo_snap->keymap == NULL) { - gizmo_snap->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); - RNA_enum_value_from_id(gizmo_snap->keymap->modal_items, "SNAP_ON", &gizmo_snap->snap_on); + if (snap_gizmo->keymap == NULL) { + snap_gizmo->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); + RNA_enum_value_from_id(snap_gizmo->keymap->modal_items, "SNAP_ON", &snap_gizmo->snap_on); } - const bool invert = wm->winactive ? invert_snap(gz, wm, wm->winactive->eventstate) : false; - if (gizmo_snap->invert_snap == invert && gizmo_snap->mval[0] == mval[0] && - gizmo_snap->mval[1] == mval[1]) { + const bool invert = wm->winactive ? invert_snap(snap_gizmo, wm, wm->winactive->eventstate) : + false; + if (snap_gizmo->invert_snap == invert && snap_gizmo->mval[0] == mval[0] && + snap_gizmo->mval[1] == mval[1]) { /* Performance, do not update. */ - return gizmo_snap->snap_elem ? 0 : -1; + return snap_gizmo->snap_elem ? 0 : -1; } - gizmo_snap->invert_snap = invert; + snap_gizmo->invert_snap = invert; #else - if (gizmo_snap->mval[0] == mval[0] && gizmo_snap->mval[1] == mval[1]) { + if (snap_gizmo->mval[0] == mval[0] && snap_gizmo->mval[1] == mval[1]) { /* Performance, do not update. */ - return gizmo_snap->snap_elem ? 0 : -1; + return snap_gizmo->snap_elem ? 0 : -1; } #endif - copy_v2_v2_int(gizmo_snap->mval, mval); + copy_v2_v2_int(snap_gizmo->mval, mval); ARegion *region = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); @@ -443,7 +449,7 @@ static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2]) return -1; } -static int gizmo_snap_modal(bContext *UNUSED(C), +static int snap_gizmo_modal(bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event), eWM_GizmoFlagTweak UNUSED(tweak_flag)) @@ -451,19 +457,19 @@ static int gizmo_snap_modal(bContext *UNUSED(C), return OPERATOR_RUNNING_MODAL; } -static int gizmo_snap_invoke(bContext *UNUSED(C), +static int snap_gizmo_invoke(bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event)) { return OPERATOR_RUNNING_MODAL; } -static void gizmo_snap_free(wmGizmo *gz) +static void snap_gizmo_free(wmGizmo *gz) { - SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; - if (gizmo_snap->snap_context_v3d) { - ED_transform_snap_object_context_destroy(gizmo_snap->snap_context_v3d); - gizmo_snap->snap_context_v3d = NULL; + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + if (snap_gizmo->snap_context_v3d) { + ED_transform_snap_object_context_destroy(snap_gizmo->snap_context_v3d); + snap_gizmo->snap_context_v3d = NULL; } } @@ -473,12 +479,12 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt) gzt->idname = "GIZMO_GT_snap_3d"; /* api callbacks */ - gzt->setup = gizmo_snap_setup; - gzt->draw = gizmo_snap_draw; - gzt->test_select = gizmo_snap_test_select; - gzt->modal = gizmo_snap_modal; - gzt->invoke = gizmo_snap_invoke; - gzt->free = gizmo_snap_free; + gzt->setup = snap_gizmo_setup; + gzt->draw = snap_gizmo_draw; + gzt->test_select = snap_gizmo_test_select; + gzt->modal = snap_gizmo_modal; + gzt->invoke = snap_gizmo_invoke; + gzt->free = snap_gizmo_free; gzt->struct_size = sizeof(SnapGizmo3D); diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index c260085e763..87d3b6cf9c6 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -202,6 +202,8 @@ typedef struct tGPDprimitive { tGPspoint *points; /** number of edges allocated */ int point_count; + /** number of subdivisions. */ + int subdiv; /** stored number of polygon edges */ int tot_stored_edges; /** number of polygon edges */ @@ -559,7 +561,11 @@ void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot); /* primitives ---------- */ -void GPENCIL_OT_primitive(struct wmOperatorType *ot); +void GPENCIL_OT_primitive_box(struct wmOperatorType *ot); +void GPENCIL_OT_primitive_line(struct wmOperatorType *ot); +void GPENCIL_OT_primitive_polyline(struct wmOperatorType *ot); +void GPENCIL_OT_primitive_circle(struct wmOperatorType *ot); +void GPENCIL_OT_primitive_curve(struct wmOperatorType *ot); /* vertex groups ------------ */ void GPENCIL_OT_vertex_group_assign(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 04e3a0dd5b6..2713e6b0f54 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -587,42 +587,14 @@ static int gpencil_stroke_merge_material_exec(bContext *C, wmOperator *op) const float val_threshold = RNA_float_get(op->ptr, "val_threshold"); /* Review materials. */ - GHash *mat_table = BLI_ghash_int_new(__func__); - short *totcol = BKE_object_material_len_p(ob); if (totcol == 0) { return OPERATOR_CANCELLED; } - bool changed = BKE_gpencil_merge_materials_table_get( - ob, hue_threshold, sat_threshold, val_threshold, mat_table); - - int removed = BLI_ghash_len(mat_table); - - /* Update stroke material index. */ - if (changed) { - CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { - continue; - } - - if (BLI_ghash_haskey(mat_table, POINTER_FROM_INT(gps->mat_nr))) { - int *idx = BLI_ghash_lookup(mat_table, POINTER_FROM_INT(gps->mat_nr)); - gps->mat_nr = POINTER_AS_INT(idx); - } - } - } - } - CTX_DATA_END; - } - - /* Free hash memory. */ - BLI_ghash_free(mat_table, NULL, NULL); + int removed; + bool changed = BKE_gpencil_merge_materials( + ob, hue_threshold, sat_threshold, val_threshold, &removed); /* notifiers */ if (changed) { diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 8561985ec07..18b096d599b 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -687,7 +687,11 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_interpolate_reverse); /* Primitives */ - WM_operatortype_append(GPENCIL_OT_primitive); + WM_operatortype_append(GPENCIL_OT_primitive_box); + WM_operatortype_append(GPENCIL_OT_primitive_line); + WM_operatortype_append(GPENCIL_OT_primitive_polyline); + WM_operatortype_append(GPENCIL_OT_primitive_circle); + WM_operatortype_append(GPENCIL_OT_primitive_curve); /* convert old 2.7 files to 2.8 */ WM_operatortype_append(GPENCIL_OT_convert_old_files); diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 5cdb32eb535..9573581d6fd 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -109,7 +109,15 @@ /* ************************************************ */ /* Core/Shared Utilities */ - +static const EnumPropertyItem gpencil_primitive_type[] = { + {GP_STROKE_BOX, "BOX", 0, "Box", ""}, + {GP_STROKE_LINE, "LINE", 0, "Line", ""}, + {GP_STROKE_POLYLINE, "POLYLINE", 0, "Polyline", ""}, + {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""}, + {GP_STROKE_ARC, "ARC", 0, "Arc", ""}, + {GP_STROKE_CURVE, "CURVE", 0, "Curve", ""}, + {0, NULL, 0, NULL, NULL}, +}; /* clear the session buffers (call this before AND after a paint operation) */ static void gpencil_session_validatebuffer(tGPDprimitive *p) { @@ -427,19 +435,20 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi } else if (tgpi->type == GP_STROKE_CIRCLE) { BLI_strncpy(msg_str, - TIP_("Circle: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge " + TIP_("Circle: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust subdivision " "number, Shift to square, Alt to center"), UI_MAX_DRAW_STR); } else if (tgpi->type == GP_STROKE_ARC) { - BLI_strncpy(msg_str, - TIP_("Arc: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge number, " - "Shift to square, Alt to center, M: Flip, E: extrude"), - UI_MAX_DRAW_STR); + BLI_strncpy( + msg_str, + TIP_("Arc: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust subdivision number, " + "Shift to square, Alt to center, M: Flip, E: extrude"), + UI_MAX_DRAW_STR); } else if (tgpi->type == GP_STROKE_CURVE) { BLI_strncpy(msg_str, - TIP_("Curve: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust edge " + TIP_("Curve: ESC to cancel, Enter/MMB to confirm, WHEEL/+- to adjust subdivision " "number, Shift to square, Alt to center, E: extrude"), UI_MAX_DRAW_STR); } @@ -519,16 +528,23 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D coords[4][0] = tgpi->start[0]; coords[4][1] = tgpi->start[1]; - const float step = 1.0f / (float)(tgpi->tot_edges); - int i = tgpi->tot_stored_edges; - - for (int j = 0; j < 4; j++) { - float a = 0.0f; - for (int k = 0; k < tgpi->tot_edges; k++) { - tGPspoint *p2d = &points2D[i]; - interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a); - a += step; - i++; + if (tgpi->tot_edges == 1) { + for (int j = 0; j < 4; j++) { + tGPspoint *p2d = &points2D[j]; + copy_v2_v2(&p2d->x, coords[j]); + } + } + else { + const float step = 1.0f / (float)(tgpi->tot_edges); + int i = tgpi->tot_stored_edges; + for (int j = 0; j < 4; j++) { + float a = 0.0f; + for (int k = 0; k < tgpi->tot_edges; k++) { + tGPspoint *p2d = &points2D[i]; + interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a); + a += step; + i++; + } } } @@ -701,6 +717,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth); if (tgpi->type == GP_STROKE_BOX) { + tgpi->tot_edges--; gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges); } else { @@ -716,7 +733,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* compute screen-space coordinates for points */ tGPspoint *points2D = tgpi->points; - if (tgpi->tot_edges > 1) { + if (tgpi->tot_edges > 0) { switch (tgpi->type) { case GP_STROKE_BOX: gpencil_primitive_rectangle(tgpi, points2D); @@ -1211,31 +1228,10 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) tgpi->curve = false; } - /* set default edge count */ - switch (tgpi->type) { - case GP_STROKE_POLYLINE: { - RNA_int_set(op->ptr, "edges", 8); - break; - } - case GP_STROKE_LINE: { - RNA_int_set(op->ptr, "edges", 8); - break; - } - case GP_STROKE_BOX: { - RNA_int_set(op->ptr, "edges", 8); - break; - } - case GP_STROKE_CIRCLE: { - RNA_int_set(op->ptr, "edges", 96); - break; - } - default: { - RNA_int_set(op->ptr, "edges", 64); - break; - } - } - tgpi->tot_stored_edges = 0; + + tgpi->subdiv = RNA_int_get(op->ptr, "subdivision"); + RNA_int_set(op->ptr, "edges", tgpi->subdiv + 2); tgpi->tot_edges = RNA_int_get(op->ptr, "edges"); tgpi->flag = IDLE; tgpi->lock_axis = ts->gp_sculpt.lock_axis; @@ -1351,11 +1347,6 @@ static void gpencil_primitive_interaction_end(bContext *C, } } - /* Close stroke with geometry */ - if ((tgpi->type == GP_STROKE_BOX) || (tgpi->type == GP_STROKE_CIRCLE)) { - BKE_gpencil_stroke_close(gps); - } - DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE); DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -1629,9 +1620,12 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case RIGHTMOUSE: { if (event->val == KM_PRESS) { tgpi->flag = IDLE; + int last_edges = tgpi->tot_edges; tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0; + RNA_int_set(op->ptr, "edges", tgpi->tot_edges); gpencil_primitive_update_strokes(C, tgpi); gpencil_primitive_interaction_end(C, op, win, tgpi); + RNA_int_set(op->ptr, "edges", last_edges); return OPERATOR_FINISHED; } break; @@ -1958,22 +1952,45 @@ static void gpencil_primitive_cancel(bContext *C, wmOperator *op) gpencil_primitive_exit(C, op); } -void GPENCIL_OT_primitive(wmOperatorType *ot) +static void gpencil_primitive_common_props(wmOperatorType *ot, int subdiv, int type) { - static EnumPropertyItem primitive_type[] = { - {GP_STROKE_BOX, "BOX", 0, "Box", ""}, - {GP_STROKE_LINE, "LINE", 0, "Line", ""}, - {GP_STROKE_POLYLINE, "POLYLINE", 0, "Polyline", ""}, - {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""}, - {GP_STROKE_ARC, "ARC", 0, "Arc", ""}, - {GP_STROKE_CURVE, "CURVE", 0, "Curve", ""}, - {0, NULL, 0, NULL, NULL}, - }; + PropertyRNA *prop; + prop = RNA_def_int(ot->srna, + "subdivision", + subdiv, + 0, + MAX_EDGES, + "Subdivisions", + "Number of subdivision by edges", + 0, + MAX_EDGES); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + /* Internal prop. */ + prop = RNA_def_int(ot->srna, + "edges", + MIN_EDGES, + MIN_EDGES, + MAX_EDGES, + "Edges", + "Number of points by edge", + MIN_EDGES, + MAX_EDGES); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + + RNA_def_enum(ot->srna, "type", gpencil_primitive_type, type, "Type", "Type of shape"); + + prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + +void GPENCIL_OT_primitive_box(wmOperatorType *ot) +{ /* identifiers */ - ot->name = "Grease Pencil Shapes"; - ot->idname = "GPENCIL_OT_primitive"; - ot->description = "Create predefined grease pencil stroke shapes"; + ot->name = "Grease Pencil Box Shape"; + ot->idname = "GPENCIL_OT_primitive_box"; + ot->description = "Create predefined grease pencil stroke box shapes"; /* callbacks */ ot->invoke = gpencil_primitive_invoke; @@ -1982,24 +1999,88 @@ void GPENCIL_OT_primitive(wmOperatorType *ot) ot->poll = gpencil_primitive_add_poll; /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; /* properties */ - PropertyRNA *prop; + gpencil_primitive_common_props(ot, 3, GP_STROKE_BOX); +} - prop = RNA_def_int(ot->srna, - "edges", - 4, - MIN_EDGES, - MAX_EDGES, - "Edges", - "Number of polygon edges", - MIN_EDGES, - MAX_EDGES); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); +void GPENCIL_OT_primitive_line(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Line Shape"; + ot->idname = "GPENCIL_OT_primitive_line"; + ot->description = "Create predefined grease pencil stroke lines"; + + /* callbacks */ + ot->invoke = gpencil_primitive_invoke; + ot->modal = gpencil_primitive_modal; + ot->cancel = gpencil_primitive_cancel; + ot->poll = gpencil_primitive_add_poll; - RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape"); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; - prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* properties */ + gpencil_primitive_common_props(ot, 6, GP_STROKE_LINE); +} + +void GPENCIL_OT_primitive_polyline(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Polyline Shape"; + ot->idname = "GPENCIL_OT_primitive_polyline"; + ot->description = "Create predefined grease pencil stroke polylines"; + + /* callbacks */ + ot->invoke = gpencil_primitive_invoke; + ot->modal = gpencil_primitive_modal; + ot->cancel = gpencil_primitive_cancel; + ot->poll = gpencil_primitive_add_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* properties */ + gpencil_primitive_common_props(ot, 6, GP_STROKE_POLYLINE); +} + +void GPENCIL_OT_primitive_circle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Circle Shape"; + ot->idname = "GPENCIL_OT_primitive_circle"; + ot->description = "Create predefined grease pencil stroke circle shapes"; + + /* callbacks */ + ot->invoke = gpencil_primitive_invoke; + ot->modal = gpencil_primitive_modal; + ot->cancel = gpencil_primitive_cancel; + ot->poll = gpencil_primitive_add_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* properties */ + gpencil_primitive_common_props(ot, 94, GP_STROKE_CIRCLE); +} + +void GPENCIL_OT_primitive_curve(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Curve Shape"; + ot->idname = "GPENCIL_OT_primitive_curve"; + ot->description = "Create predefined grease pencil stroke curve shapes"; + + /* callbacks */ + ot->invoke = gpencil_primitive_invoke; + ot->modal = gpencil_primitive_modal; + ot->cancel = gpencil_primitive_cancel; + ot->poll = gpencil_primitive_add_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* properties */ + gpencil_primitive_common_props(ot, 62, GP_STROKE_CURVE); } diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index 34731e1270c..fbb1e0dcb08 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -819,7 +819,7 @@ static void gpencil_save_selected_point(tGP_BrushVertexpaintData *gso, gso->pbuffer_used++; } -/* Select points in this stroke and add to an array to be used later. +/* Select points in this stroke and add to an array to be used later. * Returns true if any point was hit and got saved */ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index c02b4da3599..5d936cdfaa3 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1715,7 +1715,7 @@ struct Panel *UI_panel_add_instanced(struct ScrArea *area, char *panel_idname, int list_index, struct PointerRNA *custom_data); -void UI_panels_free_instanced(struct bContext *C, struct ARegion *region); +void UI_panels_free_instanced(const struct bContext *C, struct ARegion *region); #define LIST_PANEL_UNIQUE_STR_LEN 4 void UI_list_panel_unique_str(struct Panel *panel, char *r_name); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 6e0f4434b7b..1bd9b3063bd 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -120,6 +120,12 @@ void UI_view2d_curRect_validate(struct View2D *v2d); void UI_view2d_curRect_reset(struct View2D *v2d); void UI_view2d_sync(struct bScreen *screen, struct ScrArea *area, struct View2D *v2dcur, int flag); +/* Perform all required updates after `v2d->cur` as been modified. + * This includes like validation view validation (UI_view2d_curRect_validate). + * + * Current lintent is to use it from user code, such as view navigation and zoom operations. */ +void UI_view2d_curRect_changed(const struct bContext *C, struct View2D *v2d); + void UI_view2d_totRect_set(struct View2D *v2d, int width, int height); void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize); diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index cc58082cb02..56df49981e0 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -312,8 +312,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) { - const int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex; - ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, rnaindex, cfra); + ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra); } void ui_but_anim_copy_driver(bContext *C) diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 05f6e61ff40..44c3ccccda8 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -2083,7 +2083,6 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, /* Curve filled. */ immUniformColor3ubvAlpha(wcol->item, 128); - GPU_polygon_smooth(true); immBegin(GPU_PRIM_TRI_STRIP, (CM_TABLE * 2 + 2) + 4); immVertex2f(pos, line_range.xmin, rect->ymin); immVertex2f(pos, line_range.xmin, line_range.ymin); @@ -2096,7 +2095,6 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, immVertex2f(pos, line_range.xmax, rect->ymin); immVertex2f(pos, line_range.xmax, line_range.ymax); immEnd(); - GPU_polygon_smooth(false); /* Curve line. */ GPU_line_width(1.0f); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 799a3b7fd5e..d334007a097 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -117,7 +117,9 @@ typedef struct PanelSort { static int get_panel_real_size_y(const Panel *panel); static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state); static int compare_panel(const void *a1, const void *a2); -static bool panel_type_context_poll(PanelType *panel_type, const char *context); +static bool panel_type_context_poll(ARegion *region, + const PanelType *panel_type, + const char *context); static void panel_title_color_get(bool show_background, uchar color[4]) { @@ -370,7 +372,7 @@ static void panel_delete(const bContext *C, ARegion *region, ListBase *panels, P * \note Can be called with NULL \a C, but it should be avoided because * handlers might not be removed. */ -void UI_panels_free_instanced(bContext *C, ARegion *region) +void UI_panels_free_instanced(const bContext *C, ARegion *region) { /* Delete panels with the instanced flag. */ LISTBASE_FOREACH_MUTABLE (Panel *, panel, ®ion->panels) { @@ -460,14 +462,17 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr return; } - char *context = drag_panel->type->context; + char *context = NULL; + if (!UI_panel_category_is_visible(region)) { + context = drag_panel->type->context; + } /* Find how many instanced panels with this context string. */ int list_panels_len = 0; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->type) { - if (panel_type_context_poll(panel->type, context)) { - if (panel->type->flag & PNL_INSTANCED) { + if (panel->type->flag & PNL_INSTANCED) { + if (panel_type_context_poll(region, panel->type, context)) { list_panels_len++; } } @@ -479,8 +484,8 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr PanelSort *sort_index = panel_sort; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->type) { - if (panel_type_context_poll(panel->type, context)) { - if (panel->type->flag & PNL_INSTANCED) { + if (panel->type->flag & PNL_INSTANCED) { + if (panel_type_context_poll(region, panel->type, context)) { sort_index->panel = MEM_dupallocN(panel); sort_index->orig = panel; sort_index++; @@ -657,11 +662,18 @@ static void panels_collapse_all(const bContext *C, set_panels_list_data_expand_flag(C, region); } -static bool panel_type_context_poll(PanelType *panel_type, const char *context) +static bool panel_type_context_poll(ARegion *region, + const PanelType *panel_type, + const char *context) { + if (UI_panel_category_is_visible(region)) { + return STREQ(panel_type->category, UI_panel_category_active_get(region, false)); + } + if (panel_type->context[0] && STREQ(panel_type->context, context)) { return true; } + return false; } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 56807621358..cdfe6120eee 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -572,6 +572,15 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) if (override_id != NULL) { BKE_main_id_clear_newpoins(bmain); + if (GS(override_id->name) == ID_OB) { + Scene *scene = CTX_data_scene(C); + if (!BKE_collection_has_object_recursive(scene->master_collection, + (Object *)override_id)) { + BKE_collection_object_add_from( + bmain, scene, (Object *)id, (Object *)override_id); + } + } + /* Assign new pointer, takes care of updates/notifiers */ RNA_id_pointer_create(override_id, &idptr); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index c4de2730600..1be62e535de 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1181,12 +1181,7 @@ void UI_widgetbase_draw_cache_flush(void) MAX_WIDGET_PARAMETERS * MAX_WIDGET_BASE_BATCH, (float *)g_widget_base_batch.params); GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); - GPU_matrix_bind(batch->interface); - GPU_shader_set_srgb_uniform(batch->interface); - GPU_batch_bind(batch); - GPU_batch_draw_advanced(batch, 0, 0, 0, g_widget_base_batch.count); - - GPU_batch_program_use_end(batch); + GPU_batch_draw_instanced(batch, g_widget_base_batch.count); } g_widget_base_batch.count = 0; } diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 3efed43e08c..f15a95880f8 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -853,6 +853,17 @@ void UI_view2d_curRect_validate(View2D *v2d) ui_view2d_curRect_validate_resize(v2d, false); } +void UI_view2d_curRect_changed(const bContext *C, View2D *v2d) +{ + UI_view2d_curRect_validate(v2d); + + ARegion *region = CTX_wm_region(C); + + if (region->type->on_view2d_changed != NULL) { + region->type->on_view2d_changed(C, region); + } +} + /* ------------------ */ /* Called by menus to activate it, or by view2d operators diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index d62058699d9..7caa61ec91d 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -185,8 +185,8 @@ static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float v2d->cur.ymax += dy; } - /* validate that view is in valid configuration after this operation */ - UI_view2d_curRect_validate(v2d); + /* Inform v2d about changes after this operation. */ + UI_view2d_curRect_changed(C, v2d); /* don't rebuild full tree in outliner, since we're just changing our view */ ED_region_tag_redraw_no_rebuild(vpd->region); @@ -957,8 +957,8 @@ static void view_zoomstep_apply_ex( } } - /* validate that view is in valid configuration after this operation */ - UI_view2d_curRect_validate(v2d); + /* Inform v2d about changes after this operation. */ + UI_view2d_curRect_changed(C, v2d); if (ED_region_snap_size_apply(region, snap_test)) { ScrArea *area = CTX_wm_area(C); @@ -1216,8 +1216,8 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op) } } - /* validate that view is in valid configuration after this operation */ - UI_view2d_curRect_validate(v2d); + /* Inform v2d about changes after this operation. */ + UI_view2d_curRect_changed(C, v2d); if (ED_region_snap_size_apply(vzd->region, snap_test)) { ScrArea *area = CTX_wm_area(C); @@ -1806,7 +1806,7 @@ void UI_view2d_smooth_view(bContext *C, ARegion *region, const rctf *cur, const if (ok == false) { v2d->cur = sms.new_cur; - UI_view2d_curRect_validate(v2d); + UI_view2d_curRect_changed(C, v2d); ED_region_tag_redraw_no_rebuild(region); UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); } @@ -1853,7 +1853,7 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w BLI_rctf_interp(&v2d->cur, &sms->orig_cur, &sms->new_cur, step); } - UI_view2d_curRect_validate(v2d); + UI_view2d_curRect_changed(C, v2d); UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); ED_region_tag_redraw_no_rebuild(region); @@ -2176,8 +2176,8 @@ static void scroller_activate_apply(bContext *C, wmOperator *op) break; } - /* validate that view is in valid configuration after this operation */ - UI_view2d_curRect_validate(v2d); + /* Inform v2d about changes after this operation. */ + UI_view2d_curRect_changed(C, v2d); /* request updates to be done... */ ED_region_tag_redraw_no_rebuild(vsm->region); @@ -2410,8 +2410,8 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op)) } } - /* validate that view is in valid configuration after this operation */ - UI_view2d_curRect_validate(v2d); + /* Inform v2d about changes after this operation. */ + UI_view2d_curRect_changed(C, v2d); if (ED_region_snap_size_apply(region, snap_test)) { ScrArea *area = CTX_wm_area(C); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 6f4f75e802a..b02e48a652e 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1147,16 +1147,13 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); - GPU_batch_bind(batch); /* draw any snapped verts first */ rgba_uchar_to_float(fcol, kcd->colors.point_a); GPU_batch_uniform_4fv(batch, "color", fcol); - GPU_matrix_bind(batch->interface); - GPU_shader_set_srgb_uniform(batch->interface); GPU_point_size(11); if (snapped_verts_count > 0) { - GPU_batch_draw_advanced(batch, 0, snapped_verts_count, 0, 0); + GPU_batch_draw_range(batch, 0, snapped_verts_count); } /* now draw the rest */ @@ -1164,10 +1161,9 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v GPU_batch_uniform_4fv(batch, "color", fcol); GPU_point_size(7); if (other_verts_count > 0) { - GPU_batch_draw_advanced(batch, snapped_verts_count, other_verts_count, 0, 0); + GPU_batch_draw_range(batch, snapped_verts_count, other_verts_count); } - GPU_batch_program_use_end(batch); GPU_batch_discard(batch); GPU_blend(false); diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 2f453369d92..b57e486634f 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -174,8 +174,10 @@ static void ringsel_finish(bContext *C, wmOperator *op) if (lcd->do_cut) { const bool is_macro = (op->opm != NULL); /* a single edge (rare, but better support) */ - const bool is_single = (BM_edge_is_wire(lcd->eed)); - const int seltype = is_single ? SUBDIV_SELECT_INNER : SUBDIV_SELECT_LOOPCUT; + const bool is_edge_wire = BM_edge_is_wire(lcd->eed); + const bool is_single = is_edge_wire || !BM_edge_is_any_face_len_test(lcd->eed, 4); + const int seltype = is_edge_wire ? SUBDIV_SELECT_INNER : + is_single ? SUBDIV_SELECT_NONE : SUBDIV_SELECT_LOOPCUT; /* Enable gridfill, so that intersecting loopcut works as one would expect. * Note though that it will break edgeslide in this specific case. diff --git a/source/blender/editors/mesh/editmesh_preselect_edgering.c b/source/blender/editors/mesh/editmesh_preselect_edgering.c index 50af79fc5e1..d9bd63ef35f 100644 --- a/source/blender/editors/mesh/editmesh_preselect_edgering.c +++ b/source/blender/editors/mesh/editmesh_preselect_edgering.c @@ -343,12 +343,12 @@ void EDBM_preselect_edgering_update_from_edge(struct EditMesh_PreSelEdgeRing *ps BM_mesh_elem_index_ensure(bm, BM_VERT); } - if (BM_edge_is_wire(eed_start)) { - view3d_preselect_mesh_edgering_update_verts_from_edge( + if (BM_edge_is_any_face_len_test(eed_start, 4)) { + view3d_preselect_mesh_edgering_update_edges_from_edge( psel, bm, eed_start, previewlines, coords); } else { - view3d_preselect_mesh_edgering_update_edges_from_edge( + view3d_preselect_mesh_edgering_update_verts_from_edge( psel, bm, eed_start, previewlines, coords); } } diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index b96eeedd86f..5278da67777 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -1063,7 +1063,7 @@ static float *editmesh_get_mirror_uv( BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - uv_poly_center(efa, cent, cd_loop_uv_offset); + BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); if ((fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f)) { BMIter liter; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 81b8cd70353..139900d0a4d 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2647,7 +2647,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) ob_gpencil = ED_gpencil_add_object(C, ob->loc, local_view_bits); copy_v3_v3(ob_gpencil->rot, ob->rot); copy_v3_v3(ob_gpencil->scale, ob->scale); - BKE_gpencil_convert_curve(bmain, scene, ob_gpencil, ob, false, false, true); + BKE_gpencil_convert_curve(bmain, scene, ob_gpencil, ob, false, 1.0f, 0.0f); gpencilConverted = true; } } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index cb92fab3cb0..eb8b976320f 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1596,9 +1596,8 @@ static void bake_set_props(wmOperator *op, Scene *scene) prop = RNA_struct_find_property(op->ptr, "cage_object"); if (!RNA_property_is_set(op->ptr, prop)) { - if (bake->cage_object) { - RNA_property_string_set(op->ptr, prop, bake->cage_object->id.name + 2); - } + RNA_property_string_set( + op->ptr, prop, (bake->cage_object) ? bake->cage_object->id.name + 2 : ""); } prop = RNA_struct_find_property(op->ptr, "normal_space"); diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 5a0656ee916..8bec200cb40 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -766,7 +766,7 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot) static bool datalayout_transfer_poll(bContext *C) { - return (edit_modifier_poll_generic(C, &RNA_DataTransferModifier, (1 << OB_MESH), true) || + return (edit_modifier_poll_generic(C, &RNA_DataTransferModifier, (1 << OB_MESH), true, false) || data_transfer_poll(C)); } diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index 019ab2c345b..cfa55c68a56 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -412,28 +412,30 @@ void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot) /********** generic functions for operators using mod names and data context *********************/ -static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) +static bool gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) { PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); + GpencilModifierData *mod = ptr.data; /* May be NULL. */ if (!ob || ID_IS_LINKED(ob)) { - return 0; + return false; } if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) { - return 0; + return false; } if (ptr.owner_id && ID_IS_LINKED(ptr.owner_id)) { - return 0; + return false; } if (ID_IS_OVERRIDE_LIBRARY(ob)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); - return (((GpencilModifierData *)ptr.data)->flag & - eGpencilModifierFlag_OverrideLibrary_Local) != 0; + if ((mod == NULL) || (mod->flag & eGpencilModifierFlag_OverrideLibrary_Local) == 0) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); + return false; + } } - return 1; + return true; } static bool gpencil_edit_modifier_poll(bContext *C) diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index bc3c263e0a3..50825ae1ae4 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -149,8 +149,8 @@ void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot); bool edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag, - const bool is_editmode_allowed); -bool edit_modifier_poll(struct bContext *C); + const bool is_editmode_allowed, + const bool is_liboverride_allowed); void edit_modifier_properties(struct wmOperatorType *ot); bool edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op, diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 8d6d2e3e31d..ceb6553bdf6 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -895,6 +895,8 @@ int ED_object_modifier_copy( BLI_insertlinkafter(&ob->modifiers, md, nmd); BKE_modifier_unique_name(&ob->modifiers, nmd); + nmd->flag |= eModifierFlag_OverrideLibrary_Local; + return 1; } @@ -1005,7 +1007,8 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot) bool edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag, - const bool is_editmode_allowed) + const bool is_editmode_allowed, + const bool is_liboverride_allowed) { PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); @@ -1021,8 +1024,8 @@ bool edit_modifier_poll_generic(bContext *C, return false; } - if (ID_IS_OVERRIDE_LIBRARY(ob)) { - if ((mod != NULL) && (mod->flag & eModifierFlag_OverrideLibrary_Local) == 0) { + if (ID_IS_OVERRIDE_LIBRARY(ob) && !is_liboverride_allowed) { + if ((mod == NULL) || (mod->flag & eModifierFlag_OverrideLibrary_Local) == 0) { CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); return false; } @@ -1036,9 +1039,16 @@ bool edit_modifier_poll_generic(bContext *C, return true; } -bool edit_modifier_poll(bContext *C) +static bool edit_modifier_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_Modifier, 0, true); + return edit_modifier_poll_generic(C, &RNA_Modifier, 0, true, false); +} + +/* Used by operators performing actions allowed also on modifiers from the overridden linked object + * (not only from added 'local' ones). */ +static bool edit_modifier_liboverride_allowed_poll(bContext *C) +{ + return edit_modifier_poll_generic(C, &RNA_Modifier, 0, true, true); } void edit_modifier_properties(wmOperatorType *ot) @@ -1282,11 +1292,6 @@ void OBJECT_OT_modifier_move_down(wmOperatorType *ot) /** \name Move to Index Modifier Operator * \{ */ -static bool modifier_move_to_index_poll(bContext *C) -{ - return edit_modifier_poll(C); -} - static int modifier_move_to_index_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_active_context(C); @@ -1321,7 +1326,7 @@ void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot) ot->invoke = modifier_move_to_index_invoke; ot->exec = modifier_move_to_index_exec; - ot->poll = modifier_move_to_index_poll; + ot->poll = edit_modifier_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; @@ -1338,7 +1343,7 @@ void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot) static bool modifier_apply_poll_ex(bContext *C, bool allow_shared) { - if (!edit_modifier_poll_generic(C, &RNA_Modifier, 0, false)) { + if (!edit_modifier_poll_generic(C, &RNA_Modifier, 0, false, false)) { return false; } @@ -1583,7 +1588,7 @@ void OBJECT_OT_modifier_copy(wmOperatorType *ot) ot->invoke = modifier_copy_invoke; ot->exec = modifier_copy_exec; - ot->poll = edit_modifier_poll; + ot->poll = edit_modifier_liboverride_allowed_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; @@ -1598,7 +1603,7 @@ void OBJECT_OT_modifier_copy(wmOperatorType *ot) static bool multires_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_MultiresModifier, (1 << OB_MESH), true); + return edit_modifier_poll_generic(C, &RNA_MultiresModifier, (1 << OB_MESH), true, false); } static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op) @@ -2107,13 +2112,14 @@ static void modifier_skin_customdata_delete(Object *ob) static bool skin_poll(bContext *C) { - return (edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH), false)); + return (edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH), false, false)); } static bool skin_edit_poll(bContext *C) { Object *ob = CTX_data_edit_object(C); - return (ob != NULL && edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH), true) && + return (ob != NULL && + edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH), true, false) && !ID_IS_OVERRIDE_LIBRARY(ob) && !ID_IS_OVERRIDE_LIBRARY(ob->data)); } @@ -2469,7 +2475,7 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot) static bool correctivesmooth_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0, true); + return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0, true, false); } static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) @@ -2549,7 +2555,7 @@ void OBJECT_OT_correctivesmooth_bind(wmOperatorType *ot) static bool meshdeform_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_MeshDeformModifier, 0, true); + return edit_modifier_poll_generic(C, &RNA_MeshDeformModifier, 0, true, false); } static int meshdeform_bind_exec(bContext *C, wmOperator *op) @@ -2624,7 +2630,7 @@ void OBJECT_OT_meshdeform_bind(wmOperatorType *ot) static bool explode_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_ExplodeModifier, 0, true); + return edit_modifier_poll_generic(C, &RNA_ExplodeModifier, 0, true, false); } static int explode_refresh_exec(bContext *C, wmOperator *op) @@ -2676,7 +2682,7 @@ void OBJECT_OT_explode_refresh(wmOperatorType *ot) static bool ocean_bake_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_OceanModifier, 0, true); + return edit_modifier_poll_generic(C, &RNA_OceanModifier, 0, true, false); } typedef struct OceanBakeJob { @@ -2884,7 +2890,7 @@ void OBJECT_OT_ocean_bake(wmOperatorType *ot) static bool laplaciandeform_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_LaplacianDeformModifier, 0, false); + return edit_modifier_poll_generic(C, &RNA_LaplacianDeformModifier, 0, false, false); } static int laplaciandeform_bind_exec(bContext *C, wmOperator *op) @@ -2961,7 +2967,7 @@ void OBJECT_OT_laplaciandeform_bind(wmOperatorType *ot) static bool surfacedeform_bind_poll(bContext *C) { - return edit_modifier_poll_generic(C, &RNA_SurfaceDeformModifier, 0, true); + return edit_modifier_poll_generic(C, &RNA_SurfaceDeformModifier, 0, true, false); } static int surfacedeform_bind_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c index 977d4abd4d4..e2a30c4ce98 100644 --- a/source/blender/editors/object/object_shader_fx.c +++ b/source/blender/editors/object/object_shader_fx.c @@ -332,23 +332,26 @@ static bool edit_shaderfx_poll_generic(bContext *C, StructRNA *rna_type, int obt { PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type); Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); + ShaderFxData *fx = ptr.data; /* May be NULL. */ if (!ob || ID_IS_LINKED(ob)) { - return 0; + return false; } if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) { - return 0; + return false; } if (ptr.owner_id && ID_IS_LINKED(ptr.owner_id)) { - return 0; + return false; } if (ID_IS_OVERRIDE_LIBRARY(ob)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs coming from library override"); - return (((ShaderFxData *)ptr.data)->flag & eShaderFxFlag_OverrideLibrary_Local) != 0; + if ((fx == NULL) || (fx->flag & eShaderFxFlag_OverrideLibrary_Local) == 0) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs coming from library override"); + return false; + } } - return 1; + return true; } static bool edit_shaderfx_poll(bContext *C) diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 150141eed3a..af146942b2e 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2662,29 +2662,35 @@ void ED_region_panels_layout_ex(const bContext *C, if (has_instanced_panel) { LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->type == NULL) { - continue; /* Some panels don't have a type.. */ + continue; /* Some panels don't have a type. */ } - if (panel->type->flag & PNL_INSTANCED) { - if (panel && UI_panel_is_dragging(panel)) { - /* Prevent View2d.tot rectangle size changes while dragging panels. */ - update_tot_size = false; - } - - /* Use a unique identifier for instanced panels, otherwise an old block for a different - * panel of the same type might be found. */ - char unique_panel_str[8]; - UI_list_panel_unique_str(panel, unique_panel_str); - ed_panel_draw(C, - area, - region, - ®ion->panels, - panel->type, - panel, - (panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w, - em, - vertical, - unique_panel_str); + if (!(panel->type->flag & PNL_INSTANCED)) { + continue; } + if (use_category_tabs && panel->type->category[0] && + !STREQ(category, panel->type->category)) { + continue; + } + + if (panel && UI_panel_is_dragging(panel)) { + /* Prevent View2d.tot rectangle size changes while dragging panels. */ + update_tot_size = false; + } + + /* Use a unique identifier for instanced panels, otherwise an old block for a different + * panel of the same type might be found. */ + char unique_panel_str[8]; + UI_list_panel_unique_str(panel, unique_panel_str); + ed_panel_draw(C, + area, + region, + ®ion->panels, + panel->type, + panel, + (panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w, + em, + vertical, + unique_panel_str); } } diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 40a452a5363..d8d47fb01aa 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -343,6 +343,7 @@ static void drawscredge_area_draw( } GPUBatch *batch = batch_screen_edges_get(NULL); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES); GPU_batch_uniform_4fv(batch, "rect", (float *)&rect); GPU_batch_draw(batch); } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 62720d8ca37..06e800433b1 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -992,6 +992,7 @@ void ED_screen_global_areas_refresh(wmWindow *win) void screen_change_prepare( bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win) { + UNUSED_VARS_NDEBUG(bmain); BLI_assert(BLI_findindex(&bmain->screens, screen_new) != -1); if (screen_old != screen_new) { diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 88998d5063d..d4379262666 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1542,7 +1542,7 @@ static void paint_cursor_preview_boundary_data_update(PaintCursorContext *pconte } ss->boundary_preview = SCULPT_boundary_data_init( - pcontext->vc.obact, ss->active_vertex_index, pcontext->radius); + pcontext->vc.obact, pcontext->brush, ss->active_vertex_index, pcontext->radius); } static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *pcontext) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c87189997f2..d68b1226b40 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -109,7 +109,7 @@ * For multi-resolution, the same vertex in multiple grids is counted multiple times, with * different index for each grid. */ -void SCULPT_vertex_random_access_init(SculptSession *ss) +void SCULPT_vertex_random_access_ensure(SculptSession *ss) { if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { BM_mesh_elem_index_ensure(ss->bm, BM_VERT); @@ -204,6 +204,27 @@ const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index) return SCULPT_vertex_co_get(ss, index); } +void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + case PBVH_BMESH: + copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, index)); + break; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + + SubdivCCGCoord coord = {.grid_index = grid_index, + .x = vertex_index % key->grid_size, + .y = vertex_index / key->grid_size}; + BKE_subdiv_ccg_eval_limit_point(ss->subdiv_ccg, &coord, r_co); + break; + } + } +} + void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]) { if (ss->persistent_base) { @@ -1000,7 +1021,7 @@ bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3], void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood) { int vertex_count = SCULPT_vertex_count_get(ss); - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); flood->queue = BLI_gsqueue_new(sizeof(int)); flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices"); @@ -1921,8 +1942,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, if (use_area_cos && area_test_r) { /* Weight the coordinates towards the center. */ float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius); - float afactor = 3.0f * p * p - 2.0f * p * p * p; - CLAMP(afactor, 0.0f, 1.0f); + const float afactor = clamp_f(3.0f * p * p - 2.0f * p * p * p, 0.0f, 1.0f); float disp[3]; sub_v3_v3v3(disp, co, area_test.location); @@ -1935,8 +1955,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, if (use_area_nos && normal_test_r) { /* Weight the normals towards the center. */ float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius); - float nfactor = 3.0f * p * p - 2.0f * p * p * p; - CLAMP(nfactor, 0.0f, 1.0f); + const float nfactor = clamp_f(3.0f * p * p - 2.0f * p * p * p, 0.0f, 1.0f); mul_v3_fl(no, nfactor); add_v3_v3(anctd->area_nos[flip_index], no); @@ -1997,8 +2016,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, if (use_area_cos && area_test_r) { /* Weight the coordinates towards the center. */ float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius); - float afactor = 3.0f * p * p - 2.0f * p * p * p; - CLAMP(afactor, 0.0f, 1.0f); + const float afactor = clamp_f(3.0f * p * p - 2.0f * p * p * p, 0.0f, 1.0f); float disp[3]; sub_v3_v3v3(disp, co, area_test.location); @@ -2011,8 +2029,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, if (use_area_nos && normal_test_r) { /* Weight the normals towards the center. */ float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius); - float nfactor = 3.0f * p * p - 2.0f * p * p * p; - CLAMP(nfactor, 0.0f, 1.0f); + const float nfactor = clamp_f(3.0f * p * p - 2.0f * p * p * p, 0.0f, 1.0f); mul_v3_fl(no, nfactor); add_v3_v3(anctd->area_nos[flip_index], no); @@ -2240,6 +2257,8 @@ static float brush_strength(const Sculpt *sd, case SCULPT_TOOL_DRAW_SHARP: case SCULPT_TOOL_LAYER: return alpha * flip * pressure * overlap * feather; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + return alpha * pressure * overlap * feather; case SCULPT_TOOL_CLOTH: if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { /* Grab deform uses the same falloff as a regular grab brush. */ @@ -2778,8 +2797,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, return; } - float bstrength = data->strength; - CLAMP(bstrength, 0.0f, 1.0f); + const float bstrength = clamp_f(data->strength, 0.0f, 1.0f); SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( @@ -2818,14 +2836,14 @@ static void bmesh_topology_rake( Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength) { Brush *brush = BKE_paint_brush(&sd->paint); - CLAMP(bstrength, 0.0f, 1.0f); + const float strength = clamp_f(bstrength, 0.0f, 1.0f); /* Interactions increase both strength and quality. */ const int iterations = 3; int iteration; - const int count = iterations * bstrength + 1; - const float factor = iterations * bstrength / count; + const int count = iterations * strength + 1; + const float factor = iterations * strength / count; for (iteration = 0; iteration <= count; iteration++) { @@ -2871,7 +2889,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, else { (*vd.mask) += fade * bstrength * (*vd.mask); } - CLAMP(*vd.mask, 0.0f, 1.0f); + *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f); if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; @@ -2913,6 +2931,73 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } } +/** \name Sculpt Multires Displacement Eraser Brush + * \{ */ + +static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float limit_co[3]; + float disp[3]; + SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); + sub_v3_v3v3(disp, limit_co, vd.co); + mul_v3_v3fl(proxy[vd.i], disp, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings); +} + +/** \} */ + static void do_draw_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) @@ -3193,7 +3278,7 @@ void SCULPT_relax_vertex(SculptSession *ss, } if (avg_count > 0) { - mul_v3_fl(smooth_pos, 1.0f / (float)avg_count); + mul_v3_fl(smooth_pos, 1.0f / avg_count); } else { copy_v3_v3(r_final_pos, vd->co); @@ -4335,10 +4420,10 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, } if (vd.mask) { const float clamp_mask = 1.0f - *vd.mask; - CLAMP(*disp_factor, -clamp_mask, clamp_mask); + *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask); } else { - CLAMP(*disp_factor, -1.0f, 1.0f); + *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f); } float final_co[3]; @@ -5188,7 +5273,7 @@ static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache) for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) { final_pressure += cache->clay_pressure_stabilizer[i]; } - return final_pressure / (float)SCULPT_CLAY_STABILIZER_LEN; + return final_pressure / SCULPT_CLAY_STABILIZER_LEN; } static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) @@ -5229,7 +5314,7 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to * stroke. */ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) { ss->cache->clay_thumb_front_angle += 0.8f; - CLAMP(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f); + ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f); } if (is_zero_v3(ss->cache->grab_delta_symmetry)) { @@ -5705,6 +5790,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe case SCULPT_TOOL_DRAW_FACE_SETS: SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode); break; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + do_displacement_eraser_brush(sd, ob, nodes, totnode); + break; case SCULPT_TOOL_PAINT: SCULPT_do_paint_brush(sd, ob, nodes, totnode); break; @@ -5914,7 +6002,7 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used) SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); - if (is_proxy_used) { + if (is_proxy_used && ss->deform_modifiers_active) { /* This brushes aren't using proxies, so sculpt_combine_proxies() wouldn't propagate needed * deformation to original base. */ @@ -6256,6 +6344,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Cloth Brush"; case SCULPT_TOOL_DRAW_FACE_SETS: return "Draw Face Sets"; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + return "Multires Displacement Eraser"; case SCULPT_TOOL_PAINT: return "Paint Brush"; case SCULPT_TOOL_SMEAR: @@ -6441,9 +6531,12 @@ static void sculpt_update_cache_invariants( mul_m3_v3(mat, viewDir); normalize_v3_v3(cache->true_view_normal, viewDir); - cache->supports_gravity = - (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) && - (sd->gravity_factor > 0.0f)); + cache->supports_gravity = (!ELEM(brush->sculpt_tool, + SCULPT_TOOL_MASK, + SCULPT_TOOL_SMOOTH, + SCULPT_TOOL_SIMPLIFY, + SCULPT_TOOL_DISPLACEMENT_ERASER) && + (sd->gravity_factor > 0.0f)); /* Get gravity vector in world space. */ if (cache->supports_gravity) { if (sd->gravity_object) { @@ -7466,7 +7559,7 @@ static void sculpt_stroke_update_step(bContext *C, else { BKE_pbvh_bmesh_detail_size_set(ss->pbvh, (ss->cache->radius / ss->cache->dyntopo_pixel_radius) * - (float)(sd->detail_size * U.pixelsize) / 0.4f); + (sd->detail_size * U.pixelsize) / 0.4f); } if (SCULPT_stroke_is_dynamic_topology(ss, brush)) { @@ -7701,7 +7794,7 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) SculptSession *ss = ob->sculpt; if (ss) { - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); MEM_SAFE_FREE(ss->persistent_base); @@ -8931,7 +9024,7 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven return OPERATOR_CANCELLED; } - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, * so it needs to be updated here. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c index c475259623a..eef090f484e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c @@ -338,23 +338,23 @@ void SCULPT_automasking_init(Sculpt *sd, Object *ob) } if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) { - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); SCULPT_topology_automasking_init(sd, ob, ss->cache->automask_factor); } if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) { - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); sculpt_face_sets_automasking_init(sd, ob, ss->cache->automask_factor); } if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) { - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_automasking_init(ob, AUTOMASK_INIT_BOUNDARY_EDGES, brush->automasking_boundary_edges_propagation_steps, ss->cache->automask_factor); } if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_automasking_init(ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, brush->automasking_boundary_edges_propagation_steps, diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index a368214cb0b..f65c64d6d78 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -132,10 +132,14 @@ static int BOUNDARY_INDICES_BLOCK_SIZE = 300; static void sculpt_boundary_index_add(SculptBoundary *bdata, const int new_index, + const float distance, GSet *included_vertices) { bdata->vertices[bdata->num_vertices] = new_index; + if (bdata->distance) { + bdata->distance[new_index] = distance; + } if (included_vertices) { BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index)); } @@ -213,7 +217,11 @@ static bool boundary_floodfill_cb( BoundaryFloodFillData *data = userdata; SculptBoundary *bdata = data->bdata; if (SCULPT_vertex_is_boundary(ss, to_v)) { - sculpt_boundary_index_add(bdata, to_v, data->included_vertices); + const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v), + SCULPT_vertex_co_get(ss, to_v)); + const float distance_boundary_to_dst = bdata->distance ? bdata->distance[from_v] + edge_len : + 0.0f; + sculpt_boundary_index_add(bdata, to_v, distance_boundary_to_dst, data->included_vertices); if (!is_duplicate) { sculpt_boundary_preview_edge_add(bdata, from_v, to_v); } @@ -224,11 +232,16 @@ static bool boundary_floodfill_cb( static void sculpt_boundary_indices_init(SculptSession *ss, SculptBoundary *bdata, + const bool init_boundary_distances, const int initial_boundary_index) { + const int totvert = SCULPT_vertex_count_get(ss); bdata->vertices = MEM_malloc_arrayN( BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices"); + if (init_boundary_distances) { + bdata->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances"); + } bdata->edges = MEM_malloc_arrayN( BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptBoundaryPreviewEdge), "boundary edges"); @@ -238,7 +251,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss, bdata->initial_vertex = initial_boundary_index; copy_v3_v3(bdata->initial_vertex_position, SCULPT_vertex_co_get(ss, bdata->initial_vertex)); - sculpt_boundary_index_add(bdata, initial_boundary_index, included_vertices); + sculpt_boundary_index_add(bdata, initial_boundary_index, 0.0f, included_vertices); SCULPT_floodfill_add_initial(&flood, initial_boundary_index); BoundaryFloodFillData fdata = { @@ -407,7 +420,8 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss, */ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, SculptBoundary *bdata, - Brush *brush) + Brush *brush, + const float radius) { const int totvert = SCULPT_vertex_count_get(ss); BKE_curvemapping_init(brush->curve); @@ -417,18 +431,61 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss, bdata->edit_info[i].strength_factor = BKE_brush_curve_strength( brush, bdata->edit_info[i].num_propagation_steps, bdata->max_propagation_steps); } + + if (bdata->edit_info[i].original_vertex == bdata->initial_vertex) { + /* All vertices that are propagated from the original vertex won't be affected by the + * boundary falloff, so there is no need to calculate anything else. */ + continue; + } + + if (!bdata->distance) { + /* There are falloff modes that do not require to modify the previously calculated falloff + * based on boundary distances. */ + continue; + } + + const float boundary_distance = bdata->distance[bdata->edit_info[i].original_vertex]; + float falloff_distance = 0.0f; + float direction = 1.0f; + + switch (brush->boundary_falloff_type) { + case BRUSH_BOUNDARY_FALLOFF_RADIUS: + falloff_distance = boundary_distance; + break; + case BRUSH_BOUNDARY_FALLOFF_LOOP: { + const int div = boundary_distance / radius; + const float mod = fmodf(boundary_distance, radius); + falloff_distance = div % 2 == 0 ? mod : radius - mod; + } break; + case BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT: { + const int div = boundary_distance / radius; + const float mod = fmodf(boundary_distance, radius); + falloff_distance = div % 2 == 0 ? mod : radius - mod; + /* Inverts the faloff in the intervals 1 2 5 6 9 10 ... */ + if (((div - 1) & 2) == 0) { + direction = -1.0f; + } + } break; + case BRUSH_BOUNDARY_FALLOFF_CONSTANT: + /* For constant falloff distances are not allocated, so this should never happen. */ + BLI_assert(false); + } + + bdata->edit_info[i].strength_factor *= direction * BKE_brush_curve_strength( + brush, falloff_distance, radius); } } /* Main function to get SculptBoundary data both for brush deformation and viewport preview. Can * return NULL if there is no boundary from the given vertex using the given radius. */ SculptBoundary *SCULPT_boundary_data_init(Object *object, + Brush *brush, const int initial_vertex, const float radius) { SculptSession *ss = object->sculpt; - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_info_ensure(object); const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex( @@ -446,8 +503,12 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object, SculptBoundary *bdata = MEM_callocN(sizeof(SculptBoundary), "Boundary edit data"); - sculpt_boundary_indices_init(ss, bdata, boundary_initial_vertex); - sculpt_boundary_edit_data_init(ss, bdata, boundary_initial_vertex, radius); + const bool init_boundary_distances = brush->boundary_falloff_type != + BRUSH_BOUNDARY_FALLOFF_CONSTANT; + sculpt_boundary_indices_init(ss, bdata, init_boundary_distances, boundary_initial_vertex); + + const float boundary_radius = radius * (1.0f + brush->boundary_offset); + sculpt_boundary_edit_data_init(ss, bdata, boundary_initial_vertex, boundary_radius); return bdata; } @@ -455,6 +516,7 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object, void SCULPT_boundary_data_free(SculptBoundary *bdata) { MEM_SAFE_FREE(bdata->vertices); + MEM_SAFE_FREE(bdata->distance); MEM_SAFE_FREE(bdata->edit_info); MEM_SAFE_FREE(bdata->bend.pivot_positions); MEM_SAFE_FREE(bdata->bend.pivot_rotation_axis); @@ -564,6 +626,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *bdata = ss->cache->bdata[symm_area]; + const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; const float strength = ss->cache->bstrength; @@ -584,14 +647,16 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, if (bdata->edit_info[vd.index].num_propagation_steps != -1) { SCULPT_orig_vert_data_update(&orig_data, &vd); - const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - float t_orig_co[3]; - sub_v3_v3v3(t_orig_co, orig_data.co, bdata->bend.pivot_positions[vd.index]); - rotate_v3_v3v3fl(vd.co, - t_orig_co, - bdata->bend.pivot_rotation_axis[vd.index], - angle * bdata->edit_info[vd.index].strength_factor * mask); - add_v3_v3(vd.co, bdata->bend.pivot_positions[vd.index]); + if (SCULPT_check_vertex_pivot_symmetry(orig_data.co, bdata->initial_vertex_position, symm)) { + const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; + float t_orig_co[3]; + sub_v3_v3v3(t_orig_co, orig_data.co, bdata->bend.pivot_positions[vd.index]); + rotate_v3_v3v3fl(vd.co, + t_orig_co, + bdata->bend.pivot_rotation_axis[vd.index], + angle * bdata->edit_info[vd.index].strength_factor * mask); + add_v3_v3(vd.co, bdata->bend.pivot_positions[vd.index]); + } } if (vd.mvert) { @@ -609,6 +674,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *bdata = ss->cache->bdata[symm_area]; + const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; const float strength = ss->cache->bstrength; @@ -623,11 +689,13 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, if (bdata->edit_info[vd.index].num_propagation_steps != -1) { SCULPT_orig_vert_data_update(&orig_data, &vd); - const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - madd_v3_v3v3fl(vd.co, - orig_data.co, - bdata->slide.directions[vd.index], - bdata->edit_info[vd.index].strength_factor * disp * mask * strength); + if (SCULPT_check_vertex_pivot_symmetry(orig_data.co, bdata->initial_vertex_position, symm)) { + const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; + madd_v3_v3v3fl(vd.co, + orig_data.co, + bdata->slide.directions[vd.index], + bdata->edit_info[vd.index].strength_factor * disp * mask * strength); + } } if (vd.mvert) { @@ -645,6 +713,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *bdata = ss->cache->bdata[symm_area]; + const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; const float strength = ss->cache->bstrength; @@ -659,13 +728,15 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, if (bdata->edit_info[vd.index].num_propagation_steps != -1) { SCULPT_orig_vert_data_update(&orig_data, &vd); - const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - float normal[3]; - normal_short_to_float_v3(normal, orig_data.no); - madd_v3_v3v3fl(vd.co, - orig_data.co, - normal, - bdata->edit_info[vd.index].strength_factor * disp * mask * strength); + if (SCULPT_check_vertex_pivot_symmetry(orig_data.co, bdata->initial_vertex_position, symm)) { + const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; + float normal[3]; + normal_short_to_float_v3(normal, orig_data.no); + madd_v3_v3v3fl(vd.co, + orig_data.co, + normal, + bdata->edit_info[vd.index].strength_factor * disp * mask * strength); + } } if (vd.mvert) { @@ -683,6 +754,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *bdata = ss->cache->bdata[symm_area]; + const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; const float strength = ss->cache->bstrength; @@ -695,11 +767,13 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, if (bdata->edit_info[vd.index].num_propagation_steps != -1) { SCULPT_orig_vert_data_update(&orig_data, &vd); - const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - madd_v3_v3v3fl(vd.co, - orig_data.co, - ss->cache->grab_delta_symmetry, - bdata->edit_info[vd.index].strength_factor * mask * strength); + if (SCULPT_check_vertex_pivot_symmetry(orig_data.co, bdata->initial_vertex_position, symm)) { + const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; + madd_v3_v3v3fl(vd.co, + orig_data.co, + ss->cache->grab_delta_symmetry, + bdata->edit_info[vd.index].strength_factor * mask * strength); + } } if (vd.mvert) { @@ -717,6 +791,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; const int symm_area = ss->cache->mirror_symmetry_pass; SculptBoundary *bdata = ss->cache->bdata[symm_area]; + const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; const float strength = ss->cache->bstrength; @@ -736,15 +811,17 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, { if (bdata->edit_info[vd.index].num_propagation_steps != -1) { - const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; SCULPT_orig_vert_data_update(&orig_data, &vd); - float t_orig_co[3]; - sub_v3_v3v3(t_orig_co, orig_data.co, bdata->twist.pivot_position); - rotate_v3_v3v3fl(vd.co, - t_orig_co, - bdata->twist.rotation_axis, - angle * mask * bdata->edit_info[vd.index].strength_factor); - add_v3_v3(vd.co, bdata->twist.pivot_position); + if (SCULPT_check_vertex_pivot_symmetry(orig_data.co, bdata->initial_vertex_position, symm)) { + const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; + float t_orig_co[3]; + sub_v3_v3v3(t_orig_co, orig_data.co, bdata->twist.pivot_position); + rotate_v3_v3v3fl(vd.co, + t_orig_co, + bdata->twist.rotation_axis, + angle * mask * bdata->edit_info[vd.index].strength_factor); + add_v3_v3(vd.co, bdata->twist.pivot_position); + } } if (vd.mvert) { @@ -775,7 +852,7 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn } ss->cache->bdata[symm_area] = SCULPT_boundary_data_init( - ob, initial_vertex, ss->cache->initial_radius); + ob, brush, initial_vertex, ss->cache->initial_radius); if (ss->cache->bdata[symm_area]) { @@ -795,7 +872,8 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn break; } - sculpt_boundary_falloff_factor_init(ss, ss->cache->bdata[symm_area], brush); + sculpt_boundary_falloff_factor_init( + ss, ss->cache->bdata[symm_area], brush, ss->cache->initial_radius); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 7d318760476..2637cb45906 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -1137,7 +1137,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent float len = event->prevclickx - event->mval[0]; filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC; - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); @@ -1185,7 +1185,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent mouse[1] = event->mval[1]; SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); /* Needs mask data to be available as it is used when solving the constraints. */ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); @@ -1232,7 +1232,7 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent void SCULPT_OT_cloth_filter(struct wmOperatorType *ot) { /* Identifiers. */ - ot->name = "Filter cloth"; + ot->name = "Filter Cloth"; ot->idname = "SCULPT_OT_cloth_filter"; ot->description = "Applies a cloth simulation deformation to the entire mesh"; diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index e08f477c981..69c92f2baeb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -176,7 +176,7 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my) SculptSession *ss = ob->sculpt; SculptCursorGeometryInfo sgi; - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); /* Update the active vertex. */ const float mouse[2] = {mx, my}; diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 5cc32be331e..2afa3556dd9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -1005,22 +1005,26 @@ static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { static void sculpt_face_set_grow(Object *ob, SculptSession *ss, - int *prev_face_sets, - const int active_face_set_id) + const int *prev_face_sets, + const int active_face_set_id, + const bool modify_hidden) { Mesh *mesh = BKE_mesh_from_object(ob); for (int p = 0; p < mesh->totpoly; p++) { + if (!modify_hidden && prev_face_sets[p] <= 0) { + continue; + } const MPoly *c_poly = &mesh->mpoly[p]; for (int l = 0; l < c_poly->totloop; l++) { const MLoop *c_loop = &mesh->mloop[c_poly->loopstart + l]; const MeshElemMap *vert_map = &ss->pmap[c_loop->v]; for (int i = 0; i < vert_map->count; i++) { const int neighbor_face_index = vert_map->indices[i]; - if (neighbor_face_index != p) { - - if (abs(prev_face_sets[neighbor_face_index]) == active_face_set_id) { - ss->face_sets[p] = active_face_set_id; - } + if (neighbor_face_index == p) { + continue; + } + if (abs(prev_face_sets[neighbor_face_index]) == active_face_set_id) { + ss->face_sets[p] = active_face_set_id; } } } @@ -1029,11 +1033,15 @@ static void sculpt_face_set_grow(Object *ob, static void sculpt_face_set_shrink(Object *ob, SculptSession *ss, - int *prev_face_sets, - const int active_face_set_id) + const int *prev_face_sets, + const int active_face_set_id, + const bool modify_hidden) { Mesh *mesh = BKE_mesh_from_object(ob); for (int p = 0; p < mesh->totpoly; p++) { + if (!modify_hidden && prev_face_sets[p] <= 0) { + continue; + } if (abs(prev_face_sets[p]) == active_face_set_id) { const MPoly *c_poly = &mesh->mpoly[p]; for (int l = 0; l < c_poly->totloop; l++) { @@ -1041,10 +1049,11 @@ static void sculpt_face_set_shrink(Object *ob, const MeshElemMap *vert_map = &ss->pmap[c_loop->v]; for (int i = 0; i < vert_map->count; i++) { const int neighbor_face_index = vert_map->indices[i]; - if (neighbor_face_index != p) { - if (abs(prev_face_sets[neighbor_face_index]) != active_face_set_id) { - ss->face_sets[p] = prev_face_sets[neighbor_face_index]; - } + if (neighbor_face_index == p) { + continue; + } + if (abs(prev_face_sets[neighbor_face_index]) != active_face_set_id) { + ss->face_sets[p] = prev_face_sets[neighbor_face_index]; } } } @@ -1052,7 +1061,10 @@ static void sculpt_face_set_shrink(Object *ob, } } -static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, const int mode) +static void sculpt_face_set_apply_edit(Object *ob, + const int active_face_set_id, + const int mode, + const bool modify_hidden) { SculptSession *ss = ob->sculpt; @@ -1060,17 +1072,17 @@ static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, switch (mode) { case SCULPT_FACE_SET_EDIT_GROW: - sculpt_face_set_grow(ob, ss, prev_face_sets, active_face_set_id); + sculpt_face_set_grow(ob, ss, prev_face_sets, active_face_set_id, modify_hidden); break; case SCULPT_FACE_SET_EDIT_SHRINK: - sculpt_face_set_shrink(ob, ss, prev_face_sets, active_face_set_id); + sculpt_face_set_shrink(ob, ss, prev_face_sets, active_face_set_id, modify_hidden); break; } MEM_SAFE_FREE(prev_face_sets); } -static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; @@ -1084,8 +1096,21 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven return OPERATOR_CANCELLED; } + /* Ignore other events to avoid repeated operations. */ + if (event->val != KM_PRESS) { + return OPERATOR_CANCELLED; + } + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); + /* Update the current active Face Set and Vertex as the operator can be used directly from the + * tool without brush cursor. */ + SculptCursorGeometryInfo sgi; + float mouse[2]; + mouse[0] = event->mval[0]; + mouse[1] = event->mval[1]; + SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; int totnode; @@ -1099,8 +1124,9 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); const int active_face_set = SCULPT_active_face_set_get(ss); + const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden"); - sculpt_face_set_apply_edit(ob, abs(active_face_set), mode); + sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden); SCULPT_undo_push_end(); @@ -1145,4 +1171,9 @@ void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot) RNA_def_enum( ot->srna, "mode", prop_sculpt_face_sets_edit_types, SCULPT_FACE_SET_EDIT_GROW, "Mode", ""); + ot->prop = RNA_def_boolean(ot->srna, + "modify_hidden", + true, + "Modify Hidden", + "Apply the edit operation to hidden Face Sets"); } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index 912dfd808b0..576536cac03 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -127,7 +127,7 @@ static void color_filter_task_cb(void *__restrict userdata, float fill_color_rgba[4]; copy_v3_v3(fill_color_rgba, data->filter_fill_color); fill_color_rgba[3] = 1.0f; - CLAMP(fade, 0.0f, 1.0f); + fade = clamp_f(fade, 0.0f, 1.0f); mul_v4_fl(fill_color_rgba, fade); blend_color_mix_float(final_color, orig_data.col, fill_color_rgba); break; @@ -140,33 +140,28 @@ static void color_filter_task_cb(void *__restrict userdata, break; case COLOR_FILTER_SATURATION: rgb_to_hsv_v(orig_color, hsv_color); - hsv_color[1] = hsv_color[1] + fade; - CLAMP(hsv_color[1], 0.0f, 1.0f); + hsv_color[1] = clamp_f(hsv_color[1] + fade, 0.0f, 1.0f); hsv_to_rgb_v(hsv_color, final_color); break; case COLOR_FILTER_VALUE: rgb_to_hsv_v(orig_color, hsv_color); - hsv_color[2] = hsv_color[2] + fade; - CLAMP(hsv_color[2], 0.0f, 1.0f); + hsv_color[2] = clamp_f(hsv_color[2] + fade, 0.0f, 1.0f); hsv_to_rgb_v(hsv_color, final_color); break; case COLOR_FILTER_RED: - orig_color[0] = orig_color[0] + fade; - CLAMP(orig_color[0], 0.0f, 1.0f); + orig_color[0] = clamp_f(orig_color[0] + fade, 0.0f, 1.0f); copy_v3_v3(final_color, orig_color); break; case COLOR_FILTER_GREEN: - orig_color[1] = orig_color[1] + fade; - CLAMP(orig_color[1], 0.0f, 1.0f); + orig_color[1] = clamp_f(orig_color[1] + fade, 0.0f, 1.0f); copy_v3_v3(final_color, orig_color); break; case COLOR_FILTER_BLUE: - orig_color[2] = orig_color[2] + fade; - CLAMP(orig_color[2], 0.0f, 1.0f); + orig_color[2] = clamp_f(orig_color[2] + fade, 0.0f, 1.0f); copy_v3_v3(final_color, orig_color); break; case COLOR_FILTER_BRIGHTNESS: - CLAMP(fade, -1.0f, 1.0f); + fade = clamp_f(fade, -1.0f, 1.0f); brightness = fade; contrast = 0; delta = contrast / 2.0f; @@ -174,12 +169,11 @@ static void color_filter_task_cb(void *__restrict userdata, delta *= -1; offset = gain * (brightness + delta); for (int i = 0; i < 3; i++) { - final_color[i] = gain * orig_color[i] + offset; - CLAMP(final_color[i], 0.0f, 1.0f); + final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f); } break; case COLOR_FILTER_CONTRAST: - CLAMP(fade, -1.0f, 1.0f); + fade = clamp_f(fade, -1.0f, 1.0f); brightness = 0; contrast = fade; delta = contrast / 2.0f; @@ -193,12 +187,11 @@ static void color_filter_task_cb(void *__restrict userdata, offset = gain * (brightness + delta); } for (int i = 0; i < 3; i++) { - final_color[i] = gain * orig_color[i] + offset; - CLAMP(final_color[i], 0.0f, 1.0f); + final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f); } break; case COLOR_FILTER_SMOOTH: { - CLAMP(fade, -1.0f, 1.0f); + fade = clamp_f(fade, -1.0f, 1.0f); float smooth_color[4]; SCULPT_neighbor_color_average(ss, smooth_color, vd.index); blend_color_interpolate_float(final_color, vd.col, smooth_color, fade); @@ -305,7 +298,7 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent void SCULPT_OT_color_filter(struct wmOperatorType *ot) { /* identifiers */ - ot->name = "Filter color"; + ot->name = "Filter Color"; ot->idname = "SCULPT_OT_color_filter"; ot->description = "Applies a filter to modify the current sculpt vertex colors"; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 83145f5600f..e764df78c88 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -175,7 +175,7 @@ static void mask_filter_task_cb(void *__restrict userdata, *vd.mask = gain * (*vd.mask) + offset; break; } - CLAMP(*vd.mask, 0.0f, 1.0f); + *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f); if (*vd.mask != prev_val) { update = true; } @@ -204,7 +204,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); if (!ob->sculpt->pmap) { return OPERATOR_CANCELLED; @@ -434,7 +434,7 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); if (!ob->sculpt->pmap) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index ebf511c7fd3..f9ae91fce7f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -261,7 +261,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, switch (filter_type) { case MESH_FILTER_SMOOTH: - CLAMP(fade, -1.0f, 1.0f); + fade = clamp_f(fade, -1.0f, 1.0f); SCULPT_neighbor_coords_average_interior(ss, avg, vd.index); sub_v3_v3v3(val, avg, orig_co); madd_v3_v3v3fl(val, orig_co, val, fade); @@ -306,7 +306,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, const uint *hash_co = (const uint *)orig_co; const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^ BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed); - mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f); + mul_v3_fl(normal, hash * (1.0f / 0xFFFFFFFF) - 0.5f); mul_v3_v3fl(disp, normal, fade); break; } @@ -435,9 +435,8 @@ static void mesh_filter_sharpen_init_factors(SculptSession *ss) SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { - mul_v3_v3fl( - ss->filter_cache->sharpen_detail_directions[i], direction_avg, 1.0f / (float)total); - ss->filter_cache->sharpen_factor[i] = sharpen_avg / (float)total; + mul_v3_v3fl(ss->filter_cache->sharpen_detail_directions[i], direction_avg, 1.0f / total); + ss->filter_cache->sharpen_factor[i] = sharpen_avg / total; } } } @@ -500,7 +499,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * float len = event->prevclickx - event->mval[0]; filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC; - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false, false); @@ -566,7 +565,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets"); - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); const bool needs_topology_info = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_topology_info, false, false); @@ -628,7 +627,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent void SCULPT_OT_mesh_filter(struct wmOperatorType *ot) { /* Identifiers. */ - ot->name = "Filter mesh"; + ot->name = "Filter Mesh"; ot->idname = "SCULPT_OT_mesh_filter"; ot->description = "Applies a filter to modify the current mesh"; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 79b1a5bde7b..22316eb4631 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -89,7 +89,7 @@ float SCULPT_raycast_init(struct ViewContext *vc, bool original); /* Sculpt PBVH abstraction API */ -void SCULPT_vertex_random_access_init(struct SculptSession *ss); +void SCULPT_vertex_random_access_ensure(struct SculptSession *ss); int SCULPT_vertex_count_get(struct SculptSession *ss); const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index); @@ -100,6 +100,10 @@ const float *SCULPT_vertex_color_get(SculptSession *ss, int index); const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index); void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]); +/* Returs the info of the limit surface when Multires is available, otherwise it returns the + * current coordinate of the vertex. */ +void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]); + #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 typedef struct SculptVertexNeighborIter { /* Storage */ @@ -394,6 +398,7 @@ void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain); /* Boundary Brush. */ struct SculptBoundary *SCULPT_boundary_data_init(Object *object, + Brush *brush, const int initial_vertex, const float radius); void SCULPT_boundary_data_free(struct SculptBoundary *bdata); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index aaa61ee9ed3..0ae9baf7e2e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -357,7 +357,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent mouse[0] = event->mval[0]; mouse[1] = event->mval[1]; - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position"); copy_v2_v2(op->customdata, mouse); diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index ed33542967b..000b7afdf55 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -327,7 +327,7 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode if (swptd.tot_samples > 0 && is_finite_v4(swptd.color)) { copy_v4_v4(wet_color, swptd.color); - mul_v4_fl(wet_color, 1.0f / (float)swptd.tot_samples); + mul_v4_fl(wet_color, 1.0f / swptd.tot_samples); CLAMP4(wet_color, 0.0f, 1.0f); if (ss->cache->first_time) { diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index 8a288877d43..4d41d069155 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -549,7 +549,7 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd, float *r_pose_origin, float *r_pose_factor) { - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); /* Calculate the pose rotation point based on the boundaries of the brush factor. */ SculptFloodFill flood; diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index 9a64830cc20..2b93298ac4a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -150,7 +150,7 @@ void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int inde SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { - mul_v3_v3fl(result, avg, 1.0f / (float)total); + mul_v3_v3fl(result, avg, 1.0f / total); } else { copy_v3_v3(result, SCULPT_vertex_co_get(ss, index)); @@ -170,7 +170,7 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, int index) SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { - return avg / (float)total; + return avg / total; } return SCULPT_vertex_mask_get(ss, index); } @@ -188,7 +188,7 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { - mul_v4_v4fl(result, avg, 1.0f / (float)total); + mul_v4_v4fl(result, avg, 1.0f / total); } else { copy_v4_v4(result, SCULPT_vertex_color_get(ss, index)); @@ -276,7 +276,7 @@ void SCULPT_smooth(Sculpt *sd, return; } - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_info_ensure(ob); for (iteration = 0; iteration <= count; iteration++) { @@ -343,7 +343,7 @@ void SCULPT_surface_smooth_displace_step(SculptSession *ss, } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { - mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / (float)total); + mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / total); madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta); mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f)); sub_v3_v3(co, b_current_vertex); diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index f616817c330..4c54a0465b9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -75,7 +75,7 @@ void ED_sculpt_init_transform(struct bContext *C) ss->pivot_rot[3] = 1.0f; - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); SCULPT_filter_cache_init(ob, sd, SCULPT_UNDO_COORDS); } @@ -126,7 +126,7 @@ void ED_sculpt_update_modal_transform(struct bContext *C) Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - SCULPT_vertex_random_access_init(ss); + SCULPT_vertex_random_access_ensure(ss); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); SculptThreadedTaskData data = { diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index c01bc01588e..a64d5505ebe 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -642,7 +642,6 @@ static void image_main_region_draw(const bContext *C, ARegion *region) // View2DScrollers *scrollers; float col[3]; - GPU_batch_presets_reset(); GPUViewport *viewport = WM_draw_region_get_viewport(region); GPUFrameBuffer *framebuffer_default, *framebuffer_overlay; diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index c1dac30bcb6..491c475b596 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -144,17 +144,17 @@ void SEQUENCER_OT_view_frame(wmOperatorType *ot) static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op)) { + SpaceSeq *sseq = CTX_wm_space_seq(C); bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); #if 0 ARegion *region = CTX_wm_region(C); - SpaceSeq *sseq = area->spacedata.first; Scene *scene = CTX_data_scene(C); #endif View2D *v2d = UI_view2d_fromcontext(C); v2d->cur = v2d->tot; - UI_view2d_curRect_validate(v2d); + UI_view2d_curRect_changed(C, v2d); UI_view2d_sync(screen, area, v2d, V2D_LOCK_COPY); #if 0 @@ -186,6 +186,8 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op)) } #endif + sseq->flag |= SEQ_ZOOM_TO_FIT; + ED_area_tag_redraw(CTX_wm_area(C)); return OPERATOR_FINISHED; } @@ -228,6 +230,8 @@ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op) ED_region_tag_redraw(CTX_wm_region(C)); + UI_view2d_curRect_changed(C, v2d); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index b8bb3e4d43b..4a6bd0de60c 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -96,7 +96,8 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce sseq->chanshown = 0; sseq->view = SEQ_VIEW_SEQUENCE; sseq->mainb = SEQ_DRAW_IMG_IMBUF; - sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES; + sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | + SEQ_ZOOM_TO_FIT; /* Tool header. */ region = MEM_callocN(sizeof(ARegion), "tool header for sequencer"); @@ -679,6 +680,22 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region) WM_event_add_keymap_handler_v2d_mask(®ion->handlers, keymap); } +static void sequencer_preview_region_layout(const bContext *C, ARegion *region) +{ + SpaceSeq *sseq = CTX_wm_space_seq(C); + + if (sseq->flag & SEQ_ZOOM_TO_FIT) { + View2D *v2d = ®ion->v2d; + v2d->cur = v2d->tot; + } +} + +static void sequencer_preview_region_view2d_changed(const bContext *C, ARegion *UNUSED(region)) +{ + SpaceSeq *sseq = CTX_wm_space_seq(C); + sseq->flag &= ~SEQ_ZOOM_TO_FIT; +} + static void sequencer_preview_region_draw(const bContext *C, ARegion *region) { ScrArea *area = CTX_wm_area(C); @@ -881,6 +898,8 @@ void ED_spacetype_sequencer(void) art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_PREVIEW; art->init = sequencer_preview_region_init; + art->layout = sequencer_preview_region_layout; + art->on_view2d_changed = sequencer_preview_region_view2d_changed; art->draw = sequencer_preview_region_draw; art->listener = sequencer_preview_region_listener; art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 0442a0f35c9..ac70547c293 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1623,10 +1623,6 @@ void view3d_main_region_draw(const bContext *C, ARegion *region) BKE_image_free_old_gputextures(bmain); GPU_pass_cache_garbage_collect(); - /* XXX This is in order to draw UI batches with the DRW - * old context since we now use it for drawing the entire area. */ - gpu_batch_presets_reset(); - /* No depth test for drawing action zones afterwards. */ GPU_depth_test(false); diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index a828dbc2ee0..a21c1458286 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -262,8 +262,6 @@ static void draw_line_loop(const float coords[][3], int coords_len, const float GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO); GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); - GPU_batch_bind(batch); - GPU_batch_uniform_4fv(batch, "color", color); float viewport[4]; @@ -273,8 +271,6 @@ static void draw_line_loop(const float coords[][3], int coords_len, const float GPU_batch_draw(batch); - GPU_batch_program_use_end(batch); - GPU_batch_discard(batch); GPU_blend(false); } @@ -299,8 +295,6 @@ static void draw_line_pairs(const float coords_a[][3], GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); - GPU_batch_bind(batch); - GPU_batch_uniform_4fv(batch, "color", color); float viewport[4]; @@ -310,8 +304,6 @@ static void draw_line_pairs(const float coords_a[][3], GPU_batch_draw(batch); - GPU_batch_program_use_end(batch); - GPU_batch_discard(batch); GPU_blend(false); } @@ -351,8 +343,6 @@ static void draw_line_bounds(const BoundBox *bounds, const float color[4]) GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); - GPU_batch_bind(batch); - GPU_batch_uniform_4fv(batch, "color", color); float viewport[4]; @@ -362,8 +352,6 @@ static void draw_line_bounds(const BoundBox *bounds, const float color[4]) GPU_batch_draw(batch); - GPU_batch_program_use_end(batch); - GPU_batch_discard(batch); GPU_blend(false); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index df8d3cfb8db..f26e95d8861 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -288,10 +288,6 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra uint idx = 0; bool prev_ma_match = (mpoly->mat_nr == (ob_eval->actcol - 1)); - GPU_matrix_bind(geom->interface); - GPU_shader_set_srgb_uniform(geom->interface); - GPU_batch_bind(geom); - /* TODO(fclem): If drawcall count becomes a problem in the future * we can use multi draw indirect drawcalls for this. * (not implemented in GPU module at the time of writing). */ @@ -299,7 +295,7 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra bool ma_match = (mpoly->mat_nr == (ob_eval->actcol - 1)); if (ma_match != prev_ma_match) { if (ma_match == false) { - GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0); + GPU_batch_draw_range(geom, draw_start, idx - draw_start); } else { draw_start = idx; @@ -309,10 +305,8 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra prev_ma_match = ma_match; } if (prev_ma_match == true) { - GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0); + GPU_batch_draw_range(geom, draw_start, idx - draw_start); } - - GPU_batch_program_use_end(geom); } else { GPU_batch_draw(geom); @@ -455,6 +449,8 @@ static void draw_uvs(SpaceImage *sima, } col1[3] = overlay_alpha; + GPU_batch_program_set_builtin(batch->edges, shader); + /* Inner Line. Use depth test to insure selection is drawn on top. */ GPU_depth_test(true); GPU_line_width(1.0f); diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 7455004ccb8..5a510aaf945 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -33,7 +33,6 @@ struct wmOperatorType; /* geometric utilities */ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len); -void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_offset); /* find nearest */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 956c094c19b..d3d8c58829b 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -227,22 +227,6 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) /** \name Geometric Utilities * \{ */ -void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset) -{ - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - zero_v2(r_cent); - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - add_v2_v2(r_cent, luv->uv); - } - - mul_v2_fl(r_cent, 1.0f / (float)f->len); -} - void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len) { int i; diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index dd422f2443a..f6485fdef5d 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -190,6 +190,9 @@ typedef struct PChart { LinearSolver *context; float *abf_alpha; PVert *pin1, *pin2; + PVert *single_pin; + float single_pin_area; + float single_pin_uv[2]; } lscm; struct PChartPack { float rescale, area; @@ -467,6 +470,17 @@ static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2]) } } +static float p_chart_uv_area(PChart *chart) +{ + float area = 0.0f; + + for (PFace *f = chart->faces; f; f = f->nextlink) { + area += fabsf(p_face_uv_area_signed(f)); + } + + return area; +} + static void p_chart_uv_scale(PChart *chart, float scale) { PVert *v; @@ -3176,7 +3190,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) } } - if ((live && (!select || !deselect)) || (npins == 1)) { + if ((live && (!select || !deselect))) { chart->u.lscm.context = NULL; } else { @@ -3185,6 +3199,16 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) p_chart_topological_sanity_check(chart); #endif + if (npins == 1) { + chart->u.lscm.single_pin_area = p_chart_uv_area(chart); + for (v = chart->verts; v; v = v->nextlink) { + if (v->flag & PVERT_PIN) { + chart->u.lscm.single_pin = v; + break; + } + } + } + if (abf) { if (!p_chart_abf_solve(chart)) { param_warning("ABF solving failed: falling back to LSCM.\n"); @@ -3192,12 +3216,12 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) } if (npins <= 1) { - /* not enough pins, lets find some ourself */ + /* No pins, let's find some ourself. */ PEdge *outer; p_chart_boundaries(chart, NULL, &outer); - /* outer can be NULL with non-finite coords. */ + /* Outer can be NULL with non-finite coords. */ if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) { p_chart_extrema_verts(chart, &pin1, &pin2); } @@ -3235,6 +3259,11 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) } } + if (chart->u.lscm.single_pin) { + /* If only one pin, save area and pin for transform later. */ + copy_v2_v2(chart->u.lscm.single_pin_uv, chart->u.lscm.single_pin->uv); + } + if (chart->u.lscm.pin1) { EIG_linear_solver_variable_lock(context, 2 * pin1->u.id); EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1); @@ -3358,6 +3387,25 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) return P_FALSE; } +static void p_chart_lscm_transform_single_pin(PChart *chart) +{ + PVert *pin = chart->u.lscm.single_pin; + + /* If only one pin, keep UV area the same. */ + const float new_area = p_chart_uv_area(chart); + if (new_area > 0.0f) { + const float scale = chart->u.lscm.single_pin_area / new_area; + if (scale > 0.0f) { + p_chart_uv_scale(chart, sqrtf(scale)); + } + } + + /* Translate to keep the pinned vertex in place. */ + float offset[2]; + sub_v2_v2v2(offset, chart->u.lscm.single_pin_uv, pin->uv); + p_chart_uv_translate(chart, offset); +} + static void p_chart_lscm_end(PChart *chart) { if (chart->u.lscm.context) { @@ -3372,6 +3420,8 @@ static void p_chart_lscm_end(PChart *chart) chart->u.lscm.context = NULL; chart->u.lscm.pin1 = NULL; chart->u.lscm.pin2 = NULL; + chart->u.lscm.single_pin = NULL; + chart->u.lscm.single_pin_area = 0.0f; } /* Stretch */ @@ -3781,6 +3831,23 @@ static void p_chart_rotate_minimum_area(PChart *chart) } } +static void p_chart_rotate_fit_aabb(PChart *chart) +{ + float(*points)[2] = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); + + p_chart_uv_to_array(chart, points); + + float angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts); + + MEM_freeN(points); + + if (angle != 0.0f) { + float mat[2][2]; + angle_to_mat2(mat, angle); + p_chart_uv_transform(chart, mat); + } +} + /* Area Smoothing */ /* 2d bsp tree for inverse mapping - that's a bit silly */ @@ -4576,8 +4643,12 @@ void param_lscm_solve(ParamHandle *handle) if (result && !(chart->flag & PCHART_HAS_PINS)) { p_chart_rotate_minimum_area(chart); } + else if (result && chart->u.lscm.single_pin) { + p_chart_rotate_fit_aabb(chart); + p_chart_lscm_transform_single_pin(chart); + } - if (!result || (chart->u.lscm.pin1)) { + if (!result || !(chart->flag & PCHART_HAS_PINS)) { p_chart_lscm_end(chart); } } @@ -4692,28 +4763,13 @@ static void param_pack_rotate(ParamHandle *handle, bool ignore_pinned) PHandle *phandle = (PHandle *)handle; for (i = 0; i < phandle->ncharts; i++) { - float(*points)[2]; - float angle; - chart = phandle->charts[i]; if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { continue; } - points = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); - - p_chart_uv_to_array(chart, points); - - angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts); - - MEM_freeN(points); - - if (angle != 0.0f) { - float mat[2][2]; - angle_to_mat2(mat, angle); - p_chart_uv_transform(chart, mat); - } + p_chart_rotate_fit_aabb(chart); } } diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 151c881a466..149c5cf1f96 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -724,7 +724,7 @@ bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNea } float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); + BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); const float dist_test_sq = len_squared_v2v2(co, cent); @@ -2841,7 +2841,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) BM_elem_flag_disable(efa, BM_ELEM_TAG); if (uvedit_face_visible_test(scene, efa)) { - uv_poly_center(efa, cent, cd_loop_uv_offset); + BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); if (BLI_rctf_isect_pt_v(&rectf, cent)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); changed = true; @@ -3072,7 +3072,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) /* assume not touched */ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); + BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); if (uv_circle_select_is_point_inside(cent, offset, ellipse)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); changed = true; @@ -3263,7 +3263,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, /* assume not touched */ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); + BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); changed = true; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 80ea28aca3c..906ae31fbc7 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -63,6 +63,7 @@ set(SRC intern/gpu_codegen.c intern/gpu_context.cc intern/gpu_debug.cc + intern/gpu_drawlist.cc intern/gpu_element.cc intern/gpu_extensions.cc intern/gpu_framebuffer.cc @@ -88,7 +89,10 @@ set(SRC intern/gpu_vertex_format.cc intern/gpu_viewport.c + opengl/gl_batch.cc opengl/gl_context.cc + opengl/gl_drawlist.cc + opengl/gl_vertex_array.cc GPU_attr_binding.h GPU_batch.h @@ -98,6 +102,7 @@ set(SRC GPU_common.h GPU_context.h GPU_debug.h + GPU_drawlist.h GPU_element.h GPU_extensions.h GPU_framebuffer.h @@ -122,9 +127,10 @@ set(SRC intern/gpu_attr_binding_private.h intern/gpu_backend.hh - intern/gpu_batch_private.h + intern/gpu_batch_private.hh intern/gpu_codegen.h intern/gpu_context_private.hh + intern/gpu_drawlist_private.hh intern/gpu_material_library.h intern/gpu_matrix_private.h intern/gpu_node_graph.h @@ -135,7 +141,10 @@ set(SRC intern/gpu_vertex_format_private.h opengl/gl_backend.hh + opengl/gl_batch.hh opengl/gl_context.hh + opengl/gl_drawlist.hh + opengl/gl_vertex_array.hh ) set(LIB diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index 855214c279c..d57739156f8 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -26,85 +26,82 @@ #pragma once +#include "BLI_utildefines.h" + #include "GPU_element.h" #include "GPU_shader.h" -#include "GPU_shader_interface.h" #include "GPU_vertex_buffer.h" -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - GPU_BATCH_UNUSED, - GPU_BATCH_READY_TO_FORMAT, - GPU_BATCH_READY_TO_BUILD, - GPU_BATCH_BUILDING, - GPU_BATCH_READY_TO_DRAW, -} GPUBatchPhase; - #define GPU_BATCH_VBO_MAX_LEN 6 #define GPU_BATCH_INST_VBO_MAX_LEN 2 #define GPU_BATCH_VAO_STATIC_LEN 3 #define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16 -typedef struct GPUBatch { - /* geometry */ +typedef enum eGPUBatchFlag { + /** Invalid default state. */ + GPU_BATCH_INVALID = 0, + + /** GPUVertBuf ownership. (One bit per vbo) */ + GPU_BATCH_OWNS_VBO = (1 << 0), + GPU_BATCH_OWNS_VBO_MAX = (GPU_BATCH_OWNS_VBO << (GPU_BATCH_VBO_MAX_LEN - 1)), + GPU_BATCH_OWNS_VBO_ANY = ((GPU_BATCH_OWNS_VBO << GPU_BATCH_VBO_MAX_LEN) - 1), + /** Instance GPUVertBuf ownership. (One bit per vbo) */ + GPU_BATCH_OWNS_INST_VBO = (GPU_BATCH_OWNS_VBO_MAX << 1), + GPU_BATCH_OWNS_INST_VBO_MAX = (GPU_BATCH_OWNS_INST_VBO << (GPU_BATCH_INST_VBO_MAX_LEN - 1)), + GPU_BATCH_OWNS_INST_VBO_ANY = ((GPU_BATCH_OWNS_INST_VBO << GPU_BATCH_INST_VBO_MAX_LEN) - 1) & + ~GPU_BATCH_OWNS_VBO_ANY, + /** GPUIndexBuf ownership. */ + GPU_BATCH_OWNS_INDEX = (GPU_BATCH_OWNS_INST_VBO_MAX << 1), + + /** Has been initialized. At least one VBO is set. */ + GPU_BATCH_INIT = (1 << 16), + /** Batch is initialized but it's VBOs are still being populated. (optional) */ + GPU_BATCH_BUILDING = (1 << 16), + /** Cached data need to be rebuild. (VAO, PSO, ...) */ + GPU_BATCH_DIRTY = (1 << 17), +} eGPUBatchFlag; + +#define GPU_BATCH_OWNS_NONE GPU_BATCH_INVALID + +BLI_STATIC_ASSERT(GPU_BATCH_OWNS_INDEX < GPU_BATCH_INIT, + "eGPUBatchFlag: Error: status flags are shadowed by the ownership bits!") + +ENUM_OPERATORS(eGPUBatchFlag) + +#ifdef __cplusplus +extern "C" { +#endif +/** + * IMPORTANT: Do not allocate manually as the real struct is bigger (i.e: GLBatch). This is only + * the common and "public" part of the struct. Use the provided allocator. + * TODO(fclem) Make the content of this struct hidden and expose getters/setters. + **/ +typedef struct GPUBatch { /** verts[0] is required, others can be NULL */ GPUVertBuf *verts[GPU_BATCH_VBO_MAX_LEN]; /** Instance attributes. */ GPUVertBuf *inst[GPU_BATCH_INST_VBO_MAX_LEN]; /** NULL if element list not needed */ GPUIndexBuf *elem; - uint32_t gl_prim_type; - - /* cached values (avoid dereferencing later) */ - uint32_t vao_id; - uint32_t program; - const struct GPUShaderInterface *interface; - - /* book-keeping */ - uint owns_flag; - /** used to free all vaos. this implies all vaos were created under the same context. */ - struct GPUContext *context; - GPUBatchPhase phase; - bool program_in_use; - - /* Vao management: remembers all geometry state (vertex attribute bindings & element buffer) - * for each shader interface. Start with a static number of vaos and fallback to dynamic count - * if necessary. Once a batch goes dynamic it does not go back. */ - bool is_dynamic_vao_count; - union { - /** Static handle count */ - struct { - const struct GPUShaderInterface *interfaces[GPU_BATCH_VAO_STATIC_LEN]; - uint32_t vao_ids[GPU_BATCH_VAO_STATIC_LEN]; - } static_vaos; - /** Dynamic handle count */ - struct { - uint count; - const struct GPUShaderInterface **interfaces; - uint32_t *vao_ids; - } dynamic_vaos; - }; - - /* XXX This is the only solution if we want to have some data structure using - * batches as key to identify nodes. We must destroy these nodes with this callback. */ - void (*free_callback)(struct GPUBatch *, void *); - void *callback_data; + /** Bookeeping. */ + eGPUBatchFlag flag; + /** Type of geometry to draw. */ + GPUPrimType prim_type; + /** Current assigned shader. DEPRECATED. Here only for uniform binding. */ + struct GPUShader *shader; } GPUBatch; -enum { - GPU_BATCH_OWNS_VBO = (1 << 0), - /* each vbo index gets bit-shifted */ - GPU_BATCH_OWNS_INSTANCES = (1 << 30), - GPU_BATCH_OWNS_INDEX = (1u << 31u), -}; - -GPUBatch *GPU_batch_calloc(uint count); -GPUBatch *GPU_batch_create_ex(GPUPrimType, GPUVertBuf *, GPUIndexBuf *, uint owns_flag); -void GPU_batch_init_ex(GPUBatch *, GPUPrimType, GPUVertBuf *, GPUIndexBuf *, uint owns_flag); +GPUBatch *GPU_batch_calloc(void); +GPUBatch *GPU_batch_create_ex(GPUPrimType prim, + GPUVertBuf *vert, + GPUIndexBuf *elem, + eGPUBatchFlag own_flag); +void GPU_batch_init_ex(GPUBatch *batch, + GPUPrimType prim, + GPUVertBuf *vert, + GPUIndexBuf *elem, + eGPUBatchFlag own_flag); void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src); #define GPU_batch_create(prim, verts, elem) GPU_batch_create_ex(prim, verts, elem, 0) @@ -115,10 +112,6 @@ void GPU_batch_clear(GPUBatch *); void GPU_batch_discard(GPUBatch *); /* verts & elem are not discarded */ -void GPU_batch_vao_cache_clear(GPUBatch *); - -void GPU_batch_callback_free_set(GPUBatch *, void (*callback)(GPUBatch *, void *), void *); - void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */ void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo); @@ -128,19 +121,13 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo); #define GPU_batch_vertbuf_add(batch, verts) GPU_batch_vertbuf_add_ex(batch, verts, false) void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader); -void GPU_batch_set_shader_no_bind(GPUBatch *batch, GPUShader *shader); void GPU_batch_program_set_imm_shader(GPUBatch *batch); void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id); void GPU_batch_program_set_builtin_with_config(GPUBatch *batch, eGPUBuiltinShader shader_id, eGPUShaderConfig sh_cfg); -/* Entire batch draws with one shader program, but can be redrawn later with another program. */ -/* Vertex shader's inputs must be compatible with the batch's vertex format. */ - -void GPU_batch_program_use_begin(GPUBatch *); /* call before Batch_Uniform (temp hack?) */ -void GPU_batch_program_use_end(GPUBatch *); -void GPU_batch_uniform_1ui(GPUBatch *, const char *name, uint value); +/* Will only work after setting the batch program. */ void GPU_batch_uniform_1i(GPUBatch *, const char *name, int value); void GPU_batch_uniform_1b(GPUBatch *, const char *name, bool value); void GPU_batch_uniform_1f(GPUBatch *, const char *name, float value); @@ -154,10 +141,10 @@ void GPU_batch_uniform_2fv_array(GPUBatch *, const char *name, const int len, co void GPU_batch_uniform_4fv_array(GPUBatch *, const char *name, const int len, const float *data); void GPU_batch_uniform_mat4(GPUBatch *, const char *name, const float data[4][4]); -void GPU_batch_draw(GPUBatch *); +void GPU_batch_draw(GPUBatch *batch); +void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count); +void GPU_batch_draw_instanced(GPUBatch *batch, int i_count); -/* Needs to be called before GPU_batch_draw_advanced. */ -void GPU_batch_bind(GPUBatch *); /* This does not bind/unbind shader and does not call GPU_matrix_bind() */ void GPU_batch_draw_advanced(GPUBatch *, int v_first, int v_count, int i_first, int i_count); @@ -199,19 +186,6 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff #endif /* future plans */ -/** - * #GPUDrawList is an API to do lots of similar draw-calls very fast using multi-draw-indirect. - * There is a fallback if the feature is not supported. - */ -typedef struct GPUDrawList GPUDrawList; - -GPUDrawList *GPU_draw_list_create(int length); -void GPU_draw_list_discard(GPUDrawList *list); -void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch); -void GPU_draw_list_command_add( - GPUDrawList *list, int v_first, int v_count, int i_first, int i_count); -void GPU_draw_list_submit(GPUDrawList *list); - void gpu_batch_init(void); void gpu_batch_exit(void); diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h index 1674cf776db..7a235dd0e12 100644 --- a/source/blender/gpu/GPU_batch_presets.h +++ b/source/blender/gpu/GPU_batch_presets.h @@ -46,11 +46,8 @@ struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, void gpu_batch_presets_init(void); void gpu_batch_presets_register(struct GPUBatch *preset_batch); bool gpu_batch_presets_unregister(struct GPUBatch *preset_batch); -void gpu_batch_presets_reset(void); void gpu_batch_presets_exit(void); -void GPU_batch_presets_reset(void); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_drawlist.h b/source/blender/gpu/GPU_drawlist.h new file mode 100644 index 00000000000..27f70da8cf8 --- /dev/null +++ b/source/blender/gpu/GPU_drawlist.h @@ -0,0 +1,46 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPUDrawList is an API to do lots of similar draw-calls very fast using + * multi-draw-indirect. There is a fallback if the feature is not supported. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct GPUBatch; + +typedef void *GPUDrawList; /* Opaque pointer. */ + +/* Create a list with at least length drawcalls. Length can affect performance. */ +GPUDrawList GPU_draw_list_create(int length); +void GPU_draw_list_discard(GPUDrawList list); + +void GPU_draw_list_append(GPUDrawList list, GPUBatch *batch, int i_first, int i_count); +void GPU_draw_list_submit(GPUDrawList list); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/gpu/GPU_element.h b/source/blender/gpu/GPU_element.h index 3d5195b12fc..5cf85b4ea0e 100644 --- a/source/blender/gpu/GPU_element.h +++ b/source/blender/gpu/GPU_element.h @@ -54,6 +54,8 @@ typedef struct GPUIndexBuf { }; } GPUIndexBuf; +GPUIndexBuf *GPU_indexbuf_calloc(void); + void GPU_indexbuf_use(GPUIndexBuf *); uint GPU_indexbuf_size_get(const GPUIndexBuf *); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index f782742ae53..0b9109fbd4b 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -104,6 +104,19 @@ void GPU_shader_uniform_vector_int( void GPU_shader_uniform_float(GPUShader *shader, int location, float value); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); +void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value); +void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value); +void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value); +void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y); +void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z); +void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w); +void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]); +void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]); +void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]); +void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]); +void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]); +void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]); + int GPU_shader_get_attribute(GPUShader *shader, const char *name); char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len); diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h index 8aba1236b65..47e4e432d66 100644 --- a/source/blender/gpu/GPU_shader_interface.h +++ b/source/blender/gpu/GPU_shader_interface.h @@ -80,7 +80,7 @@ typedef struct GPUShaderInterface { /** Buffer containing all inputs names separated by '\0'. */ char *name_buffer; /** Reference to GPUBatches using this interface */ - struct GPUBatch **batches; + void **batches; uint batches_len; /** Input counts. */ uint attribute_len; @@ -109,8 +109,8 @@ const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *, const const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *, const char *name); /* keep track of batches using this interface */ -void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *, struct GPUBatch *); -void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *, struct GPUBatch *); +void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *interface, void *cache); +void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *interface, void *cache); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h index 757255496e0..bd1019bb1f5 100644 --- a/source/blender/gpu/GPU_vertex_buffer.h +++ b/source/blender/gpu/GPU_vertex_buffer.h @@ -59,6 +59,8 @@ typedef struct GPUVertBuf { uint32_t vbo_id; /** Usage hint for GL optimisation. */ GPUUsageType usage; + /** This counter will only avoid freeing the GPUVertBuf, not the data. */ + char handle_refcount; /** Data has been touched and need to be reuploaded to GPU. */ bool dirty; uchar *data; /* NULL indicates data in VRAM (unmapped) */ @@ -73,6 +75,10 @@ GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *, GPUUsageTyp void GPU_vertbuf_clear(GPUVertBuf *verts); void GPU_vertbuf_discard(GPUVertBuf *); +/* Avoid GPUVertBuf datablock being free but not its data. */ +void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts); +void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts); + void GPU_vertbuf_init(GPUVertBuf *, GPUUsageType); void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsageType); diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index 24f592f214f..ba382e3c3fc 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -25,13 +25,27 @@ #pragma once -struct GPUContext; +#include "gpu_context_private.hh" +#include "gpu_drawlist_private.hh" +#include "gpu_batch_private.hh" + +namespace blender { +namespace gpu { class GPUBackend { public: virtual ~GPUBackend(){}; + static GPUBackend *get(void); + virtual GPUContext *context_alloc(void *ghost_window) = 0; + + virtual Batch *batch_alloc(void) = 0; + virtual DrawList *drawlist_alloc(int list_length) = 0; + // virtual FrameBuffer *framebuffer_alloc(void) = 0; + // virtual Shader *shader_alloc(void) = 0; + // virtual Texture *texture_alloc(void) = 0; }; -GPUBackend *gpu_backend_get(void); +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index a6ba4d3d89a..7b006bdc6c2 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -26,6 +26,8 @@ #include "MEM_guardedalloc.h" +#include "BLI_math_base.h" + #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_extensions.h" @@ -33,7 +35,8 @@ #include "GPU_platform.h" #include "GPU_shader.h" -#include "gpu_batch_private.h" +#include "gpu_backend.hh" +#include "gpu_batch_private.hh" #include "gpu_context_private.hh" #include "gpu_primitive_private.h" #include "gpu_shader_private.h" @@ -43,69 +46,38 @@ #include <stdlib.h> #include <string.h> -static GLuint g_default_attr_vbo = 0; - -static void batch_update_program_bindings(GPUBatch *batch, uint i_first); +using namespace blender::gpu; -void GPU_batch_vao_cache_clear(GPUBatch *batch) -{ - if (batch->context == NULL) { - return; - } - if (batch->is_dynamic_vao_count) { - for (int i = 0; i < batch->dynamic_vaos.count; i++) { - if (batch->dynamic_vaos.vao_ids[i]) { - GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context); - } - if (batch->dynamic_vaos.interfaces[i]) { - GPU_shaderinterface_remove_batch_ref( - (GPUShaderInterface *)batch->dynamic_vaos.interfaces[i], batch); - } - } - MEM_freeN((void *)batch->dynamic_vaos.interfaces); - MEM_freeN(batch->dynamic_vaos.vao_ids); - } - else { - for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) { - if (batch->static_vaos.vao_ids[i]) { - GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context); - } - if (batch->static_vaos.interfaces[i]) { - GPU_shaderinterface_remove_batch_ref( - (GPUShaderInterface *)batch->static_vaos.interfaces[i], batch); - } - } - } - batch->is_dynamic_vao_count = false; - for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) { - batch->static_vaos.vao_ids[i] = 0; - batch->static_vaos.interfaces[i] = NULL; - } - gpu_context_remove_batch(batch->context, batch); - batch->context = NULL; -} +/* -------------------------------------------------------------------- */ +/** \name Creation & Deletion + * \{ */ -GPUBatch *GPU_batch_calloc(uint count) +GPUBatch *GPU_batch_calloc(void) { - return (GPUBatch *)MEM_callocN(sizeof(GPUBatch) * count, "GPUBatch"); + GPUBatch *batch = GPUBackend::get()->batch_alloc(); + memset(batch, 0, sizeof(*batch)); + return batch; } GPUBatch *GPU_batch_create_ex(GPUPrimType prim_type, GPUVertBuf *verts, GPUIndexBuf *elem, - uint owns_flag) + eGPUBatchFlag owns_flag) { - GPUBatch *batch = GPU_batch_calloc(1); + GPUBatch *batch = GPU_batch_calloc(); GPU_batch_init_ex(batch, prim_type, verts, elem, owns_flag); return batch; } -void GPU_batch_init_ex( - GPUBatch *batch, GPUPrimType prim_type, GPUVertBuf *verts, GPUIndexBuf *elem, uint owns_flag) +void GPU_batch_init_ex(GPUBatch *batch, + GPUPrimType prim_type, + GPUVertBuf *verts, + GPUIndexBuf *elem, + eGPUBatchFlag owns_flag) { -#if TRUST_NO_ONE - assert(verts != NULL); -#endif + BLI_assert(verts != NULL); + /* Do not pass any other flag */ + BLI_assert((owns_flag & ~(GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX)) == 0); batch->verts[0] = verts; for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) { @@ -115,19 +87,18 @@ void GPU_batch_init_ex( batch->inst[v] = NULL; } batch->elem = elem; - batch->gl_prim_type = convert_prim_type_to_gl(prim_type); - batch->phase = GPU_BATCH_READY_TO_DRAW; - batch->is_dynamic_vao_count = false; - batch->owns_flag = owns_flag; - batch->free_callback = NULL; + batch->prim_type = prim_type; + batch->flag = owns_flag | GPU_BATCH_INIT | GPU_BATCH_DIRTY; + batch->shader = NULL; } /* This will share the VBOs with the new batch. */ void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src) { - GPU_batch_init_ex(batch_dst, GPU_PRIM_POINTS, batch_src->verts[0], batch_src->elem, 0); + GPU_batch_init_ex( + batch_dst, GPU_PRIM_POINTS, batch_src->verts[0], batch_src->elem, GPU_BATCH_INVALID); - batch_dst->gl_prim_type = batch_src->gl_prim_type; + batch_dst->prim_type = batch_src->prim_type; for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) { batch_dst->verts[v] = batch_src->verts[v]; } @@ -135,484 +106,182 @@ void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src) void GPU_batch_clear(GPUBatch *batch) { - if (batch->owns_flag & GPU_BATCH_OWNS_INDEX) { + if (batch->flag & GPU_BATCH_OWNS_INDEX) { GPU_indexbuf_discard(batch->elem); } - if (batch->owns_flag & GPU_BATCH_OWNS_INSTANCES) { - GPU_vertbuf_discard(batch->inst[0]); - GPU_VERTBUF_DISCARD_SAFE(batch->inst[1]); - } - if ((batch->owns_flag & ~GPU_BATCH_OWNS_INDEX) != 0) { - for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) { - if (batch->verts[v] == NULL) { - break; + if (batch->flag & GPU_BATCH_OWNS_VBO_ANY) { + for (int v = 0; (v < GPU_BATCH_VBO_MAX_LEN) && batch->verts[v]; v++) { + if (batch->flag & (GPU_BATCH_OWNS_VBO << v)) { + GPU_VERTBUF_DISCARD_SAFE(batch->verts[v]); } - if (batch->owns_flag & (1 << v)) { - GPU_vertbuf_discard(batch->verts[v]); + } + } + if (batch->flag & GPU_BATCH_OWNS_INST_VBO_ANY) { + for (int v = 0; (v < GPU_BATCH_INST_VBO_MAX_LEN) && batch->inst[v]; v++) { + if (batch->flag & (GPU_BATCH_OWNS_INST_VBO << v)) { + GPU_VERTBUF_DISCARD_SAFE(batch->inst[v]); } } } - GPU_batch_vao_cache_clear(batch); - batch->phase = GPU_BATCH_UNUSED; + batch->flag = GPU_BATCH_INVALID; } void GPU_batch_discard(GPUBatch *batch) { - if (batch->free_callback) { - batch->free_callback(batch, batch->callback_data); - } - GPU_batch_clear(batch); - MEM_freeN(batch); -} -void GPU_batch_callback_free_set(GPUBatch *batch, - void (*callback)(GPUBatch *, void *), - void *user_data) -{ - batch->free_callback = callback; - batch->callback_data = user_data; + delete static_cast<Batch *>(batch); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Buffers Management + * \{ */ + +/* NOTE: Override ONLY the first instance vbo (and free them if owned). */ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo) { -#if TRUST_NO_ONE - assert(inst != NULL); -#endif - /* redo the bindings */ - GPU_batch_vao_cache_clear(batch); + BLI_assert(inst); + batch->flag |= GPU_BATCH_DIRTY; - if (batch->inst[0] != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INSTANCES)) { + if (batch->inst[0] && (batch->flag & GPU_BATCH_OWNS_INST_VBO)) { GPU_vertbuf_discard(batch->inst[0]); - GPU_VERTBUF_DISCARD_SAFE(batch->inst[1]); } batch->inst[0] = inst; - if (own_vbo) { - batch->owns_flag |= GPU_BATCH_OWNS_INSTANCES; - } - else { - batch->owns_flag &= ~GPU_BATCH_OWNS_INSTANCES; - } + SET_FLAG_FROM_TEST(batch->flag, own_vbo, GPU_BATCH_OWNS_INST_VBO); } +/* NOTE: Override any previously assigned elem (and free it if owned). */ void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo) { - BLI_assert(elem != NULL); - /* redo the bindings */ - GPU_batch_vao_cache_clear(batch); + BLI_assert(elem); + batch->flag |= GPU_BATCH_DIRTY; - if (batch->elem != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INDEX)) { + if (batch->elem && (batch->flag & GPU_BATCH_OWNS_INDEX)) { GPU_indexbuf_discard(batch->elem); } batch->elem = elem; - if (own_ibo) { - batch->owns_flag |= GPU_BATCH_OWNS_INDEX; - } - else { - batch->owns_flag &= ~GPU_BATCH_OWNS_INDEX; - } + SET_FLAG_FROM_TEST(batch->flag, own_ibo, GPU_BATCH_OWNS_INDEX); } -/* A bit of a quick hack. Should be streamlined as the vbos handling */ int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo) { - /* redo the bindings */ - GPU_batch_vao_cache_clear(batch); + BLI_assert(insts); + batch->flag |= GPU_BATCH_DIRTY; for (uint v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) { if (batch->inst[v] == NULL) { -#if TRUST_NO_ONE /* for now all VertexBuffers must have same vertex_len */ - if (batch->inst[0] != NULL) { - /* Allow for different size of vertex buf (will choose the smallest number of verts). */ - // assert(insts->vertex_len == batch->inst[0]->vertex_len); - assert(own_vbo == ((batch->owns_flag & GPU_BATCH_OWNS_INSTANCES) != 0)); + if (batch->inst[0]) { + /* Allow for different size of vertex buf (will choose the smallest + * number of verts). */ + // BLI_assert(insts->vertex_len == batch->inst[0]->vertex_len); } -#endif + batch->inst[v] = insts; - if (own_vbo) { - batch->owns_flag |= GPU_BATCH_OWNS_INSTANCES; - } + SET_FLAG_FROM_TEST(batch->flag, own_vbo, (eGPUBatchFlag)(GPU_BATCH_OWNS_INST_VBO << v)); return v; } } - /* we only make it this far if there is no room for another GPUVertBuf */ -#if TRUST_NO_ONE - assert(false); -#endif + BLI_assert(0 && "Not enough Instance VBO slot in batch"); return -1; } /* Returns the index of verts in the batch. */ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo) { - /* redo the bindings */ - GPU_batch_vao_cache_clear(batch); + BLI_assert(verts); + batch->flag |= GPU_BATCH_DIRTY; for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) { if (batch->verts[v] == NULL) { -#if TRUST_NO_ONE /* for now all VertexBuffers must have same vertex_len */ if (batch->verts[0] != NULL) { - assert(verts->vertex_len == batch->verts[0]->vertex_len); + BLI_assert(verts->vertex_len == batch->verts[0]->vertex_len); } -#endif batch->verts[v] = verts; - /* TODO: mark dirty so we can keep attribute bindings up-to-date */ - if (own_vbo) { - batch->owns_flag |= (1 << v); - } + SET_FLAG_FROM_TEST(batch->flag, own_vbo, (eGPUBatchFlag)(GPU_BATCH_OWNS_VBO << v)); return v; } } - /* we only make it this far if there is no room for another GPUVertBuf */ -#if TRUST_NO_ONE - assert(false); -#endif + BLI_assert(0 && "Not enough VBO slot in batch"); return -1; } -static GLuint batch_vao_get(GPUBatch *batch) -{ - /* Search through cache */ - if (batch->is_dynamic_vao_count) { - for (int i = 0; i < batch->dynamic_vaos.count; i++) { - if (batch->dynamic_vaos.interfaces[i] == batch->interface) { - return batch->dynamic_vaos.vao_ids[i]; - } - } - } - else { - for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) { - if (batch->static_vaos.interfaces[i] == batch->interface) { - return batch->static_vaos.vao_ids[i]; - } - } - } - - /* Set context of this batch. - * It will be bound to it until GPU_batch_vao_cache_clear is called. - * Until then it can only be drawn with this context. */ - if (batch->context == NULL) { - batch->context = GPU_context_active_get(); - gpu_context_add_batch(batch->context, batch); - } -#if TRUST_NO_ONE - else { - /* Make sure you are not trying to draw this batch in another context. */ - assert(batch->context == GPU_context_active_get()); - } -#endif - - /* Cache miss, time to add a new entry! */ - GLuint new_vao = 0; - if (!batch->is_dynamic_vao_count) { - int i; /* find first unused slot */ - for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) { - if (batch->static_vaos.vao_ids[i] == 0) { - break; - } - } - - if (i < GPU_BATCH_VAO_STATIC_LEN) { - batch->static_vaos.interfaces[i] = batch->interface; - batch->static_vaos.vao_ids[i] = new_vao = GPU_vao_alloc(); - } - else { - /* Not enough place switch to dynamic. */ - batch->is_dynamic_vao_count = true; - /* Erase previous entries, they will be added back if drawn again. */ - for (int j = 0; j < GPU_BATCH_VAO_STATIC_LEN; j++) { - GPU_shaderinterface_remove_batch_ref( - (GPUShaderInterface *)batch->static_vaos.interfaces[j], batch); - GPU_vao_free(batch->static_vaos.vao_ids[j], batch->context); - } - /* Init dynamic arrays and let the branch below set the values. */ - batch->dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT; - batch->dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_callocN( - batch->dynamic_vaos.count * sizeof(GPUShaderInterface *), "dyn vaos interfaces"); - batch->dynamic_vaos.vao_ids = (GLuint *)MEM_callocN( - batch->dynamic_vaos.count * sizeof(GLuint), "dyn vaos ids"); - } - } - - if (batch->is_dynamic_vao_count) { - int i; /* find first unused slot */ - for (i = 0; i < batch->dynamic_vaos.count; i++) { - if (batch->dynamic_vaos.vao_ids[i] == 0) { - break; - } - } - - if (i == batch->dynamic_vaos.count) { - /* Not enough place, realloc the array. */ - i = batch->dynamic_vaos.count; - batch->dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT; - batch->dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_recallocN( - (void *)batch->dynamic_vaos.interfaces, - sizeof(GPUShaderInterface *) * batch->dynamic_vaos.count); - batch->dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN( - batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count); - } - batch->dynamic_vaos.interfaces[i] = batch->interface; - batch->dynamic_vaos.vao_ids[i] = new_vao = GPU_vao_alloc(); - } - - GPU_shaderinterface_add_batch_ref((GPUShaderInterface *)batch->interface, batch); - -#if TRUST_NO_ONE - assert(new_vao != 0); -#endif - - /* We just got a fresh VAO we need to initialize it. */ - glBindVertexArray(new_vao); - batch_update_program_bindings(batch, 0); - glBindVertexArray(0); - - return new_vao; -} +/** \} */ -void GPU_batch_set_shader_no_bind(GPUBatch *batch, GPUShader *shader) -{ -#if TRUST_NO_ONE - assert(glIsProgram(shader->program)); - assert(batch->program_in_use == 0); -#endif - batch->interface = shader->interface; - batch->program = shader->program; - batch->vao_id = batch_vao_get(batch); -} +/* -------------------------------------------------------------------- */ +/** \name Uniform setters + * + * TODO(fclem) port this to GPUShader. + * \{ */ void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader) { - GPU_batch_set_shader_no_bind(batch, shader); - GPU_batch_program_use_begin(batch); /* hack! to make Batch_Uniform* simpler */ -} - -void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface) -{ - if (batch->is_dynamic_vao_count) { - for (int i = 0; i < batch->dynamic_vaos.count; i++) { - if (batch->dynamic_vaos.interfaces[i] == interface) { - GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context); - batch->dynamic_vaos.vao_ids[i] = 0; - batch->dynamic_vaos.interfaces[i] = NULL; - break; /* cannot have duplicates */ - } - } - } - else { - int i; - for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; i++) { - if (batch->static_vaos.interfaces[i] == interface) { - GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context); - batch->static_vaos.vao_ids[i] = 0; - batch->static_vaos.interfaces[i] = NULL; - break; /* cannot have duplicates */ - } - } - } -} - -static void create_bindings(GPUVertBuf *verts, - const GPUShaderInterface *interface, - uint16_t *attr_mask, - uint v_first, - const bool use_instancing) -{ - const GPUVertFormat *format = &verts->format; - - const uint attr_len = format->attr_len; - uint stride = format->stride; - uint offset = 0; - - GPU_vertbuf_use(verts); - - for (uint a_idx = 0; a_idx < attr_len; a_idx++) { - const GPUVertAttr *a = &format->attrs[a_idx]; - - if (format->deinterleaved) { - offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * verts->vertex_len; - stride = a->sz; - } - else { - offset = a->offset; - } - - const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride; - const GLenum type = convert_comp_type_to_gl(static_cast<GPUVertCompType>(a->comp_type)); - - for (uint n_idx = 0; n_idx < a->name_len; n_idx++) { - const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); - const GPUShaderInput *input = GPU_shaderinterface_attr(interface, name); - - if (input == NULL) { - continue; - } - - *attr_mask &= ~(1 << input->location); - - if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) { - BLI_assert(a->fetch_mode == GPU_FETCH_FLOAT); - BLI_assert(a->comp_type == GPU_COMP_F32); - for (int i = 0; i < a->comp_len / 4; i++) { - glEnableVertexAttribArray(input->location + i); - glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0); - glVertexAttribPointer( - input->location + i, 4, type, GL_FALSE, stride, (const GLubyte *)pointer + i * 16); - } - } - else { - glEnableVertexAttribArray(input->location); - glVertexAttribDivisor(input->location, (use_instancing) ? 1 : 0); - - switch (a->fetch_mode) { - case GPU_FETCH_FLOAT: - case GPU_FETCH_INT_TO_FLOAT: - glVertexAttribPointer(input->location, a->comp_len, type, GL_FALSE, stride, pointer); - break; - case GPU_FETCH_INT_TO_FLOAT_UNIT: - glVertexAttribPointer(input->location, a->comp_len, type, GL_TRUE, stride, pointer); - break; - case GPU_FETCH_INT: - glVertexAttribIPointer(input->location, a->comp_len, type, stride, pointer); - break; - } - } - } - } -} - -static void batch_update_program_bindings(GPUBatch *batch, uint i_first) -{ - uint16_t attr_mask = batch->interface->enabled_attr_mask; - - /* Reverse order so first VBO'S have more prevalence (in term of attribute override). */ - for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) { - if (batch->verts[v] != NULL) { - create_bindings(batch->verts[v], batch->interface, &attr_mask, 0, false); - } - } - - for (int v = GPU_BATCH_INST_VBO_MAX_LEN - 1; v > -1; v--) { - if (batch->inst[v]) { - create_bindings(batch->inst[v], batch->interface, &attr_mask, i_first, true); - } - } - - if (attr_mask != 0 && GLEW_ARB_vertex_attrib_binding) { - for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) { - if (attr_mask & mask) { - /* This replaces glVertexAttrib4f(a, 0.0f, 0.0f, 0.0f, 1.0f); with a more modern style. - * Fix issues for some drivers (see T75069). */ - glBindVertexBuffer(a, g_default_attr_vbo, (intptr_t)0, (intptr_t)0); - - glEnableVertexAttribArray(a); - glVertexAttribFormat(a, 4, GL_FLOAT, GL_FALSE, 0); - glVertexAttribBinding(a, a); - } - } - } - - if (batch->elem) { - GPU_indexbuf_use(batch->elem); - } -} - -void GPU_batch_program_use_begin(GPUBatch *batch) -{ - /* NOTE: use_program & done_using_program are fragile, depend on staying in sync with - * the GL context's active program. - * use_program doesn't mark other programs as "not used". */ - /* TODO: make not fragile (somehow) */ - - if (!batch->program_in_use) { - glUseProgram(batch->program); - batch->program_in_use = true; - } + batch->shader = shader; + GPU_shader_bind(batch->shader); } -void GPU_batch_program_use_end(GPUBatch *batch) -{ - if (batch->program_in_use) { -#if PROGRAM_NO_OPTI - glUseProgram(0); -#endif - batch->program_in_use = false; - } -} - -#if TRUST_NO_ONE -# define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); \ - assert(uniform); -#else -# define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); -#endif - -void GPU_batch_uniform_1ui(GPUBatch *batch, const char *name, uint value) -{ - GET_UNIFORM - glUniform1ui(uniform->location, value); -} +#define GET_UNIFORM \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->shader->interface, name); \ + BLI_assert(uniform); void GPU_batch_uniform_1i(GPUBatch *batch, const char *name, int value) { GET_UNIFORM - glUniform1i(uniform->location, value); + GPU_shader_uniform_int(batch->shader, uniform->location, value); } void GPU_batch_uniform_1b(GPUBatch *batch, const char *name, bool value) { - GET_UNIFORM - glUniform1i(uniform->location, value ? GL_TRUE : GL_FALSE); + GPU_batch_uniform_1i(batch, name, value ? GL_TRUE : GL_FALSE); } void GPU_batch_uniform_2f(GPUBatch *batch, const char *name, float x, float y) { - GET_UNIFORM - glUniform2f(uniform->location, x, y); + const float data[2] = {x, y}; + GPU_batch_uniform_2fv(batch, name, data); } void GPU_batch_uniform_3f(GPUBatch *batch, const char *name, float x, float y, float z) { - GET_UNIFORM - glUniform3f(uniform->location, x, y, z); + const float data[3] = {x, y, z}; + GPU_batch_uniform_3fv(batch, name, data); } void GPU_batch_uniform_4f(GPUBatch *batch, const char *name, float x, float y, float z, float w) { - GET_UNIFORM - glUniform4f(uniform->location, x, y, z, w); + const float data[4] = {x, y, z, w}; + GPU_batch_uniform_4fv(batch, name, data); } void GPU_batch_uniform_1f(GPUBatch *batch, const char *name, float x) { GET_UNIFORM - glUniform1f(uniform->location, x); + GPU_shader_uniform_float(batch->shader, uniform->location, x); } void GPU_batch_uniform_2fv(GPUBatch *batch, const char *name, const float data[2]) { GET_UNIFORM - glUniform2fv(uniform->location, 1, data); + GPU_shader_uniform_vector(batch->shader, uniform->location, 2, 1, data); } void GPU_batch_uniform_3fv(GPUBatch *batch, const char *name, const float data[3]) { GET_UNIFORM - glUniform3fv(uniform->location, 1, data); + GPU_shader_uniform_vector(batch->shader, uniform->location, 3, 1, data); } void GPU_batch_uniform_4fv(GPUBatch *batch, const char *name, const float data[4]) { GET_UNIFORM - glUniform4fv(uniform->location, 1, data); + GPU_shader_uniform_vector(batch->shader, uniform->location, 4, 1, data); } void GPU_batch_uniform_2fv_array(GPUBatch *batch, @@ -621,7 +290,7 @@ void GPU_batch_uniform_2fv_array(GPUBatch *batch, const float *data) { GET_UNIFORM - glUniform2fv(uniform->location, len, data); + GPU_shader_uniform_vector(batch->shader, uniform->location, 2, len, data); } void GPU_batch_uniform_4fv_array(GPUBatch *batch, @@ -630,68 +299,48 @@ void GPU_batch_uniform_4fv_array(GPUBatch *batch, const float *data) { GET_UNIFORM - glUniform4fv(uniform->location, len, data); + GPU_shader_uniform_vector(batch->shader, uniform->location, 4, len, data); } void GPU_batch_uniform_mat4(GPUBatch *batch, const char *name, const float data[4][4]) { GET_UNIFORM - glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (const float *)data); + GPU_shader_uniform_vector(batch->shader, uniform->location, 16, 1, (const float *)data); } -static void *elem_offset(const GPUIndexBuf *el, int v_first) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Drawing / Drawcall functions + * \{ */ + +void GPU_batch_draw(GPUBatch *batch) { -#if GPU_TRACK_INDEX_RANGE - if (el->index_type == GPU_INDEX_U16) { - return (GLushort *)0 + v_first + el->index_start; - } -#endif - return (GLuint *)0 + v_first + el->index_start; + GPU_shader_bind(batch->shader); + GPU_batch_draw_advanced(batch, 0, 0, 0, 0); + GPU_shader_unbind(); } -/* Use when drawing with GPU_batch_draw_advanced */ -void GPU_batch_bind(GPUBatch *batch) +void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count) { - glBindVertexArray(batch->vao_id); - -#if GPU_TRACK_INDEX_RANGE - /* Can be removed if GL 4.3 is required. */ - if (!GLEW_ARB_ES3_compatibility && batch->elem != NULL) { - GLuint restart_index = (batch->elem->index_type == GPU_INDEX_U16) ? (GLuint)0xFFFF : - (GLuint)0xFFFFFFFF; - glPrimitiveRestartIndex(restart_index); - } -#endif + GPU_shader_bind(batch->shader); + GPU_batch_draw_advanced(batch, v_first, v_count, 0, 0); + GPU_shader_unbind(); } -void GPU_batch_draw(GPUBatch *batch) +/* Draw multiple instance of a batch without having any instance attributes. */ +void GPU_batch_draw_instanced(GPUBatch *batch, int i_count) { -#if TRUST_NO_ONE - assert(batch->phase == GPU_BATCH_READY_TO_DRAW); - assert(batch->verts[0]->vbo_id != 0); -#endif - GPU_batch_program_use_begin(batch); - GPU_matrix_bind(batch->interface); // external call. - GPU_shader_set_srgb_uniform(batch->interface); - - GPU_batch_bind(batch); - GPU_batch_draw_advanced(batch, 0, 0, 0, 0); + BLI_assert(batch->inst[0] == NULL); - GPU_batch_program_use_end(batch); + GPU_shader_bind(batch->shader); + GPU_batch_draw_advanced(batch, 0, 0, 0, i_count); + GPU_shader_unbind(); } -#if GPU_TRACK_INDEX_RANGE -# define BASE_INDEX(el) ((el)->base_index) -# define INDEX_TYPE(el) ((el)->gl_index_type) -#else -# define BASE_INDEX(el) 0 -# define INDEX_TYPE(el) GL_UNSIGNED_INT -#endif - void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count) { - BLI_assert(batch->program_in_use); - /* TODO could assert that VAO is bound. */ + BLI_assert(GPU_context_active_get()->shader != NULL); if (v_count == 0) { v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len; @@ -699,8 +348,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi if (i_count == 0) { i_count = (batch->inst[0]) ? batch->inst[0]->vertex_len : 1; /* Meh. This is to be able to use different numbers of verts in instance vbos. */ - if (batch->inst[1] && i_count > batch->inst[1]->vertex_len) { - i_count = batch->inst[1]->vertex_len; + if (batch->inst[1] != NULL) { + i_count = min_ii(i_count, batch->inst[1]->vertex_len); } } @@ -709,76 +358,7 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi return; } - /* Verify there is enough data do draw. */ - /* TODO(fclem) Nice to have but this is invalid when using procedural draw-calls. - * The right assert would be to check if there is an enabled attribute from each VBO - * and check their length. */ - // BLI_assert(i_first + i_count <= (batch->inst ? batch->inst->vertex_len : INT_MAX)); - // BLI_assert(v_first + v_count <= - // (batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len)); - -#ifdef __APPLE__ - GLuint vao = 0; -#endif - - if (!GPU_arb_base_instance_is_supported()) { - if (i_first > 0) { -#ifdef __APPLE__ - /** - * There seems to be a nasty bug when drawing using the same VAO reconfiguring. (see T71147) - * We just use a throwaway VAO for that. Note that this is likely to degrade performance. - **/ - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); -#else - /* If using offset drawing with instancing, we must - * use the default VAO and redo bindings. */ - glBindVertexArray(GPU_vao_default()); -#endif - batch_update_program_bindings(batch, i_first); - } - else { - /* Previous call could have bind the default vao - * see above. */ - glBindVertexArray(batch->vao_id); - } - } - - if (batch->elem) { - const GPUIndexBuf *el = batch->elem; - GLenum index_type = INDEX_TYPE(el); - GLint base_index = BASE_INDEX(el); - void *v_first_ofs = elem_offset(el, v_first); - - if (GPU_arb_base_instance_is_supported()) { - glDrawElementsInstancedBaseVertexBaseInstance( - batch->gl_prim_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first); - } - else { - glDrawElementsInstancedBaseVertex( - batch->gl_prim_type, v_count, index_type, v_first_ofs, i_count, base_index); - } - } - else { -#ifdef __APPLE__ - glDisable(GL_PRIMITIVE_RESTART); -#endif - if (GPU_arb_base_instance_is_supported()) { - glDrawArraysInstancedBaseInstance(batch->gl_prim_type, v_first, v_count, i_count, i_first); - } - else { - glDrawArraysInstanced(batch->gl_prim_type, v_first, v_count, i_count); - } -#ifdef __APPLE__ - glEnable(GL_PRIMITIVE_RESTART); -#endif - } - -#ifdef __APPLE__ - if (vao != 0) { - glDeleteVertexArrays(1, &vao); - } -#endif + static_cast<Batch *>(batch)->draw(v_first, v_count, i_first, i_count); } /* just draw some vertices and let shader place them where we want. */ @@ -795,191 +375,6 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count) // glBindVertexArray(0); } -/* -------------------------------------------------------------------- */ -/** \name Indirect Draw Calls - * \{ */ - -#if 0 -# define USE_MULTI_DRAW_INDIRECT 0 -#else -# define USE_MULTI_DRAW_INDIRECT \ - (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported()) -#endif - -typedef struct GPUDrawCommand { - uint v_count; - uint i_count; - uint v_first; - uint i_first; -} GPUDrawCommand; - -typedef struct GPUDrawCommandIndexed { - uint v_count; - uint i_count; - uint v_first; - uint base_index; - uint i_first; -} GPUDrawCommandIndexed; - -struct GPUDrawList { - GPUBatch *batch; - uint base_index; /* Avoid dereferencing batch. */ - uint cmd_offset; /* in bytes, offset inside indirect command buffer. */ - uint cmd_len; /* Number of used command for the next call. */ - uint buffer_size; /* in bytes, size of indirect command buffer. */ - GLuint buffer_id; /* Draw Indirect Buffer id */ - union { - GPUDrawCommand *commands; - GPUDrawCommandIndexed *commands_indexed; - }; -}; - -GPUDrawList *GPU_draw_list_create(int length) -{ - GPUDrawList *list = (GPUDrawList *)MEM_callocN(sizeof(GPUDrawList), "GPUDrawList"); - /* Alloc the biggest possible command list which is indexed. */ - list->buffer_size = sizeof(GPUDrawCommandIndexed) * length; - if (USE_MULTI_DRAW_INDIRECT) { - list->buffer_id = GPU_buf_alloc(); - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id); - glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW); - } - else { - list->commands = (GPUDrawCommand *)MEM_mallocN(list->buffer_size, "GPUDrawList data"); - } - return list; -} - -void GPU_draw_list_discard(GPUDrawList *list) -{ - if (list->buffer_id) { - GPU_buf_free(list->buffer_id); - } - else { - MEM_SAFE_FREE(list->commands); - } - MEM_freeN(list); -} - -void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch) -{ - BLI_assert(batch->phase == GPU_BATCH_READY_TO_DRAW); - list->batch = batch; - list->base_index = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX; - list->cmd_len = 0; - - if (USE_MULTI_DRAW_INDIRECT) { - if (list->commands == NULL) { - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id); - if (list->cmd_offset >= list->buffer_size) { - /* Orphan buffer data and start fresh. */ - glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW); - list->cmd_offset = 0; - } - GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT; - list->commands = (GPUDrawCommand *)glMapBufferRange( - GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags); - } - } - else { - list->cmd_offset = 0; - } -} - -void GPU_draw_list_command_add( - GPUDrawList *list, int v_first, int v_count, int i_first, int i_count) -{ - BLI_assert(list->commands); - - if (v_count == 0 || i_count == 0) { - return; - } - - if (list->base_index != UINT_MAX) { - GPUDrawCommandIndexed *cmd = list->commands_indexed + list->cmd_len; - cmd->v_first = v_first; - cmd->v_count = v_count; - cmd->i_count = i_count; - cmd->base_index = list->base_index; - cmd->i_first = i_first; - } - else { - GPUDrawCommand *cmd = list->commands + list->cmd_len; - cmd->v_first = v_first; - cmd->v_count = v_count; - cmd->i_count = i_count; - cmd->i_first = i_first; - } - - list->cmd_len++; - uint offset = list->cmd_offset + list->cmd_len * sizeof(GPUDrawCommandIndexed); - - if (offset == list->buffer_size) { - GPU_draw_list_submit(list); - GPU_draw_list_init(list, list->batch); - } -} - -void GPU_draw_list_submit(GPUDrawList *list) -{ - GPUBatch *batch = list->batch; - - if (list->cmd_len == 0) { - return; - } - - BLI_assert(list->commands); - BLI_assert(batch->program_in_use); - /* TODO could assert that VAO is bound. */ - - /* TODO We loose a bit of memory here if we only draw arrays. Fix that. */ - uintptr_t offset = list->cmd_offset; - uint cmd_len = list->cmd_len; - size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed); - list->cmd_len = 0; /* Avoid reuse. */ - - /* Only do multi-draw indirect if doing more than 2 drawcall. - * This avoids the overhead of buffer mapping if scene is - * not very instance friendly. - * BUT we also need to take into account the case where only - * a few instances are needed to finish filling a call buffer. */ - const bool do_mdi = (cmd_len > 2) || (list->cmd_offset + bytes_used == list->buffer_size); - - if (USE_MULTI_DRAW_INDIRECT && do_mdi) { - GLenum prim = batch->gl_prim_type; - - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id); - glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used); - glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); - list->commands = NULL; /* Unmapped */ - list->cmd_offset += bytes_used; - - if (batch->elem) { - glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0); - } - else { - glMultiDrawArraysIndirect(prim, (void *)offset, cmd_len, 0); - } - } - else { - /* Fallback */ - if (batch->elem) { - GPUDrawCommandIndexed *cmd = list->commands_indexed; - for (int i = 0; i < cmd_len; i++, cmd++) { - /* Index start was added by Draw manager. Avoid counting it twice. */ - cmd->v_first -= batch->elem->index_start; - GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); - } - } - else { - GPUDrawCommand *cmd = list->commands; - for (int i = 0; i < cmd_len; i++, cmd++) { - GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); - } - } - } -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -1015,23 +410,11 @@ void GPU_batch_program_set_imm_shader(GPUBatch *batch) void gpu_batch_init(void) { - if (g_default_attr_vbo == 0) { - g_default_attr_vbo = GPU_buf_alloc(); - - float default_attrib_data[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - glBindBuffer(GL_ARRAY_BUFFER, g_default_attr_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(float[4]), default_attrib_data, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - gpu_batch_presets_init(); } void gpu_batch_exit(void) { - GPU_buf_free(g_default_attr_vbo); - g_default_attr_vbo = 0; - gpu_batch_presets_exit(); } diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index 3d9b4326c7e..71c971d8656 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -380,18 +380,6 @@ bool gpu_batch_presets_unregister(GPUBatch *preset_batch) return false; } -void gpu_batch_presets_reset(void) -{ - BLI_mutex_lock(&g_presets_3d.mutex); - /* Reset vao caches for these every time we switch opengl context. - * This way they will draw correctly for each window. */ - LISTBASE_FOREACH (LinkData *, link, &presets_list) { - GPUBatch *preset = link->data; - GPU_batch_vao_cache_clear(preset); - } - BLI_mutex_unlock(&g_presets_3d.mutex); -} - void gpu_batch_presets_exit(void) { LinkData *link; @@ -404,17 +392,4 @@ void gpu_batch_presets_exit(void) BLI_mutex_end(&g_presets_3d.mutex); } -/** - * This function only needs to be accessed externally because - * we are drawing UI batches with the DRW old context. - * - * And now we use it for drawing the entire area. - * - * XXX (Clément) - to cleanup in the upcoming 2.91 refactor. - **/ -void GPU_batch_presets_reset() -{ - gpu_batch_presets_reset(); -} - /** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_private.h b/source/blender/gpu/intern/gpu_batch_private.hh index 93745b9ca9b..3a8044efc1d 100644 --- a/source/blender/gpu/intern/gpu_batch_private.h +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -30,12 +30,16 @@ #include "GPU_context.h" #include "GPU_shader_interface.h" -#ifdef __cplusplus -extern "C" { -#endif +namespace blender { +namespace gpu { -void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface); +class Batch : public GPUBatch { + public: + Batch(){}; + virtual ~Batch(){}; -#ifdef __cplusplus -} -#endif + virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0; +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 85a4d643a0c..e04631910c1 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -40,7 +40,7 @@ #include "GHOST_C-api.h" #include "gpu_backend.hh" -#include "gpu_batch_private.h" +#include "gpu_batch_private.hh" #include "gpu_context_private.hh" #include "gpu_matrix_private.h" @@ -83,12 +83,12 @@ bool GPUContext::is_active_on_thread(void) GPUContext *GPU_context_create(void *ghost_window) { - if (gpu_backend_get() == NULL) { + if (GPUBackend::get() == NULL) { /* TODO move where it make sense. */ GPU_backend_init(GPU_BACKEND_OPENGL); } - GPUContext *ctx = gpu_backend_get()->context_alloc(ghost_window); + GPUContext *ctx = GPUBackend::get()->context_alloc(ghost_window); GPU_context_active_set(ctx); return ctx; @@ -173,14 +173,14 @@ void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx) void GPU_buf_free(GLuint buf_id) { /* TODO avoid using backend */ - GPUBackend *backend = gpu_backend_get(); + GPUBackend *backend = GPUBackend::get(); static_cast<GLBackend *>(backend)->buf_free(buf_id); } void GPU_tex_free(GLuint tex_id) { /* TODO avoid using backend */ - GPUBackend *backend = gpu_backend_get(); + GPUBackend *backend = GPUBackend::get(); static_cast<GLBackend *>(backend)->tex_free(tex_id); } @@ -188,18 +188,6 @@ void GPU_tex_free(GLuint tex_id) * which are not shared across contexts. So we need to keep track of * ownership. */ -void gpu_context_add_batch(GPUContext *ctx, GPUBatch *batch) -{ - BLI_assert(ctx); - static_cast<GLContext *>(ctx)->batch_register(batch); -} - -void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch) -{ - BLI_assert(ctx); - static_cast<GLContext *>(ctx)->batch_unregister(batch); -} - void gpu_context_add_framebuffer(GPUContext *ctx, GPUFrameBuffer *fb) { #ifdef DEBUG @@ -280,14 +268,12 @@ void GPU_backend_init(eGPUBackendType backend_type) void GPU_backend_exit(void) { - if (g_backend) { - /* TODO assert no resource left. Currently UI textures are still not freed in their context - * correctly. */ - delete g_backend; - } + /* TODO assert no resource left. Currently UI textures are still not freed in their context + * correctly. */ + delete g_backend; } -GPUBackend *gpu_backend_get(void) +GPUBackend *GPUBackend::get(void) { return g_backend; } diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh index d369dbe7402..3f9fca16ff7 100644 --- a/source/blender/gpu/intern/gpu_context_private.hh +++ b/source/blender/gpu/intern/gpu_context_private.hh @@ -41,6 +41,7 @@ struct GPUMatrixState; struct GPUContext { public: /** State managment */ + GPUShader *shader = NULL; GPUFrameBuffer *current_fbo = NULL; GPUMatrixState *matrix_state = NULL; @@ -77,9 +78,6 @@ void GPU_tex_free(GLuint tex_id); void GPU_vao_free(GLuint vao_id, GPUContext *ctx); void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx); -void gpu_context_add_batch(GPUContext *ctx, GPUBatch *batch); -void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch); - void gpu_context_add_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb); void gpu_context_remove_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb); diff --git a/source/blender/gpu/intern/gpu_drawlist.cc b/source/blender/gpu/intern/gpu_drawlist.cc new file mode 100644 index 00000000000..7b807a2fa80 --- /dev/null +++ b/source/blender/gpu/intern/gpu_drawlist.cc @@ -0,0 +1,59 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Implementation of Multi Draw Indirect. + */ + +#include "MEM_guardedalloc.h" + +#include "GPU_batch.h" +#include "GPU_drawlist.h" + +#include "gpu_backend.hh" + +#include "gpu_drawlist_private.hh" + +using namespace blender::gpu; + +GPUDrawList GPU_draw_list_create(int list_length) +{ + DrawList *list_ptr = GPUBackend::get()->drawlist_alloc(list_length); + return reinterpret_cast<DrawList *>(list_ptr); +} + +void GPU_draw_list_discard(GPUDrawList list) +{ + DrawList *list_ptr = reinterpret_cast<DrawList *>(list); + delete list_ptr; +} + +void GPU_draw_list_append(GPUDrawList list, GPUBatch *batch, int i_first, int i_count) +{ + DrawList *list_ptr = reinterpret_cast<DrawList *>(list); + list_ptr->append(batch, i_first, i_count); +} + +void GPU_draw_list_submit(GPUDrawList list) +{ + DrawList *list_ptr = reinterpret_cast<DrawList *>(list); + list_ptr->submit(); +} diff --git a/source/blender/gpu/intern/gpu_drawlist_private.hh b/source/blender/gpu/intern/gpu_drawlist_private.hh new file mode 100644 index 00000000000..04cc18a5ffd --- /dev/null +++ b/source/blender/gpu/intern/gpu_drawlist_private.hh @@ -0,0 +1,40 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +namespace blender { +namespace gpu { + +class DrawList { + public: + virtual ~DrawList(){}; + + virtual void append(GPUBatch *batch, int i_first, int i_count) = 0; + virtual void submit() = 0; +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/intern/gpu_element.cc b/source/blender/gpu/intern/gpu_element.cc index cf7cc1d214c..29c95c725fd 100644 --- a/source/blender/gpu/intern/gpu_element.cc +++ b/source/blender/gpu/intern/gpu_element.cc @@ -326,6 +326,11 @@ static void squeeze_indices_short(GPUIndexBufBuilder *builder, #endif /* GPU_TRACK_INDEX_RANGE */ +GPUIndexBuf *GPU_indexbuf_calloc(void) +{ + return (GPUIndexBuf *)MEM_callocN(sizeof(GPUIndexBuf), __func__); +} + GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder) { GPUIndexBuf *elem = (GPUIndexBuf *)MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 9cededa54f7..2d137c2f21c 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -171,12 +171,8 @@ void immBindBuiltinProgram(eGPUBuiltinShader shader_id) void immUnbindProgram(void) { -#if TRUST_NO_ONE - assert(imm.bound_program != NULL); -#endif -#if PROGRAM_NO_OPTI - glUseProgram(0); -#endif + BLI_assert(imm.bound_program != NULL); + GPU_shader_unbind(); imm.bound_program = NULL; } @@ -321,7 +317,7 @@ GPUBatch *immBeginBatch(GPUPrimType prim_type, uint vertex_len) imm.vertex_data = verts->data; imm.batch = GPU_batch_create_ex(prim_type, verts, NULL, GPU_BATCH_OWNS_VBO); - imm.batch->phase = GPU_BATCH_BUILDING; + imm.batch->flag |= GPU_BATCH_BUILDING; return imm.batch; } @@ -423,7 +419,7 @@ void immEnd(void) /* TODO: resize only if vertex count is much smaller */ } GPU_batch_set_shader(imm.batch, imm.bound_program); - imm.batch->phase = GPU_BATCH_READY_TO_DRAW; + imm.batch->flag &= ~GPU_BATCH_BUILDING; imm.batch = NULL; /* don't free, batch belongs to caller */ } else { diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 03b7d5402f5..7a44efce7fb 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -42,6 +42,7 @@ #include "GPU_texture.h" #include "GPU_uniformbuffer.h" +#include "gpu_context_private.hh" #include "gpu_shader_private.h" extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[]; @@ -258,38 +259,6 @@ GPUShader *GPU_shader_create_from_python(const char *vertexcode, return sh; } -GPUShader *GPU_shader_load_from_binary(const char *binary, - const int binary_format, - const int binary_len, - const char *shname) -{ - BLI_assert(GL_ARB_get_program_binary); - int success; - int program = glCreateProgram(); - - glProgramBinary(program, binary_format, binary, binary_len); - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success) { - glUseProgram(program); - - GPUShader *shader = (GPUShader *)MEM_callocN(sizeof(*shader), __func__); - shader->interface = GPU_shaderinterface_create(program); - shader->program = program; - -#ifndef NDEBUG - BLI_snprintf(shader->name, sizeof(shader->name), "%s_%u", shname, g_shaderid++); -#else - UNUSED_VARS(shname); -#endif - - return shader; - } - - glDeleteProgram(program); - return NULL; -} - GPUShader *GPU_shader_create_ex(const char *vertexcode, const char *fragcode, const char *geocode, @@ -598,14 +567,27 @@ void GPU_shader_bind(GPUShader *shader) { BLI_assert(shader && shader->program); - glUseProgram(shader->program); - GPU_matrix_bind(shader->interface); - GPU_shader_set_srgb_uniform(shader->interface); + GPUContext *ctx = GPU_context_active_get(); + + if (ctx->shader != shader) { + ctx->shader = shader; + glUseProgram(shader->program); + GPU_matrix_bind(shader->interface); + GPU_shader_set_srgb_uniform(shader->interface); + } + + if (GPU_matrix_dirty_get()) { + GPU_matrix_bind(shader->interface); + } } void GPU_shader_unbind(void) { +#ifndef NDEBUG + GPUContext *ctx = GPU_context_active_get(); + ctx->shader = NULL; glUseProgram(0); +#endif } /** \} */ @@ -709,38 +691,12 @@ int GPU_shader_get_program(GPUShader *shader) return (int)shader->program; } -char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len) -{ - BLI_assert(GLEW_ARB_get_program_binary); - char *r_binary; - int binary_len = 0; - - glGetProgramiv(shader->program, GL_PROGRAM_BINARY_LENGTH, &binary_len); - r_binary = (char *)MEM_mallocN(binary_len, __func__); - glGetProgramBinary(shader->program, binary_len, NULL, r_binary_format, r_binary); - - if (r_binary_len) { - *r_binary_len = binary_len; - } - - return r_binary; -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name Uniforms setters * \{ */ -void GPU_shader_uniform_float(GPUShader *UNUSED(shader), int location, float value) -{ - if (location == -1) { - return; - } - - glUniform1f(location, value); -} - void GPU_shader_uniform_vector( GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) { @@ -773,22 +729,9 @@ void GPU_shader_uniform_vector( } } -void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) -{ - if (location == -1) { - return; - } - - glUniform1i(location, value); -} - void GPU_shader_uniform_vector_int( GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) { - if (location == -1) { - return; - } - switch (length) { case 1: glUniform1iv(location, arraysize, value); @@ -808,6 +751,91 @@ void GPU_shader_uniform_vector_int( } } +void GPU_shader_uniform_int(GPUShader *shader, int location, int value) +{ + GPU_shader_uniform_vector_int(shader, location, 1, 1, &value); +} + +void GPU_shader_uniform_float(GPUShader *shader, int location, float value) +{ + GPU_shader_uniform_vector(shader, location, 1, 1, &value); +} + +#define GET_UNIFORM \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(sh->interface, name); \ + BLI_assert(uniform); + +void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value) +{ + GET_UNIFORM + GPU_shader_uniform_int(sh, uniform->location, value); +} + +void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value) +{ + GPU_shader_uniform_1i(sh, name, value ? 1 : 0); +} + +void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y) +{ + const float data[2] = {x, y}; + GPU_shader_uniform_2fv(sh, name, data); +} + +void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z) +{ + const float data[3] = {x, y, z}; + GPU_shader_uniform_3fv(sh, name, data); +} + +void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w) +{ + const float data[4] = {x, y, z, w}; + GPU_shader_uniform_4fv(sh, name, data); +} + +void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float x) +{ + GET_UNIFORM + GPU_shader_uniform_float(sh, uniform->location, x); +} + +void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]) +{ + GET_UNIFORM + GPU_shader_uniform_vector(sh, uniform->location, 2, 1, data); +} + +void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]) +{ + GET_UNIFORM + GPU_shader_uniform_vector(sh, uniform->location, 3, 1, data); +} + +void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]) +{ + GET_UNIFORM + GPU_shader_uniform_vector(sh, uniform->location, 4, 1, data); +} + +void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]) +{ + GET_UNIFORM + GPU_shader_uniform_vector(sh, uniform->location, 16, 1, (const float *)data); +} + +void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]) +{ + GET_UNIFORM + GPU_shader_uniform_vector(sh, uniform->location, 2, len, (const float *)val); +} + +void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]) +{ + GET_UNIFORM + GPU_shader_uniform_vector(sh, uniform->location, 4, len, (const float *)val); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc index 4511d4a199d..ef90dde1877 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.cc +++ b/source/blender/gpu/intern/gpu_shader_interface.cc @@ -32,9 +32,11 @@ #include "GPU_shader_interface.h" -#include "gpu_batch_private.h" +#include "gpu_batch_private.hh" #include "gpu_context_private.hh" +#include "gl_batch.hh" + #include <stddef.h> #include <stdlib.h> #include <string.h> @@ -45,6 +47,8 @@ # include <stdio.h> #endif +using namespace blender::gpu; + static const char *BuiltinUniform_name(GPUUniformBuiltin u) { switch (u) { @@ -400,8 +404,8 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) /* Batches ref buffer */ shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = (GPUBatch **)MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), - "GPUShaderInterface batches"); + shaderface->batches = (void **)MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), + "GPUShaderInterface batches"); MEM_freeN(uniforms_from_blocks); MEM_freeN(inputs_tmp); @@ -468,7 +472,8 @@ void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) /* Remove this interface from all linked Batches vao cache. */ for (int i = 0; i < shaderface->batches_len; i++) { if (shaderface->batches[i] != NULL) { - gpu_batch_remove_interface_ref(shaderface->batches[i], shaderface); + /* XXX GL specific. to be removed during refactor. */ + reinterpret_cast<GLVaoCache *>(shaderface->batches[i])->remove(shaderface); } } MEM_freeN(shaderface->batches); @@ -511,7 +516,7 @@ int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, return shaderface->builtin_blocks[builtin]; } -void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch) +void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, void *batch) { int i; /* find first unused slot */ for (i = 0; i < shaderface->batches_len; i++) { @@ -523,13 +528,14 @@ void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch /* Not enough place, realloc the array. */ i = shaderface->batches_len; shaderface->batches_len += GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = (GPUBatch **)MEM_recallocN(shaderface->batches, - sizeof(GPUBatch *) * shaderface->batches_len); + shaderface->batches = (void **)MEM_recallocN(shaderface->batches, + sizeof(void *) * shaderface->batches_len); } - shaderface->batches[i] = batch; + /** XXX todo cleanup. */ + shaderface->batches[i] = reinterpret_cast<void *>(batch); } -void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch) +void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, void *batch) { for (int i = 0; i < shaderface->batches_len; i++) { if (shaderface->batches[i] == batch) { diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index 14ef285ad01..a45bd222664 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -614,6 +614,13 @@ static float *GPU_texture_rescale_3d( static bool gpu_texture_check_capacity( GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum data_format, GLenum data_type) { + if (proxy == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB && + GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_ANY)) { + /* Special fix for T79703. */ + /* Depth has already been checked. */ + return tex->w <= GPU_max_cube_map_size(); + } + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY) || GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_OFFICIAL) || GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL)) { diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc index 67ad8835b6a..debf9835c90 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.cc +++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc @@ -77,6 +77,7 @@ void GPU_vertbuf_init(GPUVertBuf *verts, GPUUsageType usage) memset(verts, 0, sizeof(GPUVertBuf)); verts->usage = usage; verts->dirty = true; + verts->handle_refcount = 1; } void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, @@ -137,7 +138,23 @@ void GPU_vertbuf_clear(GPUVertBuf *verts) void GPU_vertbuf_discard(GPUVertBuf *verts) { GPU_vertbuf_clear(verts); - MEM_freeN(verts); + GPU_vertbuf_handle_ref_remove(verts); +} + +void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts) +{ + verts->handle_refcount++; +} + +void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts) +{ + BLI_assert(verts->handle_refcount > 0); + verts->handle_refcount--; + if (verts->handle_refcount == 0) { + /* Should already have been cleared. */ + BLI_assert(verts->vbo_id == 0 && verts->data == NULL); + MEM_freeN(verts); + } } uint GPU_vertbuf_size_get(const GPUVertBuf *verts) diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index f7c01b2f184..eba275f0245 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -27,7 +27,9 @@ #include "BLI_vector.hh" +#include "gl_batch.hh" #include "gl_context.hh" +#include "gl_drawlist.hh" namespace blender { namespace gpu { @@ -42,6 +44,16 @@ class GLBackend : public GPUBackend { return new GLContext(ghost_window, shared_orphan_list_); }; + Batch *batch_alloc(void) + { + return new GLBatch(); + }; + + DrawList *drawlist_alloc(int list_length) + { + return new GLDrawList(list_length); + }; + /* TODO remove */ void buf_free(GLuint buf_id); void tex_free(GLuint tex_id); diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc new file mode 100644 index 00000000000..00e1a61f7cf --- /dev/null +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -0,0 +1,367 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GL implementation of GPUBatch. + * The only specificity of GL here is that it caches a list of + * Vertex Array Objects based on the bound shader interface. + */ + +#include "BLI_assert.h" + +#include "glew-mx.h" + +#include "GPU_extensions.h" + +#include "gpu_batch_private.hh" +#include "gpu_primitive_private.h" +#include "gpu_shader_private.h" + +#include "gl_batch.hh" +#include "gl_context.hh" +#include "gl_vertex_array.hh" + +using namespace blender::gpu; + +/* -------------------------------------------------------------------- */ +/** \name Vao cache + * + * Each GLBatch has a small cache of VAO objects that are used to avoid VAO reconfiguration. + * TODO(fclem) Could be revisited to avoid so much cross references. + * \{ */ + +GLVaoCache::GLVaoCache(void) +{ + init(); +} + +GLVaoCache::~GLVaoCache() +{ + this->clear(); +} + +void GLVaoCache::init(void) +{ + context_ = NULL; + interface_ = NULL; + is_dynamic_vao_count = false; + for (int i = 0; i < GPU_VAO_STATIC_LEN; i++) { + static_vaos.interfaces[i] = NULL; + static_vaos.vao_ids[i] = 0; + } + vao_base_instance_ = 0; + base_instance_ = 0; +} + +/* Create a new VAO object and store it in the cache. */ +void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao) +{ + /* Now insert the cache. */ + if (!is_dynamic_vao_count) { + int i; /* find first unused slot */ + for (i = 0; i < GPU_VAO_STATIC_LEN; i++) { + if (static_vaos.vao_ids[i] == 0) { + break; + } + } + + if (i < GPU_VAO_STATIC_LEN) { + static_vaos.interfaces[i] = interface; + static_vaos.vao_ids[i] = vao; + } + else { + /* Erase previous entries, they will be added back if drawn again. */ + for (int i = 0; i < GPU_VAO_STATIC_LEN; i++) { + if (static_vaos.interfaces[i] != NULL) { + GPU_shaderinterface_remove_batch_ref( + const_cast<GPUShaderInterface *>(static_vaos.interfaces[i]), this); + context_->vao_free(static_vaos.vao_ids[i]); + } + } + /* Not enough place switch to dynamic. */ + is_dynamic_vao_count = true; + /* Init dynamic arrays and let the branch below set the values. */ + dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT; + dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_callocN( + dynamic_vaos.count * sizeof(GPUShaderInterface *), "dyn vaos interfaces"); + dynamic_vaos.vao_ids = (GLuint *)MEM_callocN(dynamic_vaos.count * sizeof(GLuint), + "dyn vaos ids"); + } + } + + if (is_dynamic_vao_count) { + int i; /* find first unused slot */ + for (i = 0; i < dynamic_vaos.count; i++) { + if (dynamic_vaos.vao_ids[i] == 0) { + break; + } + } + + if (i == dynamic_vaos.count) { + /* Not enough place, realloc the array. */ + i = dynamic_vaos.count; + dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT; + dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_recallocN( + (void *)dynamic_vaos.interfaces, sizeof(GPUShaderInterface *) * dynamic_vaos.count); + dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN(dynamic_vaos.vao_ids, + sizeof(GLuint) * dynamic_vaos.count); + } + dynamic_vaos.interfaces[i] = interface; + dynamic_vaos.vao_ids[i] = vao; + } + + GPU_shaderinterface_add_batch_ref(const_cast<GPUShaderInterface *>(interface), this); +} + +void GLVaoCache::remove(const GPUShaderInterface *interface) +{ + const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN; + GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids; + const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : + static_vaos.interfaces; + for (int i = 0; i < count; i++) { + if (interfaces[i] == interface) { + context_->vao_free(vaos[i]); + vaos[i] = 0; + interfaces[i] = NULL; + break; /* cannot have duplicates */ + } + } +} + +void GLVaoCache::clear(void) +{ + GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get()); + const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN; + GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids; + const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : + static_vaos.interfaces; + /* Early out, nothing to free. */ + if (context_ == NULL) { + return; + } + + if (context_ == ctx) { + glDeleteVertexArrays(count, vaos); + glDeleteVertexArrays(1, &vao_base_instance_); + } + else { + /* TODO(fclem) Slow way. Could avoid multiple mutex lock here */ + for (int i = 0; i < count; i++) { + context_->vao_free(vaos[i]); + } + context_->vao_free(vao_base_instance_); + } + + for (int i = 0; i < count; i++) { + if (interfaces[i] == NULL) { + continue; + } + GPU_shaderinterface_remove_batch_ref(const_cast<GPUShaderInterface *>(interfaces[i]), this); + } + + if (is_dynamic_vao_count) { + MEM_freeN((void *)dynamic_vaos.interfaces); + MEM_freeN(dynamic_vaos.vao_ids); + } + + if (context_) { + context_->vao_cache_unregister(this); + } + /* Reinit. */ + this->init(); +} + +/* Return 0 on cache miss (invalid VAO) */ +GLuint GLVaoCache::lookup(const GPUShaderInterface *interface) +{ + const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN; + const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : + static_vaos.interfaces; + for (int i = 0; i < count; i++) { + if (interfaces[i] == interface) { + return (is_dynamic_vao_count) ? dynamic_vaos.vao_ids[i] : static_vaos.vao_ids[i]; + } + } + return 0; +} + +/* The GLVaoCache object is only valid for one GLContext. + * Reset the cache if trying to draw in another context; */ +void GLVaoCache::context_check(void) +{ + GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get()); + BLI_assert(ctx); + + if (context_ != ctx) { + if (context_ != NULL) { + /* IMPORTANT: Trying to draw a batch in multiple different context will trash the VAO cache. + * This has major performance impact and should be avoided in most cases. */ + context_->vao_cache_unregister(this); + } + this->clear(); + context_ = ctx; + context_->vao_cache_register(this); + } +} + +GLuint GLVaoCache::base_instance_vao_get(GPUBatch *batch, int i_first) +{ + this->context_check(); + /* Make sure the interface is up to date. */ + if (interface_ != GPU_context_active_get()->shader->interface) { + vao_get(batch); + /* Trigger update. */ + base_instance_ = 0; + } + /** + * There seems to be a nasty bug when drawing using the same VAO reconfiguring (T71147). + * We just use a throwaway VAO for that. Note that this is likely to degrade performance. + **/ +#ifdef __APPLE__ + glDeleteVertexArrays(1, &vao_base_instance_); + vao_base_instance_ = 0; +#endif + + if (vao_base_instance_ == 0) { + glGenVertexArrays(1, &vao_base_instance_); + } + + if (base_instance_ != i_first) { + base_instance_ = i_first; + GLVertArray::update_bindings(vao_base_instance_, batch, interface_, i_first); + } + return base_instance_; +} + +GLuint GLVaoCache::vao_get(GPUBatch *batch) +{ + this->context_check(); + + GPUContext *ctx = GPU_context_active_get(); + if (interface_ != ctx->shader->interface) { + interface_ = ctx->shader->interface; + vao_id_ = this->lookup(interface_); + + if (vao_id_ == 0) { + /* Cache miss, create a new VAO. */ + glGenVertexArrays(1, &vao_id_); + this->insert(interface_, vao_id_); + GLVertArray::update_bindings(vao_id_, batch, interface_, 0); + } + } + + return vao_id_; +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Creation & Deletion + * \{ */ + +GLBatch::GLBatch(void) +{ +} + +GLBatch::~GLBatch() +{ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Drawing + * \{ */ + +#if GPU_TRACK_INDEX_RANGE +# define BASE_INDEX(el) ((el)->base_index) +# define INDEX_TYPE(el) ((el)->gl_index_type) +#else +# define BASE_INDEX(el) 0 +# define INDEX_TYPE(el) GL_UNSIGNED_INT +#endif + +void GLBatch::bind(int i_first) +{ + if (flag & GPU_BATCH_DIRTY) { + vao_cache_.clear(); + } + +#if GPU_TRACK_INDEX_RANGE + /* Can be removed if GL 4.3 is required. */ + if (!GLEW_ARB_ES3_compatibility && (elem != NULL)) { + glPrimitiveRestartIndex((elem->index_type == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu); + } +#endif + + /* Can be removed if GL 4.2 is required. */ + if (!GPU_arb_base_instance_is_supported() && (i_first > 0)) { + glBindVertexArray(vao_cache_.base_instance_vao_get(this, i_first)); + } + else { + glBindVertexArray(vao_cache_.vao_get(this)); + } +} + +void GLBatch::draw(int v_first, int v_count, int i_first, int i_count) +{ + this->bind(i_first); + + GLenum gl_type = convert_prim_type_to_gl(prim_type); + + if (elem) { + const GPUIndexBuf *el = elem; + GLenum index_type = INDEX_TYPE(el); + GLint base_index = BASE_INDEX(el); + void *v_first_ofs = (GLuint *)0 + v_first + el->index_start; + +#if GPU_TRACK_INDEX_RANGE + if (el->index_type == GPU_INDEX_U16) { + v_first_ofs = (GLushort *)0 + v_first + el->index_start; + } +#endif + + if (GPU_arb_base_instance_is_supported()) { + glDrawElementsInstancedBaseVertexBaseInstance( + gl_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first); + } + else { + glDrawElementsInstancedBaseVertex( + gl_type, v_count, index_type, v_first_ofs, i_count, base_index); + } + } + else { +#ifdef __APPLE__ + glDisable(GL_PRIMITIVE_RESTART); +#endif + if (GPU_arb_base_instance_is_supported()) { + glDrawArraysInstancedBaseInstance(gl_type, v_first, v_count, i_count, i_first); + } + else { + glDrawArraysInstanced(gl_type, v_first, v_count, i_count); + } +#ifdef __APPLE__ + glEnable(GL_PRIMITIVE_RESTART); +#endif + } +} + +/** \} */ diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh new file mode 100644 index 00000000000..d70f43aed2a --- /dev/null +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -0,0 +1,105 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU geometry batch + * Contains VAOs + VBOs + Shader representing a drawable entity. + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_batch_private.hh" + +#include "glew-mx.h" + +#include "GPU_shader_interface.h" + +namespace blender { +namespace gpu { + +#define GPU_VAO_STATIC_LEN 3 + +/* Vao management: remembers all geometry state (vertex attribute bindings & element buffer) + * for each shader interface. Start with a static number of vaos and fallback to dynamic count + * if necessary. Once a batch goes dynamic it does not go back. */ +class GLVaoCache { + private: + /** Context for which the vao_cache_ was generated. */ + struct GLContext *context_ = NULL; + /** Last interface this batch was drawn with. */ + GPUShaderInterface *interface_ = NULL; + /** Cached vao for the last interface. */ + GLuint vao_id_ = 0; + /** Used whend arb_base_instance is not supported. */ + GLuint vao_base_instance_ = 0; + int base_instance_ = 0; + + bool is_dynamic_vao_count = false; + union { + /** Static handle count */ + struct { + const GPUShaderInterface *interfaces[GPU_VAO_STATIC_LEN]; + GLuint vao_ids[GPU_VAO_STATIC_LEN]; + } static_vaos; + /** Dynamic handle count */ + struct { + uint count; + const GPUShaderInterface **interfaces; + GLuint *vao_ids; + } dynamic_vaos; + }; + + public: + GLVaoCache(); + ~GLVaoCache(); + + GLuint vao_get(GPUBatch *batch); + GLuint base_instance_vao_get(GPUBatch *batch, int i_first); + + GLuint lookup(const GPUShaderInterface *interface); + void insert(const GPUShaderInterface *interface, GLuint vao_id); + void remove(const GPUShaderInterface *interface); + void clear(void); + + private: + void init(void); + void context_check(void); +}; + +class GLBatch : public Batch { + public: + /** All vaos corresponding to all the GPUShaderInterface this batch was drawn with. */ + GLVaoCache vao_cache_; + + public: + GLBatch(); + ~GLBatch(); + + void draw(int v_first, int v_count, int i_first, int i_count) override; + void bind(int i_first); + + MEM_CXX_CLASS_ALLOC_FUNCS("GLBatch"); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc index 37c84abaa7f..dd413612879 100644 --- a/source/blender/gpu/opengl/gl_context.cc +++ b/source/blender/gpu/opengl/gl_context.cc @@ -63,8 +63,8 @@ GLContext::~GLContext() /* For now don't allow GPUFrameBuffers to be reuse in another context. */ BLI_assert(framebuffers_.is_empty()); /* Delete vaos so the batch can be reused in another context. */ - for (GPUBatch *batch : batches_) { - GPU_batch_vao_cache_clear(batch); + for (GLVaoCache *cache : vao_caches_) { + cache->clear(); } glDeleteVertexArrays(1, &default_vao_); glDeleteBuffers(1, &default_attr_vbo_); @@ -193,24 +193,21 @@ void GLBackend::tex_free(GLuint tex_id) /** \name Linked object deletion * * These objects contain data that are stored per context. We - * need to do some cleanup if they are used accross context or if context + * need to do some cleanup if they are used across context or if context * is discarded. * \{ */ -void GLContext::batch_register(struct GPUBatch *batch) +void GLContext::vao_cache_register(GLVaoCache *cache) { lists_mutex_.lock(); - batches_.add(batch); + vao_caches_.add(cache); lists_mutex_.unlock(); } -void GLContext::batch_unregister(struct GPUBatch *batch) +void GLContext::vao_cache_unregister(GLVaoCache *cache) { - /* vao_cache_clear() can acquire lists_mutex_ so avoid deadlock. */ - // reinterpret_cast<GLBatch *>(batch)->vao_cache_clear(); - lists_mutex_.lock(); - batches_.remove(batch); + vao_caches_.remove(cache); lists_mutex_.unlock(); } diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index 3b55965b9d1..0b762c939f1 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -25,15 +25,16 @@ #include "gpu_context_private.hh" +#include "GPU_framebuffer.h" + #include "BLI_set.hh" #include "BLI_vector.hh" #include "glew-mx.h" -#include <iostream> +#include "gl_batch.hh" + #include <mutex> -#include <unordered_set> -#include <vector> namespace blender { namespace gpu { @@ -50,7 +51,7 @@ class GLSharedOrphanLists { void orphans_clear(void); }; -class GLContext : public GPUContext { +struct GLContext : public GPUContext { /* TODO(fclem) these needs to become private. */ public: /** Default VAO for procedural draw calls. */ @@ -63,7 +64,7 @@ class GLContext : public GPUContext { * GPUBatch & GPUFramebuffer have references to the context they are from, in the case the * context is destroyed, we need to remove any reference to it. */ - Set<GPUBatch *> batches_; + Set<GLVaoCache *> vao_caches_; Set<GPUFrameBuffer *> framebuffers_; /** Mutex for the bellow structures. */ std::mutex lists_mutex_; @@ -87,8 +88,8 @@ class GLContext : public GPUContext { void vao_free(GLuint vao_id); void fbo_free(GLuint fbo_id); - void batch_register(struct GPUBatch *batch); - void batch_unregister(struct GPUBatch *batch); + void vao_cache_register(GLVaoCache *cache); + void vao_cache_unregister(GLVaoCache *cache); void framebuffer_register(struct GPUFrameBuffer *fb); void framebuffer_unregister(struct GPUFrameBuffer *fb); }; diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc new file mode 100644 index 00000000000..c121fb9ba2c --- /dev/null +++ b/source/blender/gpu/opengl/gl_drawlist.cc @@ -0,0 +1,240 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Implementation of Multi Draw Indirect using OpenGL. + * Fallback if the needed extensions are not supported. + */ + +#include "BLI_assert.h" + +#include "GPU_batch.h" +#include "GPU_extensions.h" + +#include "glew-mx.h" + +#include "gpu_context_private.hh" +#include "gpu_drawlist_private.hh" +#include "gpu_primitive_private.h" + +#include "gl_backend.hh" +#include "gl_drawlist.hh" + +#include <limits.h> + +#define USE_MULTI_DRAW_INDIRECT 1 + +/* TODO remove. */ +#if GPU_TRACK_INDEX_RANGE +# define BASE_INDEX(el) ((el)->base_index) +# define INDEX_TYPE(el) ((el)->gl_index_type) +#else +# define BASE_INDEX(el) 0 +# define INDEX_TYPE(el) GL_UNSIGNED_INT +#endif + +using namespace blender::gpu; + +typedef struct GLDrawCommand { + GLuint v_count; + GLuint i_count; + GLuint v_first; + GLuint i_first; +} GLDrawCommand; + +typedef struct GLDrawCommandIndexed { + GLuint v_count; + GLuint i_count; + GLuint v_first; + GLuint base_index; + GLuint i_first; +} GLDrawCommandIndexed; + +#define MDI_ENABLED (buffer_size_ != 0) +#define MDI_DISABLED (buffer_size_ == 0) +#define MDI_INDEXED (base_index_ != UINT_MAX) + +GLDrawList::GLDrawList(int length) +{ + BLI_assert(length > 0); + batch_ = NULL; + buffer_id_ = 0; + command_len_ = 0; + command_offset_ = 0; + data_offset_ = 0; + data_size_ = 0; + data_ = NULL; + + if (USE_MULTI_DRAW_INDIRECT && GLEW_ARB_multi_draw_indirect && + GPU_arb_base_instance_is_supported()) { + /* Alloc the biggest possible command list, which is indexed. */ + buffer_size_ = sizeof(GLDrawCommandIndexed) * length; + } + else { + /* Indicates MDI is not supported. */ + buffer_size_ = 0; + } +} + +GLDrawList::~GLDrawList() +{ + /* TODO This ... */ + static_cast<GLBackend *>(GPUBackend::get())->buf_free(buffer_id_); + /* ... should be this. */ + // context_->buf_free(buffer_id_) +} + +void GLDrawList::init(void) +{ + BLI_assert(GPU_context_active_get()); + BLI_assert(MDI_ENABLED); + BLI_assert(data_ == NULL); + batch_ = NULL; + command_len_ = 0; + + if (buffer_id_ == 0) { + /* Allocate on first use. */ + glGenBuffers(1, &buffer_id_); + context_ = static_cast<GLContext *>(GPU_context_active_get()); + } + + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer_id_); + /* If buffer is full, orphan buffer data and start fresh. */ + // if (command_offset_ >= data_size_) { + glBufferData(GL_DRAW_INDIRECT_BUFFER, buffer_size_, NULL, GL_DYNAMIC_DRAW); + data_offset_ = 0; + // } + /* Map the remaining range. */ + GLbitfield flag = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT; + data_size_ = buffer_size_ - data_offset_; + data_ = (GLbyte *)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, data_offset_, data_size_, flag); + command_offset_ = 0; +} + +void GLDrawList::append(GPUBatch *batch, int i_first, int i_count) +{ + /* Fallback when MultiDrawIndirect is not supported/enabled. */ + if (MDI_DISABLED) { + GPU_batch_draw_advanced(batch, 0, 0, i_first, i_count); + return; + } + + if (data_ == NULL) { + this->init(); + } + + if (batch != batch_) { + // BLI_assert(batch->flag | GPU_BATCH_INIT); + this->submit(); + batch_ = batch; + /* Cached for faster access. */ + base_index_ = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX; + v_first_ = batch->elem ? batch->elem->index_start : 0; + v_count_ = batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len; + } + + if (MDI_INDEXED) { + GLDrawCommandIndexed *cmd = reinterpret_cast<GLDrawCommandIndexed *>(data_ + command_offset_); + cmd->v_first = v_first_; + cmd->v_count = v_count_; + cmd->i_count = i_count; + cmd->base_index = base_index_; + cmd->i_first = i_first; + command_offset_ += sizeof(GLDrawCommandIndexed); + } + else { + GLDrawCommand *cmd = reinterpret_cast<GLDrawCommand *>(data_ + command_offset_); + cmd->v_first = v_first_; + cmd->v_count = v_count_; + cmd->i_count = i_count; + cmd->i_first = i_first; + command_offset_ += sizeof(GLDrawCommand); + } + + command_len_++; + + if (command_offset_ >= data_size_) { + this->submit(); + } +} + +void GLDrawList::submit(void) +{ + if (command_len_ == 0) { + return; + } + /* Something's wrong if we get here without MDI support. */ + BLI_assert(MDI_ENABLED); + BLI_assert(data_); + BLI_assert(GPU_context_active_get()->shader != NULL); + + GLBatch *batch = static_cast<GLBatch *>(batch_); + + /* Only do multi-draw indirect if doing more than 2 drawcall. This avoids the overhead of + * buffer mapping if scene is not very instance friendly. BUT we also need to take into + * account the + * case where only a few instances are needed to finish filling a call buffer. */ + const bool is_finishing_a_buffer = (command_offset_ >= data_size_); + if (command_len_ > 2 || is_finishing_a_buffer) { + GLenum prim = convert_prim_type_to_gl(batch_->prim_type); + void *offset = (void *)data_offset_; + + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer_id_); + glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, command_offset_); + glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); + data_ = NULL; /* Unmapped */ + data_offset_ += command_offset_; + + batch->bind(0); + + if (MDI_INDEXED) { + glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch_->elem), offset, command_len_, 0); + } + else { + glMultiDrawArraysIndirect(prim, offset, command_len_, 0); + } + } + else { + /* Fallback do simple drawcalls, and don't unmap the buffer. */ + if (MDI_INDEXED) { + GLDrawCommandIndexed *cmd = (GLDrawCommandIndexed *)data_; + for (int i = 0; i < command_len_; i++, cmd++) { + /* Index start was already added. Avoid counting it twice. */ + cmd->v_first -= batch->elem->index_start; + batch->draw(cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); + } + /* Reuse the same data. */ + command_offset_ -= command_len_ * sizeof(GLDrawCommandIndexed); + } + else { + GLDrawCommand *cmd = (GLDrawCommand *)data_; + for (int i = 0; i < command_len_; i++, cmd++) { + batch->draw(cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); + } + /* Reuse the same data. */ + command_offset_ -= command_len_ * sizeof(GLDrawCommand); + } + } + /* Do not submit this buffer again. */ + command_len_ = 0; +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/gpu/opengl/gl_drawlist.hh b/source/blender/gpu/opengl/gl_drawlist.hh new file mode 100644 index 00000000000..4f085149388 --- /dev/null +++ b/source/blender/gpu/opengl/gl_drawlist.hh @@ -0,0 +1,80 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "BLI_sys_types.h" + +#include "GPU_batch.h" +#include "GPU_glew.h" + +#include "gpu_drawlist_private.hh" + +#include "gl_context.hh" + +namespace blender { +namespace gpu { + +class GLDrawList : public DrawList { + public: + GLDrawList(int length); + ~GLDrawList(); + + void append(GPUBatch *batch, int i_first, int i_count) override; + void submit(void) override; + + private: + void init(void); + + /** Batch for which we are recording commands for. */ + GPUBatch *batch_; + /** Mapped memory bounds. */ + GLbyte *data_; + /** Length of the mapped buffer (in byte). */ + GLsizeiptr data_size_; + /** Current offset inside the mapped buffer (in byte). */ + GLintptr command_offset_; + /** Current number of command recorded inside the mapped buffer. */ + uint command_len_; + /** Is UINT_MAX if not drawing indexed geom. Also Avoid dereferencing batch. */ + GLuint base_index_; + /** Also Avoid dereferencing batch. */ + GLuint v_first_, v_count_; + + /** GL Indirect Buffer id. 0 means MultiDrawIndirect is not supported/enabled. */ + GLuint buffer_id_; + /** Length of whole the buffer (in byte). */ + GLsizeiptr buffer_size_; + /** Offset of data_ inside the whole buffer (in byte). */ + GLintptr data_offset_; + + /** To free the buffer_id_. */ + GLContext *context_; + + MEM_CXX_CLASS_ALLOC_FUNCS("GLDrawList"); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc new file mode 100644 index 00000000000..907dc37e46f --- /dev/null +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -0,0 +1,158 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "GPU_glew.h" + +#include "GPU_shader_interface.h" +#include "GPU_vertex_buffer.h" + +#include "gpu_vertex_format_private.h" + +#include "gl_batch.hh" +#include "gl_context.hh" + +#include "gl_vertex_array.hh" + +using namespace blender::gpu; + +/* -------------------------------------------------------------------- */ +/** \name Vertex Array Bindings + * \{ */ + +/* Returns enabled vertex pointers as a bitflag (one bit per attrib). */ +static uint16_t vbo_bind(const GPUShaderInterface *interface, + const GPUVertFormat *format, + uint v_first, + uint v_len, + const bool use_instancing) +{ + uint16_t enabled_attrib = 0; + const uint attr_len = format->attr_len; + uint stride = format->stride; + uint offset = 0; + GLuint divisor = (use_instancing) ? 1 : 0; + + for (uint a_idx = 0; a_idx < attr_len; a_idx++) { + const GPUVertAttr *a = &format->attrs[a_idx]; + + if (format->deinterleaved) { + offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * v_len; + stride = a->sz; + } + else { + offset = a->offset; + } + + const GLvoid *pointer = (const GLubyte *)0 + offset + v_first * stride; + const GLenum type = convert_comp_type_to_gl(static_cast<GPUVertCompType>(a->comp_type)); + + for (uint n_idx = 0; n_idx < a->name_len; n_idx++) { + const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); + const GPUShaderInput *input = GPU_shaderinterface_attr(interface, name); + + if (input == NULL) { + continue; + } + + enabled_attrib |= (1 << input->location); + + if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) { + BLI_assert(a->fetch_mode == GPU_FETCH_FLOAT); + BLI_assert(a->comp_type == GPU_COMP_F32); + for (int i = 0; i < a->comp_len / 4; i++) { + glEnableVertexAttribArray(input->location + i); + glVertexAttribDivisor(input->location + i, divisor); + glVertexAttribPointer( + input->location + i, 4, type, GL_FALSE, stride, (const GLubyte *)pointer + i * 16); + } + } + else { + glEnableVertexAttribArray(input->location); + glVertexAttribDivisor(input->location, divisor); + + switch (a->fetch_mode) { + case GPU_FETCH_FLOAT: + case GPU_FETCH_INT_TO_FLOAT: + glVertexAttribPointer(input->location, a->comp_len, type, GL_FALSE, stride, pointer); + break; + case GPU_FETCH_INT_TO_FLOAT_UNIT: + glVertexAttribPointer(input->location, a->comp_len, type, GL_TRUE, stride, pointer); + break; + case GPU_FETCH_INT: + glVertexAttribIPointer(input->location, a->comp_len, type, stride, pointer); + break; + } + } + } + } + return enabled_attrib; +} + +/* Update the Attrib Binding of the currently bound VAO. */ +void GLVertArray::update_bindings(const GLuint vao, + const GPUBatch *batch, + const GPUShaderInterface *interface, + const int base_instance) +{ + uint16_t attr_mask = interface->enabled_attr_mask; + + glBindVertexArray(vao); + + /* Reverse order so first VBO'S have more prevalence (in term of attribute override). */ + for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) { + GPUVertBuf *vbo = batch->verts[v]; + if (vbo) { + GPU_vertbuf_use(vbo); + attr_mask &= ~vbo_bind(interface, &vbo->format, 0, vbo->vertex_len, false); + } + } + + for (int v = GPU_BATCH_INST_VBO_MAX_LEN - 1; v > -1; v--) { + GPUVertBuf *vbo = batch->inst[v]; + if (vbo) { + GPU_vertbuf_use(vbo); + attr_mask &= ~vbo_bind(interface, &vbo->format, base_instance, vbo->vertex_len, true); + } + } + + if (attr_mask != 0 && GLEW_ARB_vertex_attrib_binding) { + for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) { + if (attr_mask & mask) { + GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get()); + /* This replaces glVertexAttrib4f(a, 0.0f, 0.0f, 0.0f, 1.0f); with a more modern style. + * Fix issues for some drivers (see T75069). */ + glBindVertexBuffer(a, ctx->default_attr_vbo_, (intptr_t)0, (intptr_t)0); + glEnableVertexAttribArray(a); + glVertexAttribFormat(a, 4, GL_FLOAT, GL_FALSE, 0); + glVertexAttribBinding(a, a); + } + } + } + + if (batch->elem) { + /* Binds the index buffer. This state is also saved in the VAO. */ + GPU_indexbuf_use(batch->elem); + } +} + +/** \} */ diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh new file mode 100644 index 00000000000..6da414d7e62 --- /dev/null +++ b/source/blender/gpu/opengl/gl_vertex_array.hh @@ -0,0 +1,44 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "glew-mx.h" + +#include "GPU_batch.h" +#include "GPU_shader_interface.h" + +namespace blender { +namespace gpu { + +namespace GLVertArray { + +void update_bindings(const GLuint vao, + const GPUBatch *batch, + const GPUShaderInterface *interface, + const int base_instance); + +} // namespace GLVertArray + +} // namespace gpu +} // namespace blender diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 503dba776a7..6c4d2856526 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -387,6 +387,13 @@ typedef enum eBrushBoundaryDeformType { BRUSH_BOUNDARY_DEFORM_TWIST = 4, } eBrushBushBoundaryDeformType; +typedef enum eBrushBoundaryFalloffType { + BRUSH_BOUNDARY_FALLOFF_CONSTANT = 0, + BRUSH_BOUNDARY_FALLOFF_RADIUS = 1, + BRUSH_BOUNDARY_FALLOFF_LOOP = 2, + BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT = 3, +} eBrushBoundaryFalloffType; + /* Gpencilsettings.Vertex_mode */ typedef enum eGp_Vertex_Mode { /* Affect to Stroke only. */ @@ -596,6 +603,8 @@ typedef struct Brush { /* boundary */ int boundary_deform_type; + int boundary_falloff_type; + float boundary_offset; /* cloth */ int cloth_deform_type; @@ -810,6 +819,7 @@ typedef enum eBrushSculptTool { SCULPT_TOOL_PAINT = 28, SCULPT_TOOL_SMEAR = 29, SCULPT_TOOL_BOUNDARY = 30, + SCULPT_TOOL_DISPLACEMENT_ERASER = 31, } eBrushSculptTool; /* Brush.uv_sculpt_tool */ @@ -847,6 +857,7 @@ typedef enum eBrushUVSculptTool { SCULPT_TOOL_CLOTH, \ SCULPT_TOOL_THUMB, \ SCULPT_TOOL_LAYER, \ + SCULPT_TOOL_DISPLACEMENT_ERASER, \ SCULPT_TOOL_DRAW_SHARP, \ SCULPT_TOOL_SLIDE_RELAX, \ SCULPT_TOOL_ELASTIC_DEFORM, \ @@ -866,6 +877,7 @@ typedef enum eBrushUVSculptTool { SCULPT_TOOL_ROTATE, \ SCULPT_TOOL_THUMB, \ SCULPT_TOOL_DRAW_SHARP, \ + SCULPT_TOOL_DISPLACEMENT_ERASER, \ SCULPT_TOOL_SLIDE_RELAX, \ SCULPT_TOOL_MASK) == 0) diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 3816cee0cf8..a6aef5b08ad 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -109,9 +109,12 @@ typedef struct Mesh_Runtime { /** Set by modifier stack if only deformed from original. */ char deformed_only; /** - * Copied from edit-mesh (hint, draw with editmesh data). - * In the future we may leave the mesh-data empty - * since its not needed if we can use edit-mesh data. */ + * Copied from edit-mesh (hint, draw with edit-mesh data when true). + * + * Modifiers that edit the mesh data in-place must set this to false + * (most #eModifierTypeType_NonGeometrical modifiers). Otherwise the edit-mesh + * data will be used for drawing, missing changes from modifiers. See T79517. + */ char is_original; /** #eMeshWrapperType and others. */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index b01b3f42e6a..fc50261eb03 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -22,6 +22,7 @@ #include "DNA_defs.h" #include "DNA_listBase.h" +#include "DNA_session_uuid_types.h" #ifdef __cplusplus extern "C" { @@ -124,6 +125,11 @@ typedef struct ModifierData { /* Pointer to a ModifierData in the original domain. */ struct ModifierData *orig_modifier_data; + + /* Runtime field which contains unique identifier of the modifier. */ + SessionUUID session_uuid; + + /* Runtime field which contains runtime data which is specific to a modifier type. */ void *runtime; } ModifierData; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 7d77e8478ae..ad1635ba0c0 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -612,6 +612,7 @@ typedef enum eSpaceSeq_Flag { SEQ_SHOW_SAFE_CENTER = (1 << 9), SEQ_SHOW_METADATA = (1 << 10), SEQ_SHOW_MARKERS = (1 << 11), /* show markers region */ + SEQ_ZOOM_TO_FIT = (1 << 12), } eSpaceSeq_Flag; /* SpaceSeq.view */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 852ddf32607..a3fa4fed575 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -100,6 +100,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_CLOTH, "CLOTH", ICON_BRUSH_SCULPT_DRAW, "Cloth", ""}, {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""}, {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, + {SCULPT_TOOL_DISPLACEMENT_ERASER, "DISPLACEMENT_ERASER", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Eraser", ""}, {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""}, {SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""}, {SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""}, @@ -1996,6 +1997,31 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_boundary_falloff_type_items[] = { + {BRUSH_BOUNDARY_FALLOFF_CONSTANT, + "CONSTANT", + 0, + "Constant", + "Applies the same deformation in the entire boundary"}, + {BRUSH_BOUNDARY_FALLOFF_RADIUS, + "RADIUS", + 0, + "Brush Radius", + "Applies the deformation in a localiced area limited by the brush radius"}, + {BRUSH_BOUNDARY_FALLOFF_LOOP, + "LOOP", + 0, + "Loop", + "Applies the brush falloff in a loop pattern"}, + {BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT, + "LOOP_INVERT", + 0, + "Loop and Invert", + "Applies the fallof radius in a loop pattern, inverting the displacement direction in each " + "pattern repetition"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_cloth_simulation_area_type_items[] = { {BRUSH_CLOTH_SIMULATION_AREA_LOCAL, "LOCAL", @@ -2193,6 +2219,12 @@ static void rna_def_brush(BlenderRNA *brna) "Part of the mesh that is going to be simulated when the stroke is active"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "boundary_falloff_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_boundary_falloff_type_items); + RNA_def_property_ui_text( + prop, "Boundary Falloff", "How the brush falloff is applied across the boundary"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "smooth_deform_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, brush_smooth_deform_type_items); RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); @@ -2544,6 +2576,14 @@ static void rna_def_brush(BlenderRNA *brna) "Maximum distance to search for disconnected loose parts in the mesh"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "boundary_offset", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "boundary_offset"); + RNA_def_property_range(prop, 0.0f, 30.0f); + RNA_def_property_ui_text(prop, + "Boundary Origin Offset", + "Offset of the boundary origin in relation to the brush radius"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "surface_smooth_shape_preservation", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "surface_smooth_shape_preservation"); RNA_def_property_range(prop, 0.0f, 1.0f); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 05e11ffc919..f95899262d3 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -5539,7 +5539,8 @@ static void rna_def_modifier_remesh(BlenderRNA *brna) prop = RNA_def_property(srna, "octree_depth", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "depth"); - RNA_def_property_range(prop, 1, 12); + RNA_def_property_range(prop, 1, 24); + RNA_def_property_ui_range(prop, 1, 12, 1, 3); RNA_def_property_ui_text( prop, "Octree Depth", "Resolution of the octree; higher values give finer details"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 3b80714bcc5..ab6b60603c7 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -713,8 +713,9 @@ bool rna_Object_generate_gpencil_strokes(Object *ob, bContext *C, ReportList *reports, Object *ob_gpencil, - bool gpencil_lines, - bool use_collections) + bool use_collections, + float scale_thickness, + float sample) { if (ob->type != OB_CURVE) { BKE_reportf(reports, @@ -726,7 +727,8 @@ bool rna_Object_generate_gpencil_strokes(Object *ob, Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - BKE_gpencil_convert_curve(bmain, scene, ob_gpencil, ob, gpencil_lines, use_collections, false); + BKE_gpencil_convert_curve( + bmain, scene, ob_gpencil, ob, use_collections, scale_thickness, sample); WM_main_add_notifier(NC_GPENCIL | ND_DATA, NULL); @@ -1190,12 +1192,17 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_ui_description(func, "Convert a curve object to grease pencil strokes."); RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); - parm = RNA_def_pointer( - func, "ob_gpencil", "Object", "", "Grease Pencil object used to create new strokes"); + parm = RNA_def_pointer(func, + "grease_pencil_object", + "Object", + "", + "Grease Pencil object used to create new strokes"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_boolean(func, "gpencil_lines", 0, "", "Create Lines"); - parm = RNA_def_boolean(func, "use_collections", 1, "", "Use Collections"); - + parm = RNA_def_boolean(func, "use_collections", true, "", "Use Collections"); + parm = RNA_def_float( + func, "scale_thickness", 1.0f, 0.0f, FLT_MAX, "", "Thickness scaling factor", 0.0f, 100.0f); + parm = RNA_def_float( + func, "sample", 0.0f, 0.0f, FLT_MAX, "", "Sample distance, zero to disable", 0.0f, 100.0f); parm = RNA_def_boolean(func, "result", 0, "", "Result"); RNA_def_function_return(func, parm); } diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index fa837df682a..bb3756d9cfc 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -935,7 +935,7 @@ static void rna_def_pointcache_common(StructRNA *srna) prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "startframe"); RNA_def_property_range(prop, -MAXFRAME, MAXFRAME); - RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1); + RNA_def_property_ui_range(prop, 0, MAXFRAME, 1, 1); RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts"); prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_TIME); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 155f5ab3043..9f259aba0c7 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -4796,6 +4796,12 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Waveform Displaying", "How Waveforms are drawn"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + prop = RNA_def_property(srna, "zoom_to_fit", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_ZOOM_TO_FIT); + RNA_def_property_ui_text( + prop, "Zoom to Fit", "Automatically zoom preview image to make it fully fit the region"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + prop = RNA_def_property(srna, "show_overexposed", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "zebra"); RNA_def_property_ui_text(prop, "Show Overexposed", "Show overexposed areas with zebra stripes"); diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 0b205ec4fc5..c8f49694a2f 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -204,32 +204,36 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * BKE_reports_init(&reports, RPT_STORE); /* Note: no islands precision for now here. */ - BKE_object_data_transfer_ex(ctx->depsgraph, - scene, - ob_source, - ctx->object, - result, - dtmd->data_types, - false, - dtmd->vmap_mode, - dtmd->emap_mode, - dtmd->lmap_mode, - dtmd->pmap_mode, - space_transform, - false, - max_dist, - dtmd->map_ray_radius, - 0.0f, - dtmd->layers_select_src, - dtmd->layers_select_dst, - dtmd->mix_mode, - dtmd->mix_factor, - dtmd->defgrp_name, - invert_vgroup, - &reports); + if (BKE_object_data_transfer_ex(ctx->depsgraph, + scene, + ob_source, + ctx->object, + result, + dtmd->data_types, + false, + dtmd->vmap_mode, + dtmd->emap_mode, + dtmd->lmap_mode, + dtmd->pmap_mode, + space_transform, + false, + max_dist, + dtmd->map_ray_radius, + 0.0f, + dtmd->layers_select_src, + dtmd->layers_select_dst, + dtmd->mix_mode, + dtmd->mix_factor, + dtmd->defgrp_name, + invert_vgroup, + &reports)) { + result->runtime.is_original = false; + } if (BKE_reports_contain(&reports, RPT_ERROR)) { - BKE_modifier_set_error(md, "%s", BKE_reports_string(&reports, RPT_ERROR)); + const char *report_str = BKE_reports_string(&reports, RPT_ERROR); + BKE_modifier_set_error(md, "%s", report_str); + MEM_freeN((void *)report_str); } else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) { BKE_modifier_set_error((ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties"); diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index f091385ff8e..98a348bfbfc 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -487,7 +487,7 @@ static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Multires, panel_draw); modifier_subpanel_register( - region_type, "subdivide", "Subdivions", NULL, subdivisions_panel_draw, panel_type); + region_type, "subdivide", "Subdivision", NULL, subdivisions_panel_draw, panel_type); modifier_subpanel_register(region_type, "shape", "Shape", NULL, shape_panel_draw, panel_type); modifier_subpanel_register( region_type, "generate", "Generate", NULL, generate_panel_draw, panel_type); diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 66ab6b9e4db..f22ece11726 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -637,6 +637,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, CustomData_free_layers(pdata, CD_NORMAL, num_polys); MEM_SAFE_FREE(loopnors); + result->runtime.is_original = false; + return result; } diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index a0c4799a46f..797d9e9e251 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -772,6 +772,11 @@ static EMat *build_edge_mats(const MVertSkin *vs, *has_valid_root = true; } + else if (totedge == 0) { + /* Vertex-only mesh is valid, mark valid root as well (will display error otherwise). */ + *has_valid_root = true; + break; + } } } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 6f261f9f67a..361c778bb95 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -308,6 +308,8 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, } } + mesh->runtime.is_original = false; + /* Mark tessellated CD layers as dirty. */ mesh->runtime.cd_dirty_vert |= CD_MASK_TESSLOOPNORMAL; diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index adc89f1b954..05224e1ffaa 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -235,6 +235,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* XXX TODO is this still needed? */ // me_eval->dirty |= DM_DIRTY_TESS_CDLAYERS; + mesh->runtime.is_original = false; + return mesh; } diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index f174b6d5aa4..744bab02c56 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -677,6 +677,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Currently Modifier stack assumes there is no poly normal data passed around... */ CustomData_free_layers(pdata, CD_NORMAL, numPolys); + + result->runtime.is_original = false; + return result; } diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 6bb4f3dc1b5..4f67fd88d4e 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -312,6 +312,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_freeN(new_w); MEM_freeN(dw); + mesh->runtime.is_original = false; + /* Return the vgroup-modified mesh. */ return mesh; } diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 9821ead2340..649481a7023 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -455,6 +455,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_freeN(dw2); MEM_SAFE_FREE(indices); + mesh->runtime.is_original = false; + /* Return the vgroup-modified mesh. */ return mesh; } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 0668a7a086f..b23eb997f61 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -637,6 +637,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * TIMEIT_END(perf); #endif + mesh->runtime.is_original = false; + /* Return the vgroup-modified mesh. */ return mesh; } diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c index 01bccc57c7a..bb7028c11ab 100644 --- a/source/blender/python/gpu/gpu_py_batch.c +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -50,7 +50,7 @@ static bool bpygpu_batch_is_program_or_error(BPyGPUBatch *self) { - if (!glIsProgram(self->batch->program)) { + if (!self->batch->shader) { PyErr_SetString(PyExc_RuntimeError, "batch does not have any program assigned to it"); return false; } @@ -227,7 +227,7 @@ static PyObject *bpygpu_Batch_draw(BPyGPUBatch *self, PyObject *args) return NULL; } } - else if (self->batch->program != GPU_shader_get_program(py_program->shader)) { + else if (self->batch->shader != py_program->shader) { GPU_batch_set_shader(self->batch, py_program->shader); } @@ -240,7 +240,7 @@ static PyObject *bpygpu_Batch_program_use_begin(BPyGPUBatch *self) if (!bpygpu_batch_is_program_or_error(self)) { return NULL; } - GPU_batch_program_use_begin(self->batch); + GPU_shader_bind(self->batch->shader); Py_RETURN_NONE; } @@ -249,7 +249,7 @@ static PyObject *bpygpu_Batch_program_use_end(BPyGPUBatch *self) if (!bpygpu_batch_is_program_or_error(self)) { return NULL; } - GPU_batch_program_use_end(self->batch); + GPU_shader_unbind(); Py_RETURN_NONE; } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 4b2b5f129a7..274c1934e9e 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -227,7 +227,14 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) context_dict_back = CTX_py_dict_get(C); - CTX_py_dict_set(C, (void *)context_dict); + /** + * It might be that there is already a Python context override. We don't want to remove that + * except when this operator call sets a new override explicitly. This is necessary so that + * called operator runs in the same context as the calling code by default. + */ + if (context_dict != NULL) { + CTX_py_dict_set(C, (void *)context_dict); + } Py_XINCREF(context_dict); /* so we done loose it */ if (WM_operator_poll_context((bContext *)C, ot, context) == false) { diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 0c53639c67d..9d76f07e4fb 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -549,8 +549,7 @@ static bool py_bvhtree_overlap_cb(void *userdata, int index_a, int index_b, int } } - return (isect_tri_tri_v3( - UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) && + return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) && ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon))); } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 0941dd49d23..bea4faa779a 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -387,6 +387,18 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C) CTX_wm_window_set(C, NULL); } +static void wm_event_execute_timers(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + /* Set the first window as context, so that there is some minimal context. This avoids crashes + * when calling code that assumes that there is always a window in the context (which many + * operators do). */ + CTX_wm_window_set(C, wm->windows.first); + BLI_timer_execute(); + CTX_wm_window_set(C, NULL); +} + /* called in mainloop */ void wm_event_do_notifiers(bContext *C) { @@ -398,7 +410,7 @@ void wm_event_do_notifiers(bContext *C) return; } - BLI_timer_execute(); + wm_event_execute_timers(C); /* disable? - keep for now since its used for window level notifiers. */ #if 1 diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c index 83558bc9192..953fb9fed79 100644 --- a/source/blender/windowmanager/intern/wm_keymap_utils.c +++ b/source/blender/windowmanager/intern/wm_keymap_utils.c @@ -217,7 +217,6 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) * FLUID_OT * TEXTURE_OT * UI_OT - * VIEW2D_OT * WORLD_OT */ @@ -344,6 +343,10 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) break; } } + /* General 2D View, not bound to a specific spacetype. */ + else if (STRPREFIX(opname, "VIEW2D_OT")) { + km = WM_keymap_find_all(wm, "View2D", 0, 0); + } /* Image Editor */ else if (STRPREFIX(opname, "IMAGE_OT")) { km = WM_keymap_find_all(wm, "Image", sl->spacetype, 0); diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c index 12e55790259..9948434d340 100644 --- a/source/blender/windowmanager/intern/wm_surface.c +++ b/source/blender/windowmanager/intern/wm_surface.c @@ -56,8 +56,6 @@ void wm_surface_clear_drawable(void) WM_opengl_context_release(g_drawable->ghost_ctx); GPU_context_active_set(NULL); - BLF_batch_reset(); - gpu_batch_presets_reset(); immDeactivate(); if (g_drawable->deactivate) { diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 47afa343394..a8a1817be5e 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1112,8 +1112,6 @@ static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool acti void wm_window_clear_drawable(wmWindowManager *wm) { if (wm->windrawable) { - BLF_batch_reset(); - gpu_batch_presets_reset(); immDeactivate(); wm->windrawable = NULL; } |