diff options
122 files changed, 2738 insertions, 2433 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 46f1694ed38..130173d7f01 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -433,7 +433,7 @@ OPENEXR_FORCE_REBUILD=false OPENEXR_SKIP=false _with_built_openexr=false -OIIO_VERSION="2.1.15" +OIIO_VERSION="2.1.15.0" OIIO_VERSION_SHORT="2.1" OIIO_VERSION_MIN="1.8" OIIO_VERSION_MAX="3.0" 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..70189ea4812 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,146 @@ 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; - void add_node(int x, int y, int z); + VolumeMeshBuilder(); - void add_node_with_padding(int x, int y, int z); +#ifdef WITH_OPENVDB + void add_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping); +#endif - void create_mesh(vector<float3> &vertices, vector<int> &indices, vector<float3> &face_normals); + void add_padding(int pad_size); + + 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 +262,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 +270,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 +386,115 @@ 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 +523,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 +562,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/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/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 02f3d0e559e..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", @@ -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_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/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index ae144d9e8d0..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: @@ -2595,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/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..b68fac23f56 100644 --- a/source/blender/blenkernel/BKE_gpencil_curve.h +++ b/source/blender/blenkernel/BKE_gpencil_curve.h @@ -40,7 +40,8 @@ void BKE_gpencil_convert_curve(struct Main *bmain, 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_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/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/collision.c b/source/blender/blenkernel/intern/collision.c index f358355912b..7015e36be1a 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, @@ -665,11 +690,12 @@ static int cloth_collision_response_static(ClothModifierData *clmd, cloth1 = clmd->clothObject; for (int i = 0; i < collision_count; i++, collpair++) { - float i1[3], i2[3], i3[3]; - + float i1[3], i2[3], i3[3], time_multiplier, d; zero_v3(i1); zero_v3(i2); zero_v3(i3); + 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; /* Only handle static collisions here. */ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) { @@ -728,11 +754,10 @@ static int cloth_collision_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]; - float time_multiplier; /* Calculate tangential velocity. */ copy_v3_v3(temp, collpair->normal); @@ -762,20 +787,11 @@ static int cloth_collision_response_static(ClothModifierData *clmd, 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++; - if (!is_hair) { VECADDMUL(i3, collpair->normal, w3 * impulse); - cloth1->verts[collpair->ap3].impulse_count++; } - 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 +806,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,92 +813,33 @@ 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]; - } - } - } + float clamp_sq = clmd->coll_parms->clamp * dt; + clamp_sq *= clamp_sq; + cloth_selfcollision_impulse_vert(clamp_sq, i1, &cloth1->verts[collpair->ap1]); + cloth_selfcollision_impulse_vert(clamp_sq, i2, &cloth1->verts[collpair->ap2]); + cloth_selfcollision_impulse_vert(clamp_sq, i3, &cloth1->verts[collpair->ap3]); } } 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, @@ -900,6 +856,8 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, for (int i = 0; i < collision_count; i++, collpair++) { float ia[3][3] = {{0.0f}}; float ib[3][3] = {{0.0f}}; + float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); + float d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance; /* Only handle static collisions here. */ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) { @@ -952,10 +910,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); @@ -993,10 +951,6 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, VECADDMUL(ib[1], collpair->normal, -u2 * impulse); VECADDMUL(ib[2], collpair->normal, -u3 * 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; - if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) { repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel); @@ -1019,27 +973,20 @@ static int cloth_selfcollision_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->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance; + 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; - 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) { 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..79c41c7c713 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,86 @@ 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 +340,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 +405,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 +440,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 +451,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); } @@ -417,7 +483,8 @@ static void gpencil_editstroke_deselect_all(bGPDcurve *gpc) * \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, @@ -425,7 +492,8 @@ void BKE_gpencil_convert_curve(Main *bmain, 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 +531,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, gpencil_lines, 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/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/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 631961e342d..df0b2b380fa 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -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/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/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/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/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/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 04e3a0dd5b6..e636e755430 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -594,35 +594,9 @@ static int gpencil_stroke_merge_material_exec(bContext *C, wmOperator *op) 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/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/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_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/object/object_add.c b/source/blender/editors/object/object_add.c index 81b8cd70353..197c1c3bdbe 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, false, 1.0f, 0.0f); gpencilConverted = true; } } 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/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..c86e922a347 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -428,7 +428,7 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object, { 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( 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 a8de3be3baf..2afa3556dd9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -1082,7 +1082,7 @@ static void sculpt_face_set_apply_edit(Object *ob, 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; @@ -1096,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; 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..b11a7005fb5 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 */ 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/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/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 85a4d643a0c..283784aec20 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -280,11 +280,9 @@ 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) 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/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 503dba776a7..5d8eddaf5e1 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -810,6 +810,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 +848,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 +868,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/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 852ddf32607..38916e2a45a 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", ""}, 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..609340888e1 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -714,7 +714,9 @@ bool rna_Object_generate_gpencil_strokes(Object *ob, 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 +728,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, gpencil_lines, use_collections, scale_thickness, sample); WM_main_add_notifier(NC_GPENCIL | ND_DATA, NULL); @@ -1190,12 +1193,18 @@ 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, "gpencil_lines", false, "", "Create Lines"); + 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/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_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/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); |