diff options
author | Joseph Eagar <joeedh@gmail.com> | 2022-10-15 09:22:01 +0300 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2022-10-15 09:22:01 +0300 |
commit | aa1f2f243ddb7ed340856ddf97ec650407ad386b (patch) | |
tree | 471c95b234e7764ff7368e480308f21dc5bb0ca7 | |
parent | 278a2137f9a5989f8e9ebb30bbfb761608f0de14 (diff) | |
parent | ebe9804cfa421b746148f3067797f16e7f460551 (diff) |
Merge branch 'master' into temp-pbvh-split
344 files changed, 5326 insertions, 2254 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bb685195bd..408cf819ce8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,17 +242,17 @@ if(UNIX AND NOT (APPLE OR HAIKU)) option(WITH_GHOST_X11 "Enable building Blender against X11 for windowing" ON) mark_as_advanced(WITH_GHOST_X11) - option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing (under development)" OFF) + option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing" ON) mark_as_advanced(WITH_GHOST_WAYLAND) if(WITH_GHOST_WAYLAND) - option(WITH_GHOST_WAYLAND_LIBDECOR "Optionally build with LibDecor window decorations" OFF) + option(WITH_GHOST_WAYLAND_LIBDECOR "Optionally build with LibDecor window decorations" ON) mark_as_advanced(WITH_GHOST_WAYLAND_LIBDECOR) option(WITH_GHOST_WAYLAND_DBUS "Optionally build with DBUS support (used for Cursor themes). May hang on startup systems where DBUS is not used." OFF) mark_as_advanced(WITH_GHOST_WAYLAND_DBUS) - option(WITH_GHOST_WAYLAND_DYNLOAD "Enable runtime dynamic WAYLAND libraries loading" OFF) + option(WITH_GHOST_WAYLAND_DYNLOAD "Enable runtime dynamic WAYLAND libraries loading" ON) mark_as_advanced(WITH_GHOST_WAYLAND_DYNLOAD) endif() endif() @@ -1913,9 +1913,25 @@ if(FIRST_RUN) info_cfg_option(WITH_INSTALL_PORTABLE) info_cfg_option(WITH_MEM_JEMALLOC) info_cfg_option(WITH_MEM_VALGRIND) - info_cfg_option(WITH_X11_XF86VMODE) - info_cfg_option(WITH_X11_XFIXES) - info_cfg_option(WITH_X11_XINPUT) + + info_cfg_text("GHOST Options:") + info_cfg_option(WITH_GHOST_DEBUG) + info_cfg_option(WITH_GHOST_SDL) + if(UNIX AND NOT APPLE) + info_cfg_option(WITH_GHOST_X11) + info_cfg_option(WITH_GHOST_WAYLAND) + if(WITH_GHOST_X11) + info_cfg_option(WITH_GHOST_XDND) + info_cfg_option(WITH_X11_XF86VMODE) + info_cfg_option(WITH_X11_XFIXES) + info_cfg_option(WITH_X11_XINPUT) + endif() + if(WITH_GHOST_WAYLAND) + info_cfg_option(WITH_GHOST_WAYLAND_DYNLOAD) + info_cfg_option(WITH_GHOST_WAYLAND_LIBDECOR) + info_cfg_option(WITH_GHOST_WAYLAND_DBUS) + endif() + endif() info_cfg_text("Image Formats:") info_cfg_option(WITH_IMAGE_CINEON) diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index 468a434b887..4f40f44ad18 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -172,6 +172,8 @@ if(UNIX AND NOT APPLE) include(cmake/wayland_protocols.cmake) # Can be removed when the build-bot upgrades to v1.20.x or newer. include(cmake/wayland.cmake) + include(cmake/wayland_libdecor.cmake) endif() include(cmake/harvest.cmake) +include(cmake/cve_check.cmake) diff --git a/build_files/build_environment/cmake/cve_check.cmake b/build_files/build_environment/cmake/cve_check.cmake new file mode 100644 index 00000000000..dfb190bcffa --- /dev/null +++ b/build_files/build_environment/cmake/cve_check.cmake @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# CVE Check requirements +# +# - A working installation of intels cve-bin-tool [1] has to be available in +# your path +# +# - Not strictly required, but highly recommended is obtaining a NVD key from +# nist since it significantly speeds up downloading/updating the required +# databases one can request a key on the following website: +# https://nvd.nist.gov/developers/request-an-api-key + +# Bill of Materials construction +# +# This constructs a CSV cve-bin-tool [1] can read and process. Sadly +# cve-bin-tool at this point does not take a list of CPE's and output a check +# based on that list. so we need to pick apart the CPE retrieve the vendor, +# product and version tokens and generate a CSV. +# +# [1] https://github.com/intel/cve-bin-tool + +# Because not all deps are downloaded (ie python packages) but can still have a +# xxx_CPE declared loop over all variables and look for variables ending in CPE. + +set(SBOMCONTENTS) +get_cmake_property(_variableNames VARIABLES) +foreach (_variableName ${_variableNames}) + if(_variableName MATCHES "CPE$") + string(REPLACE ":" ";" CPE_LIST ${${_variableName}}) + list(GET CPE_LIST 3 CPE_VENDOR) + list(GET CPE_LIST 4 CPE_NAME) + list(GET CPE_LIST 5 CPE_VERSION) + set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}\n") + endif() +endforeach() +configure_file(${CMAKE_SOURCE_DIR}/cmake/cve_check.csv.in ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv @ONLY) + +# Custom Targets +# +# This defines two new custom targets one could run in the build folder +# `cve_check` which will output the report to the console, and `cve_check_html` +# which will write out blender_dependencies.html in the build folder that one +# could share with other people or be used to get more information on the +# reported CVE's. +# +# cve-bin-tool takes data from the nist nvd database which rate limits +# unauthenticated requests to 1 requests per 6 seconds making the database +# download take "quite a bit" of time. +# +# When adding -DCVE_CHECK_NVD_KEY=your_api_key_here to your cmake invocation +# this key will be passed on to cve-bin-tool speeding up the process. +# +if(DEFINED CVE_CHECK_NVD_KEY) + set(NVD_ARGS --nvd-api-key ${CVE_CHECK_NVD_KEY}) +endif() + +# This will just report to the console +add_custom_target(cve_check + COMMAND cve-bin-tool + ${NVD_ARGS} + -i ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv + --affected-versions + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv +) + +# This will write out blender_dependencies.html +add_custom_target(cve_check_html + COMMAND cve-bin-tool + ${NVD_ARGS} + -i ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv + -f html + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv +) diff --git a/build_files/build_environment/cmake/cve_check.csv.in b/build_files/build_environment/cmake/cve_check.csv.in new file mode 100644 index 00000000000..6e7e8db5609 --- /dev/null +++ b/build_files/build_environment/cmake/cve_check.csv.in @@ -0,0 +1,2 @@ +vendor,product,version +@SBOMCONTENTS@ diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake index 7c91fe5455e..35bc028a1e3 100644 --- a/build_files/build_environment/cmake/download.cmake +++ b/build_files/build_environment/cmake/download.cmake @@ -133,6 +133,7 @@ download_source(NASM) download_source(XR_OPENXR_SDK) download_source(WL_PROTOCOLS) download_source(WAYLAND) +download_source(WAYLAND_LIBDECOR) download_source(ISPC) download_source(GMP) download_source(POTRACE) diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake index 6c920e651fe..9afc1974677 100644 --- a/build_files/build_environment/cmake/harvest.cmake +++ b/build_files/build_environment/cmake/harvest.cmake @@ -118,6 +118,8 @@ else() harvest(wayland-protocols/share/wayland-protocols wayland-protocols/share/wayland-protocols/ "*.xml") harvest(wayland/bin wayland/bin "wayland-scanner") + harvest(wayland/include wayland/include "*.h") + harvest(wayland_libdecor/include wayland_libdecor/include "*.h") else() harvest(blosc/lib openvdb/lib "*.a") harvest(xml2/lib opencollada/lib "*.a") diff --git a/build_files/build_environment/cmake/openpgl.cmake b/build_files/build_environment/cmake/openpgl.cmake index e6b0cd8eb4a..b41264ac22b 100644 --- a/build_files/build_environment/cmake/openpgl.cmake +++ b/build_files/build_environment/cmake/openpgl.cmake @@ -4,11 +4,9 @@ # library itself does not depend on them, so should give no problems. set(OPENPGL_EXTRA_ARGS - -DOPENPGL_BUILD_PYTHON=OFF -DOPENPGL_BUILD_STATIC=ON -DOPENPGL_TBB_ROOT=${LIBDIR}/tbb -DTBB_ROOT=${LIBDIR}/tbb - -Dembree_DIR=${LIBDIR}/embree/lib/cmake/embree-${EMBREE_VERSION} -DCMAKE_DEBUG_POSTFIX=_d ) @@ -31,7 +29,6 @@ ExternalProject_Add(external_openpgl add_dependencies( external_openpgl external_tbb - external_embree ) if(WIN32) @@ -43,6 +40,7 @@ if(WIN32) else() ExternalProject_Add_Step(external_openpgl after_install COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openpgl/lib/openpgl_d.lib ${HARVEST_TARGET}/openpgl/lib/openpgl_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION}/openpgl_Exports-debug.cmake ${HARVEST_TARGET}/openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION}/openpgl_Exports-debug.cmake DEPENDEES install ) endif() diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index 01996efa9bd..bfc6d27f74d 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -1,10 +1,19 @@ # SPDX-License-Identifier: GPL-2.0-or-later +# CPE's are used to identify dependencies, for more information on what they +# are please see https://nvd.nist.gov/products/cpe +# +# We use them in combination with cve-bin-tool to scan for known security issues. +# +# Not all of our dependencies are currently in the nvd database so not all +# dependencies have one assigned. + set(ZLIB_VERSION 1.2.12) set(ZLIB_URI https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz) set(ZLIB_HASH 5fc414a9726be31427b440b434d05f78) set(ZLIB_HASH_TYPE MD5) set(ZLIB_FILE zlib-${ZLIB_VERSION}.tar.gz) +set(ZLIB_CPE "cpe:2.3:a:zlib:zlib:${ZLIB_VERSION}:*:*:*:*:*:*:*") set(OPENAL_VERSION 1.21.1) set(OPENAL_URI http://openal-soft.org/openal-releases/openal-soft-${OPENAL_VERSION}.tar.bz2) @@ -17,12 +26,14 @@ set(PNG_URI http://prdownloads.sourceforge.net/libpng/libpng-${PNG_VERSION}.tar. set(PNG_HASH 505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca) set(PNG_HASH_TYPE SHA256) set(PNG_FILE libpng-${PNG_VERSION}.tar.xz) +set(PNG_CPE "cpe:2.3:a:libpng:libpng:${PNG_VERSION}:*:*:*:*:*:*:*") set(JPEG_VERSION 2.1.3) set(JPEG_URI https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${JPEG_VERSION}.tar.gz) set(JPEG_HASH 627b980fad0573e08e4c3b80b290fc91) set(JPEG_HASH_TYPE MD5) set(JPEG_FILE libjpeg-turbo-${JPEG_VERSION}.tar.gz) +set(JPEG_CPE "cpe:2.3:a:d.r.commander:libjpeg-turbo:${JPEG_VERSION}:*:*:*:*:*:*:*") set(BOOST_VERSION 1.78.0) set(BOOST_VERSION_SHORT 1.78) @@ -32,12 +43,14 @@ set(BOOST_URI https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION set(BOOST_HASH c2f6428ac52b0e5a3c9b2e1d8cc832b5) set(BOOST_HASH_TYPE MD5) set(BOOST_FILE boost_${BOOST_VERSION_NODOTS}.tar.gz) +set(BOOST_CPE "cpe:2.3:a:boost:boost:${BOOST_VERSION}:*:*:*:*:*:*:*") set(BLOSC_VERSION 1.21.1) set(BLOSC_URI https://github.com/Blosc/c-blosc/archive/v${BLOSC_VERSION}.tar.gz) set(BLOSC_HASH 134b55813b1dca57019d2a2dc1f7a923) set(BLOSC_HASH_TYPE MD5) set(BLOSC_FILE blosc-${BLOSC_VERSION}.tar.gz) +set(BLOSC_CPE "cpe:2.3:a:c-blosc2_project:c-blosc2:${BLOSC_VERSION}:*:*:*:*:*:*:*") set(PTHREADS_VERSION 3.0.0) set(PTHREADS_URI http://prdownloads.sourceforge.net/pthreads4w/pthreads4w-code-v${PTHREADS_VERSION}.zip) @@ -50,6 +63,7 @@ set(OPENEXR_URI https://github.com/AcademySoftwareFoundation/openexr/archive/v${ set(OPENEXR_HASH a92f38eedd43e56c0af56d4852506886) set(OPENEXR_HASH_TYPE MD5) set(OPENEXR_FILE openexr-${OPENEXR_VERSION}.tar.gz) +set(OPENEXR_CPE "cpe:2.3:a:openexr:openexr:${OPENEXR_VERSION}:*:*:*:*:*:*:*") set(IMATH_VERSION 3.1.5) set(IMATH_URI https://github.com/AcademySoftwareFoundation/Imath/archive/v${OPENEXR_VERSION}.tar.gz) @@ -79,6 +93,7 @@ set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE set(FREETYPE_HASH bd4e3b007474319909a6b79d50908e85) set(FREETYPE_HASH_TYPE MD5) set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz) +SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*") set(EPOXY_VERSION 1.5.10) set(EPOXY_URI https://github.com/anholt/libepoxy/archive/refs/tags/${EPOXY_VERSION}.tar.gz) @@ -97,6 +112,7 @@ set(ALEMBIC_URI https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.ta set(ALEMBIC_HASH 2cd8d6e5a3ac4a014e24a4b04f4fadf9) set(ALEMBIC_HASH_TYPE MD5) set(ALEMBIC_FILE alembic-${ALEMBIC_VERSION}.tar.gz) +SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*") set(OPENSUBDIV_VERSION v3_4_4) set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.tar.gz) @@ -109,6 +125,7 @@ set(SDL_URI https://www.libsdl.org/release/SDL2-${SDL_VERSION}.tar.gz) set(SDL_HASH a53acc02e1cca98c4123229069b67c9e) set(SDL_HASH_TYPE MD5) set(SDL_FILE SDL2-${SDL_VERSION}.tar.gz) +set(SDL_CPE "cpe:2.3:a:libsdl:sdl:${SDL_VERSION}:*:*:*:*:*:*:*") set(OPENCOLLADA_VERSION v1.6.68) set(OPENCOLLADA_URI https://github.com/KhronosGroup/OpenCOLLADA/archive/${OPENCOLLADA_VERSION}.tar.gz) @@ -127,6 +144,7 @@ set(LLVM_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LL set(LLVM_HASH 5a4fab4d7fc84aefffb118ac2c8a4fc0) set(LLVM_HASH_TYPE MD5) set(LLVM_FILE llvm-project-${LLVM_VERSION}.src.tar.xz) +set(LLVM_CPE "cpe:2.3:a:llvm:compiler:${LLVM_VERSION}:*:*:*:*:*:*:*") if(APPLE) # Cloth physics test is crashing due to this bug: @@ -154,6 +172,7 @@ set(FMT_URI https://github.com/fmtlib/fmt/archive/refs/tags/${FMT_VERSION}.tar.g set(FMT_HASH 7bce0e9e022e586b178b150002e7c2339994e3c2bbe44027e9abb0d60f9cce83) set(FMT_HASH_TYPE SHA256) set(FMT_FILE fmt-${FMT_VERSION}.tar.gz) +set(FMT_CPE "cpe:2.3:a:fmt:fmt:${FMT_VERSION}:*:*:*:*:*:*:*") # 0.6.2 is currently oiio's preferred version although never versions may be available. # the preferred version can be found in oiio's externalpackages.cmake @@ -168,6 +187,7 @@ set(TIFF_URI http://download.osgeo.org/libtiff/tiff-${TIFF_VERSION}.tar.gz) set(TIFF_HASH 376f17f189e9d02280dfe709b2b2bbea) set(TIFF_HASH_TYPE MD5) set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz) +set(TIFF_CPE "cpe:2.3:a:libtiff:libtiff:${TIFF_VERSION}:*:*:*:*:*:*:*") set(OSL_VERSION 1.11.17.0) set(OSL_URI https://github.com/imageworks/OpenShadingLanguage/archive/Release-${OSL_VERSION}.tar.gz) @@ -182,12 +202,15 @@ set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTH set(PYTHON_HASH 14e8c22458ed7779a1957b26cde01db9) set(PYTHON_HASH_TYPE MD5) set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz) +set(PYTHON_CPE "cpe:2.3:a:python:python:${PYTHON_VERSION}:-:*:*:*:*:*:*") -set(TBB_VERSION 2020_U3) +set(TBB_YEAR 2020) +set(TBB_VERSION ${TBB_YEAR}_U3) set(TBB_URI https://github.com/oneapi-src/oneTBB/archive/${TBB_VERSION}.tar.gz) set(TBB_HASH 55ec8df6eae5ed6364a47f0e671e460c) set(TBB_HASH_TYPE MD5) set(TBB_FILE oneTBB-${TBB_VERSION}.tar.gz) +set(TBB_CPE "cpe:2.3:a:intel:threading_building_blocks:${TBB_YEAR}:*:*:*:*:*:*:*") set(OPENVDB_VERSION 9.0.0) set(OPENVDB_URI https://github.com/AcademySoftwareFoundation/openvdb/archive/v${OPENVDB_VERSION}.tar.gz) @@ -198,6 +221,7 @@ set(OPENVDB_FILE openvdb-${OPENVDB_VERSION}.tar.gz) set(IDNA_VERSION 3.3) set(CHARSET_NORMALIZER_VERSION 2.0.10) set(URLLIB3_VERSION 1.26.8) +set(URLLIB3_CPE "cpe:2.3:a:urllib3:urllib3:${URLLIB3_VERSION}:*:*:*:*:*:*:*") set(CERTIFI_VERSION 2021.10.8) set(REQUESTS_VERSION 2.27.1) set(CYTHON_VERSION 0.29.26) @@ -214,12 +238,14 @@ set(NUMPY_URI https://github.com/numpy/numpy/releases/download/v${NUMPY_VERSION} set(NUMPY_HASH 252de134862a27bd66705d29622edbfe) set(NUMPY_HASH_TYPE MD5) set(NUMPY_FILE numpy-${NUMPY_VERSION}.zip) +set(NUMPY_CPE "cpe:2.3:a:numpy:numpy:${NUMPY_VERSION}:*:*:*:*:*:*:*") set(LAME_VERSION 3.100) set(LAME_URI http://downloads.sourceforge.net/project/lame/lame/3.100/lame-${LAME_VERSION}.tar.gz) set(LAME_HASH 83e260acbe4389b54fe08e0bdbf7cddb) set(LAME_HASH_TYPE MD5) set(LAME_FILE lame-${LAME_VERSION}.tar.gz) +set(LAME_CPE "cpe:2.3:a:lame_project:lame:${LAME_VERSION}:*:*:*:*:*:*:*") set(OGG_VERSION 1.3.5) set(OGG_URI http://downloads.xiph.org/releases/ogg/libogg-${OGG_VERSION}.tar.gz) @@ -232,6 +258,7 @@ set(VORBIS_URI http://downloads.xiph.org/releases/vorbis/libvorbis-${VORBIS_VERS set(VORBIS_HASH 0e982409a9c3fc82ee06e08205b1355e5c6aa4c36bca58146ef399621b0ce5ab) set(VORBIS_HASH_TYPE SHA256) set(VORBIS_FILE libvorbis-${VORBIS_VERSION}.tar.gz) +set(VORBIS_CPE "cpe:2.3:a:xiph.org:libvorbis:${VORBIS_VERSION}:*:*:*:*:*:*:*") set(THEORA_VERSION 1.1.1) set(THEORA_URI http://downloads.xiph.org/releases/theora/libtheora-${THEORA_VERSION}.tar.bz2) @@ -244,12 +271,14 @@ set(FLAC_URI http://downloads.xiph.org/releases/flac/flac-${FLAC_VERSION}.tar.xz set(FLAC_HASH 8ff0607e75a322dd7cd6ec48f4f225471404ae2730d0ea945127b1355155e737 ) set(FLAC_HASH_TYPE SHA256) set(FLAC_FILE flac-${FLAC_VERSION}.tar.xz) +set(FLAC_CPE "cpe:2.3:a:flac_project:flac:${FLAC_VERSION}:*:*:*:*:*:*:*") set(VPX_VERSION 1.11.0) set(VPX_URI https://github.com/webmproject/libvpx/archive/v${VPX_VERSION}/libvpx-v${VPX_VERSION}.tar.gz) set(VPX_HASH 965e51c91ad9851e2337aebcc0f517440c637c506f3a03948062e3d5ea129a83) set(VPX_HASH_TYPE SHA256) set(VPX_FILE libvpx-v${VPX_VERSION}.tar.gz) +set(VPX_CPE "cpe:2.3:a:webmproject:libvpx:${VPX_VERSION}:*:*:*:*:*:*:*") set(OPUS_VERSION 1.3.1) set(OPUS_URI https://archive.mozilla.org/pub/opus/opus-${OPUS_VERSION}.tar.gz) @@ -275,12 +304,14 @@ set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSI set(OPENJPEG_HASH 8702ba68b442657f11aaeb2b338443ca8d5fb95b0d845757968a7be31ef7f16d) set(OPENJPEG_HASH_TYPE SHA256) set(OPENJPEG_FILE openjpeg-v${OPENJPEG_VERSION}.tar.gz) +set(OPENJPEG_CPE "cpe:2.3:a:uclouvain:openjpeg:${OPENJPEG_VERSION}:*:*:*:*:*:*:*") set(FFMPEG_VERSION 5.0) set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2) set(FFMPEG_HASH c0130b8db2c763430fd1c6905288d61bc44ee0548ad5fcd2dfd650b88432bed9) set(FFMPEG_HASH_TYPE SHA256) set(FFMPEG_FILE ffmpeg-${FFMPEG_VERSION}.tar.bz2) +set(FFMPEG_CPE "cpe:2.3:a:ffmpeg:ffmpeg:${FFMPEG_VERSION}:*:*:*:*:*:*:*") set(FFTW_VERSION 3.3.10) set(FFTW_URI http://www.fftw.org/fftw-${FFTW_VERSION}.tar.gz) @@ -299,12 +330,14 @@ set(SNDFILE_URI http://www.mega-nerd.com/libsndfile/files/libsndfile-${SNDFILE_V set(SNDFILE_HASH 646b5f98ce89ac60cdb060fcd398247c) set(SNDFILE_HASH_TYPE MD5) set(SNDFILE_FILE libsndfile-${SNDFILE_VERSION}.tar.gz) +set(SNDFILE_CPE "cpe:2.3:a:libsndfile_project:libsndfile:${SNDFILE_VERSION}:*:*:*:*:*:*:*") set(WEBP_VERSION 1.2.2) set(WEBP_URI https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${WEBP_VERSION}.tar.gz) set(WEBP_HASH b5e2e414a8adee4c25fe56b18dd9c549) set(WEBP_HASH_TYPE MD5) set(WEBP_FILE libwebp-${WEBP_VERSION}.tar.gz) +set(WEBP_CPE "cpe:2.3:a:webmproject:libwebp:${WEBP_VERSION}:*:*:*:*:*:*:*") set(SPNAV_VERSION 0.2.3) set(SPNAV_URI http://downloads.sourceforge.net/project/spacenav/spacenav%20library%20%28SDK%29/libspnav%20${SPNAV_VERSION}/libspnav-${SPNAV_VERSION}.tar.gz) @@ -323,6 +356,7 @@ set(XML2_URI http://xmlsoft.org/sources/libxml2-${XML2_VERSION}.tar.gz) set(XML2_HASH 10942a1dc23137a8aa07f0639cbfece5) set(XML2_HASH_TYPE MD5) set(XML2_FILE libxml2-${XML2_VERSION}.tar.gz) +set(XML2_CPE "cpe:2.3:a:xmlsoft:libxml2:${XML2_VERSION}:*:*:*:*:*:*:*") set(TINYXML_VERSION 2_6_2) set(TINYXML_VERSION_DOTS 2.6.2) @@ -330,12 +364,14 @@ set(TINYXML_URI https://nchc.dl.sourceforge.net/project/tinyxml/tinyxml/${TINYXM set(TINYXML_HASH c1b864c96804a10526540c664ade67f0) set(TINYXML_HASH_TYPE MD5) set(TINYXML_FILE tinyxml_${TINYXML_VERSION}.tar.gz) +set(TINYXML_CPE "cpe:2.3:a:tinyxml_project:tinyxml:${TINYXML_VERSION_DOTS}:*:*:*:*:*:*:*") set(YAMLCPP_VERSION 0.6.3) set(YAMLCPP_URI https://codeload.github.com/jbeder/yaml-cpp/tar.gz/yaml-cpp-${YAMLCPP_VERSION}) set(YAMLCPP_HASH b45bf1089a382e81f6b661062c10d0c2) set(YAMLCPP_HASH_TYPE MD5) set(YAMLCPP_FILE yaml-cpp-${YAMLCPP_VERSION}.tar.gz) +set(YAMLCPP "cpe:2.3:a:yaml-cpp_project:yaml-cpp:${YAMLCPP_VERSION}:*:*:*:*:*:*:*") set(PYSTRING_VERSION v1.1.3) set(PYSTRING_URI https://codeload.github.com/imageworks/pystring/tar.gz/refs/tags/${PYSTRING_VERSION}) @@ -344,16 +380,19 @@ set(PYSTRING_HASH_TYPE MD5) set(PYSTRING_FILE pystring-${PYSTRING_VERSION}.tar.gz) set(EXPAT_VERSION 2_4_4) +set(EXPAT_VERSION_DOTS 2.4.4) set(EXPAT_URI https://github.com/libexpat/libexpat/archive/R_${EXPAT_VERSION}.tar.gz) set(EXPAT_HASH 2d3e81dee94b452369dc6394ff0f8f98) set(EXPAT_HASH_TYPE MD5) set(EXPAT_FILE libexpat-${EXPAT_VERSION}.tar.gz) +set(EXPAT_CPE "cpe:2.3:a:libexpat_project:libexpat:${EXPAT_VERSION_DOTS}:*:*:*:*:*:*:*") set(PUGIXML_VERSION 1.10) set(PUGIXML_URI https://github.com/zeux/pugixml/archive/v${PUGIXML_VERSION}.tar.gz) set(PUGIXML_HASH 0c208b0664c7fb822bf1b49ad035e8fd) set(PUGIXML_HASH_TYPE MD5) set(PUGIXML_FILE pugixml-${PUGIXML_VERSION}.tar.gz) +set(PUGIXML_CPE "cpe:2.3:a:pugixml_project:pugixml:${PUGIXML_VERSION}:*:*:*:*:*:*:*") set(FLEXBISON_VERSION 2.5.24) set(FLEXBISON_URI http://prdownloads.sourceforge.net/winflexbison/win_flex_bison-${FLEXBISON_VERSION}.zip) @@ -376,12 +415,14 @@ set(BZIP2_URI http://http.debian.net/debian/pool/main/b/bzip2/bzip2_${BZIP2_VERS set(BZIP2_HASH ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269) set(BZIP2_HASH_TYPE SHA256) set(BZIP2_FILE bzip2_${BZIP2_VERSION}.orig.tar.gz) +set(BZIP2_CPE "cpe:2.3:a:bzip:bzip2:${BZIP2_VERSION}:*:*:*:*:*:*:*") set(FFI_VERSION 3.3) set(FFI_URI https://sourceware.org/pub/libffi/libffi-${FFI_VERSION}.tar.gz) set(FFI_HASH 72fba7922703ddfa7a028d513ac15a85c8d54c8d67f55fa5a4802885dc652056) set(FFI_HASH_TYPE SHA256) set(FFI_FILE libffi-${FFI_VERSION}.tar.gz) +set(FFI_CPE "cpe:2.3:a:libffi_project:libffi:${FFI_VERSION}:*:*:*:*:*:*:*") set(LZMA_VERSION 5.2.5) set(LZMA_URI https://tukaani.org/xz/xz-${LZMA_VERSION}.tar.bz2) @@ -403,12 +444,14 @@ else() set(SSL_HASH_TYPE SHA256) set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) endif() +set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*") set(SQLITE_VERSION 3.31.1) set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip) set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7) set(SQLITE_HASH_TYPE SHA1) set(SQLITE_FILE sqlite-src-3240000.zip) +set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*") set(EMBREE_VERSION 3.13.4) set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip) @@ -439,12 +482,14 @@ set(MESA_URI ftp://ftp.freedesktop.org/pub/mesa/mesa-${MESA_VERSION}.tar.xz) set(MESA_HASH 022c7293074aeeced2278c872db4fa693147c70f8595b076cf3f1ef81520766d) set(MESA_HASH_TYPE SHA256) set(MESA_FILE mesa-${MESA_VERSION}.tar.xz) +set(MESA_CPE "cpe:2.3:a:mesa3d:mesa:${MESA_VERSION}:*:*:*:*:*:*:*") set(NASM_VERSION 2.15.02) set(NASM_URI https://github.com/netwide-assembler/nasm/archive/nasm-${NASM_VERSION}.tar.gz) set(NASM_HASH aded8b796c996a486a56e0515c83e414116decc3b184d88043480b32eb0a8589) set(NASM_HASH_TYPE SHA256) set(NASM_FILE nasm-${NASM_VERSION}.tar.gz) +set(NASM_PCE "cpe:2.3:a:nasm:nasm:${NASM_VERSION}:*:*:*:*:*:*:*") set(XR_OPENXR_SDK_VERSION 1.0.22) set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz) @@ -464,6 +509,12 @@ set(WAYLAND_URI https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.21.0 set(WAYLAND_HASH f2653a2293bcd882d756c6a83d278903) set(WAYLAND_HASH_TYPE MD5) +set(WAYLAND_LIBDECOR_VERSION 0.1.0) +set(WAYLAND_LIBDECOR_FILE libdecor-${WAYLAND_LIBDECOR_VERSION}.tar.xz) +set(WAYLAND_LIBDECOR_URI https://gitlab.gnome.org/jadahl/libdecor/uploads/81adf91d27620e20bcc5f6b9b312d768/libdecor-${WAYLAND_LIBDECOR_VERSION}.tar.xz ) +set(WAYLAND_LIBDECOR_HASH 47b59eba76faa3787f0878bf8700e912) +set(WAYLAND_LIBDECOR_HASH_TYPE MD5) + set(ISPC_VERSION v1.17.0) set(ISPC_URI https://github.com/ispc/ispc/archive/${ISPC_VERSION}.tar.gz) set(ISPC_HASH 4f476a3109332a77fe839a9014c60ca9) @@ -475,12 +526,14 @@ set(GMP_URI https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.xz) set(GMP_HASH 0b82665c4a92fd2ade7440c13fcaa42b) set(GMP_HASH_TYPE MD5) set(GMP_FILE gmp-${GMP_VERSION}.tar.xz) +set(GMP_CPE "cpe:2.3:a:gmplib:gmp:${GMP_VERSION}:*:*:*:*:*:*:*") set(POTRACE_VERSION 1.16) set(POTRACE_URI http://potrace.sourceforge.net/download/${POTRACE_VERSION}/potrace-${POTRACE_VERSION}.tar.gz) set(POTRACE_HASH 5f0bd87ddd9a620b0c4e65652ef93d69) set(POTRACE_HASH_TYPE MD5) set(POTRACE_FILE potrace-${POTRACE_VERSION}.tar.gz) +set(POTRACE_CPE "cpe:2.3:a:icoasoft:potrace:${POTRACE_VERSION}:*:*:*:*:*:*:*") set(HARU_VERSION 2_3_0) set(HARU_URI https://github.com/libharu/libharu/archive/RELEASE_${HARU_VERSION}.tar.gz) @@ -493,6 +546,7 @@ set(ZSTD_URI https://github.com/facebook/zstd/releases/download/v${ZSTD_VERSION} set(ZSTD_HASH 5194fbfa781fcf45b98c5e849651aa7b3b0a008c6b72d4a0db760f3002291e94) set(ZSTD_HASH_TYPE SHA256) set(ZSTD_FILE zstd-${ZSTD_VERSION}.tar.gz) +set(ZSTD_CPE "cpe:2.3:a:facebook:zstandard:${ZSTD_VERSION}:*:*:*:*:*:*:*") set(SSE2NEON_VERSION fe5ff00bb8d19b327714a3c290f3e2ce81ba3525) set(SSE2NEON_URI https://github.com/DLTcollab/sse2neon/archive/${SSE2NEON_VERSION}.tar.gz) @@ -500,16 +554,17 @@ set(SSE2NEON_HASH 0780253525d299c31775ef95853698d03db9c7739942af8570000f4a25a5d6 set(SSE2NEON_HASH_TYPE SHA256) set(SSE2NEON_FILE sse2neon-${SSE2NEON_VERSION}.tar.gz) -set(BROTLI_VERSION v1.0.9) -set(BROTLI_URI https://github.com/google/brotli/archive/refs/tags/${BROTLI_VERSION}.tar.gz) +set(BROTLI_VERSION 1.0.9) +set(BROTLI_URI https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz) set(BROTLI_HASH f9e8d81d0405ba66d181529af42a3354f838c939095ff99930da6aa9cdf6fe46) set(BROTLI_HASH_TYPE SHA256) -set(BROTLI_FILE brotli-${BROTLI_VERSION}.tar.gz) +set(BROTLI_FILE brotli-v${BROTLI_VERSION}.tar.gz) +set(BROTLI_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*") -set(OPENPGL_VERSION v0.3.1-beta) -set(OPENPGL_SHORT_VERSION 0.3.1) +set(OPENPGL_VERSION v0.4.0-beta) +set(OPENPGL_SHORT_VERSION 0.4.0) set(OPENPGL_URI https://github.com/OpenPathGuidingLibrary/openpgl/archive/refs/tags/${OPENPGL_VERSION}.tar.gz) -set(OPENPGL_HASH 3830098c485c962018932766199527aab453a8029528dbbc04d4454d82431e2c) +set(OPENPGL_HASH 58d5b65c533ce6cac3f7e1d51cf169a5411adf356abcd85f04049bbcaecc2e77) set(OPENPGL_HASH_TYPE SHA256) set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz) diff --git a/build_files/build_environment/cmake/wayland.cmake b/build_files/build_environment/cmake/wayland.cmake index 29859cc9ba5..799f2513da9 100644 --- a/build_files/build_environment/cmake/wayland.cmake +++ b/build_files/build_environment/cmake/wayland.cmake @@ -6,9 +6,11 @@ ExternalProject_Add(external_wayland URL_HASH ${WAYLAND_HASH_TYPE}=${WAYLAND_HASH} PREFIX ${BUILD_DIR}/wayland PATCH_COMMAND ${PATCH_CMD} -d ${BUILD_DIR}/wayland/src/external_wayland < ${PATCH_DIR}/wayland.diff - # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT. - CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:$PKG_CONFIG_PATH - meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -Dlibraries=false . ../external_wayland + # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT & LIBXML2. + # Note that passing link args "ffi/lib" should not be needed, but + # `pkgconfig` would incorrectly look in "ffi/lib/../lib64" otherwise. + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:${LIBDIR}/ffi/lib/pkgconfig:$PKG_CONFIG_PATH + meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -Dc_link_args=-L${LIBDIR}/ffi/lib . ../external_wayland BUILD_COMMAND ninja INSTALL_COMMAND ninja install ) @@ -17,4 +19,5 @@ add_dependencies( external_wayland external_expat external_xml2 + external_ffi ) diff --git a/build_files/build_environment/cmake/wayland_libdecor.cmake b/build_files/build_environment/cmake/wayland_libdecor.cmake new file mode 100644 index 00000000000..f4628fa3a1b --- /dev/null +++ b/build_files/build_environment/cmake/wayland_libdecor.cmake @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# NOTE: currently only the header file is extracted, no compilation is needed +# as the library is dynamically loaded when found on the system. + +ExternalProject_Add(external_wayland_libdecor + URL file://${PACKAGE_DIR}/${WAYLAND_LIBDECOR_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${WAYLAND_LIBDECOR_HASH_TYPE}=${WAYLAND_LIBDECOR_HASH} + PREFIX ${BUILD_DIR}/wayland_libdecor + BUILD_COMMAND echo . + CONFIGURE_COMMAND echo . + INSTALL_COMMAND cp ../external_wayland_libdecor/src/libdecor.h ${LIBDIR}/wayland_libdecor/include/libdecor-0/libdecor.h + INSTALL_DIR ${LIBDIR}/wayland_libdecor/include/libdecor-0 +) diff --git a/build_files/build_environment/cmake/wayland_protocols.cmake b/build_files/build_environment/cmake/wayland_protocols.cmake index 23d29b49260..9bdbc38fd6c 100644 --- a/build_files/build_environment/cmake/wayland_protocols.cmake +++ b/build_files/build_environment/cmake/wayland_protocols.cmake @@ -5,7 +5,14 @@ ExternalProject_Add(external_wayland_protocols DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${WL_PROTOCOLS_HASH_TYPE}=${WL_PROTOCOLS_HASH} PREFIX ${BUILD_DIR}/wayland-protocols - CONFIGURE_COMMAND meson --prefix ${LIBDIR}/wayland-protocols . ../external_wayland_protocols -Dtests=false + # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own WAYLAND. + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/wayland/lib64/pkgconfig:$PKG_CONFIG_PATH + meson --prefix ${LIBDIR}/wayland-protocols . ../external_wayland_protocols -Dtests=false BUILD_COMMAND ninja INSTALL_COMMAND ninja install ) + +add_dependencies( + external_wayland_protocols + external_wayland +) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 5de0547727d..f913ac5e73c 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -1222,7 +1222,7 @@ Those libraries should be available as packages in all recent distributions (opt * Basics of dev environment (cmake, gcc, svn , git, ...). * libjpeg, libpng, libtiff, [openjpeg2], [libopenal]. * libx11, libxcursor, libxi, libxrandr, libxinerama (and other libx... as needed). - * libwayland-client0, libwayland-cursor0, libwayland-egl1, libxkbcommon0, libdbus-1-3, libegl1 (Wayland) + * libwayland-client0, libdecor, libwayland-cursor0, libwayland-egl1, libxkbcommon0, libdbus-1-3, libegl1 (Wayland) * libsqlite3, libzstd, libbz2, libssl, libfftw3, libxml2, libtinyxml, yasm, libyaml-cpp, flex. * libsdl2, libepoxy, libpugixml, libpotrace, [libgmp], fontconfig, [libharu/libhpdf].\"" @@ -4205,7 +4205,7 @@ install_DEB() { _packages="gawk cmake cmake-curses-gui build-essential libjpeg-dev libpng-dev libtiff-dev \ git libfreetype6-dev libfontconfig-dev libx11-dev flex bison libxxf86vm-dev \ libxcursor-dev libxi-dev wget libsqlite3-dev libxrandr-dev libxinerama-dev \ - libwayland-dev wayland-protocols libegl-dev libxkbcommon-dev libdbus-1-dev linux-libc-dev \ + libwayland-dev libdecor-0-dev wayland-protocols libegl-dev libxkbcommon-dev libdbus-1-dev linux-libc-dev \ libbz2-dev libncurses5-dev libssl-dev liblzma-dev libreadline-dev \ libopenal-dev libepoxy-dev yasm \ libsdl2-dev libfftw3-dev patch bzip2 libxml2-dev libtinyxml-dev libjemalloc-dev \ @@ -4928,7 +4928,7 @@ install_RPM() { _packages="gcc gcc-c++ git make cmake tar bzip2 xz findutils flex bison fontconfig-devel \ libtiff-devel libjpeg-devel libpng-devel sqlite-devel fftw-devel SDL2-devel \ libX11-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel \ - wayland-devel wayland-protocols-devel mesa-libEGL-devel libxkbcommon-devel dbus-devel kernel-headers \ + wayland-devel libdecor-devel wayland-protocols-devel mesa-libEGL-devel libxkbcommon-devel dbus-devel kernel-headers \ wget ncurses-devel readline-devel $OPENJPEG_DEV openal-soft-devel \ libepoxy-devel yasm patch \ libxml2-devel yaml-cpp-devel tinyxml-devel jemalloc-devel \ @@ -5582,7 +5582,7 @@ install_ARCH() { fi _packages="$BASE_DEVEL git cmake fontconfig flex \ - libxi libxcursor libxrandr libxinerama libepoxy libpng libtiff wget openal \ + libxi libxcursor libxrandr libxinerama libepoxy libdecor libpng libtiff wget openal \ $OPENJPEG_DEV yasm sdl2 fftw \ libxml2 yaml-cpp tinyxml python-requests jemalloc gmp potrace pugixml libharu \ zstd pystring" diff --git a/build_files/build_environment/linux/linux-centos7-setup.sh b/build_files/build_environment/linux/linux-centos7-setup.sh index 84c14a1d2be..e664f530edb 100644 --- a/build_files/build_environment/linux/linux-centos7-setup.sh +++ b/build_files/build_environment/linux/linux-centos7-setup.sh @@ -1,4 +1,8 @@ -#!/bin/sh +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0-or-later + +# This script is part of the official build environment, see WIKI page for details. +# https://wiki.blender.org/wiki/Building_Blender/Other/CentOS7ReleaseEnvironment set -e @@ -22,18 +26,79 @@ yum -y install centos-release-scl yum -y install devtoolset-9 # Install packages needed for Blender's dependencies. -yum -y install -y \ - git subversion bzip2 tar cmake3 patch make autoconf automake libtool \ - meson ninja-build \ - libXrandr-devel libXinerama-devel libXcursor-devel libXi-devel \ - libX11-devel libXt-devel \ - mesa-libEGL-devel mesa-libGL-devel mesa-libGLU-devel \ - zlib-devel \ - rubygem-asciidoctor \ - wget tcl yasm python36 python-setuptools bison flex \ - ncurses-devel \ - wayland-devel libwayland-client libwayland-server \ +PACKAGES_FOR_LIBS=( + # Used to checkout Blender's code. + git + # Used to checkout Blender's `../lib/` directory. + subversion + # Used to extract packages. + bzip2 + # Used to extract packages. + tar + # Blender and some dependencies use `cmake`. + cmake3 + # Apply patches from Blender's: `./build_files/build_environment/patches` + patch + # Use by `cmake` and `autoconf`. + make + + # Required by: `external_nasm` which uses an `autoconf` build-system. + autoconf + automake + libtool + + # Meta-build system used by various packages. + meson + # Builds generated by meson use Ninja for the actual build. + ninja-build + + # Required by Blender build option: `WITH_GHOST_X11`. + libXrandr-devel + libXinerama-devel + libXcursor-devel + libXi-devel + libX11-devel + libXt-devel + + # Required by Blender build option: `WITH_GHOST_WAYLAND`. + mesa-libEGL-devel + # Required by: Blender & `external_opensubdiv` (probably others). + mesa-libGL-devel + mesa-libGLU-devel + + # Required by: `external_ispc`. + zlib-devel + # TODO: dependencies build without this, consider removal. + rubygem-asciidoctor + # TODO: dependencies build without this, consider removal. + wget + # Required by: `external_sqlite` as a build-time dependency (needed for the `tclsh` command). + tcl + # Required by: `external_aom`. + # TODO: Blender is already building `external_nasm` which is listed as an alternative to `yasm`. + # Why are both needed? + yasm + + # Required by: `meson` (Python based build system). + python36 + # Required by: `mako` (Python module used for building `external_mesa`) + python-setuptools + + # Required by: `external_igc` & `external_osl` as a build-time dependency. + bison + # Required by: `external_osl` as a build-time dependency. + flex + # TODO: dependencies build without this, consider removal. + ncurses-devel +) + +# Additional packages needed for building Blender. +PACKAGES_FOR_BLENDER=( + # Required by Blender build option: `WITH_GHOST_WAYLAND`. + libxkbcommon-devel +) +yum -y install -y ${PACKAGES_FOR_LIBS[@]} ${PACKAGES_FOR_BLENDER[@]} # Dependencies for Mesa yum -y install expat-devel diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 0aab46b1250..7b7937959bf 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -699,14 +699,23 @@ endif() if(WITH_GHOST_WAYLAND) find_package(PkgConfig) - pkg_check_modules(wayland-client wayland-client>=1.12) - pkg_check_modules(wayland-egl wayland-egl) - pkg_check_modules(wayland-scanner wayland-scanner) pkg_check_modules(xkbcommon xkbcommon) - pkg_check_modules(wayland-cursor wayland-cursor) - pkg_check_modules(wayland-protocols wayland-protocols>=1.15) - if(${wayland-protocols_FOUND}) + # When dynamically linked WAYLAND is used and `${LIBDIR}/wayland` is present, + # there is no need to search for the libraries as they are not needed for building. + # Only the headers are needed which can reference the known paths. + if(EXISTS "${LIBDIR}/wayland" AND WITH_GHOST_WAYLAND_DYNLOAD) + set(_use_system_wayland OFF) + else() + set(_use_system_wayland ON) + endif() + + if(_use_system_wayland) + pkg_check_modules(wayland-client wayland-client>=1.12) + pkg_check_modules(wayland-egl wayland-egl) + pkg_check_modules(wayland-scanner wayland-scanner) + pkg_check_modules(wayland-cursor wayland-cursor) + pkg_check_modules(wayland-protocols wayland-protocols>=1.15) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) else() # CentOS 7 packages have too old a version, a newer version exist in the @@ -720,6 +729,15 @@ if(WITH_GHOST_WAYLAND) if(EXISTS ${WAYLAND_PROTOCOLS_DIR}) set(wayland-protocols_FOUND ON) endif() + + set(wayland-client_INCLUDE_DIRS "${LIBDIR}/wayland/include") + set(wayland-egl_INCLUDE_DIRS "${LIBDIR}/wayland/include") + set(wayland-cursor_INCLUDE_DIRS "${LIBDIR}/wayland/include") + + set(wayland-client_FOUND ON) + set(wayland-egl_FOUND ON) + set(wayland-scanner_FOUND ON) + set(wayland-cursor_FOUND ON) endif() if (NOT ${wayland-client_FOUND}) @@ -753,34 +771,18 @@ if(WITH_GHOST_WAYLAND) endif() if(WITH_GHOST_WAYLAND_LIBDECOR) - pkg_check_modules(libdecor REQUIRED libdecor-0>=0.1) - endif() - - list(APPEND PLATFORM_LINKLIBS - ${xkbcommon_LINK_LIBRARIES} - ) - - if(NOT WITH_GHOST_WAYLAND_DYNLOAD) - list(APPEND PLATFORM_LINKLIBS - ${wayland-client_LINK_LIBRARIES} - ${wayland-egl_LINK_LIBRARIES} - ${wayland-cursor_LINK_LIBRARIES} - ) + if(_use_system_wayland) + pkg_check_modules(libdecor REQUIRED libdecor-0>=0.1) + else() + set(libdecor_INCLUDE_DIRS "${LIBDIR}/wayland_libdecor/include/libdecor-0") + endif() endif() if(WITH_GHOST_WAYLAND_DBUS) - list(APPEND PLATFORM_LINKLIBS - ${dbus_LINK_LIBRARIES} - ) add_definitions(-DWITH_GHOST_WAYLAND_DBUS) endif() if(WITH_GHOST_WAYLAND_LIBDECOR) - if(NOT WITH_GHOST_WAYLAND_DYNLOAD) - list(APPEND PLATFORM_LINKLIBS - ${libdecor_LIBRARIES} - ) - endif() add_definitions(-DWITH_GHOST_WAYLAND_LIBDECOR) endif() @@ -823,6 +825,8 @@ if(WITH_GHOST_WAYLAND) # End wayland-scanner version check. endif() + + unset(_use_system_wayland) endif() if(WITH_GHOST_X11) @@ -831,12 +835,8 @@ if(WITH_GHOST_X11) find_path(X11_XF86keysym_INCLUDE_PATH X11/XF86keysym.h ${X11_INC_SEARCH_PATH}) mark_as_advanced(X11_XF86keysym_INCLUDE_PATH) - list(APPEND PLATFORM_LINKLIBS ${X11_X11_LIB}) - if(WITH_X11_XINPUT) - if(X11_Xinput_LIB) - list(APPEND PLATFORM_LINKLIBS ${X11_Xinput_LIB}) - else() + if(NOT X11_Xinput_LIB) message(FATAL_ERROR "LibXi not found. Disable WITH_X11_XINPUT if you want to build without tablet support") endif() @@ -846,18 +846,14 @@ if(WITH_GHOST_X11) # XXX, why doesn't cmake make this available? find_library(X11_Xxf86vmode_LIB Xxf86vm ${X11_LIB_SEARCH_PATH}) mark_as_advanced(X11_Xxf86vmode_LIB) - if(X11_Xxf86vmode_LIB) - list(APPEND PLATFORM_LINKLIBS ${X11_Xxf86vmode_LIB}) - else() + if(NOT X11_Xxf86vmode_LIB) message(FATAL_ERROR "libXxf86vm not found. Disable WITH_X11_XF86VMODE if you want to build without") endif() endif() if(WITH_X11_XFIXES) - if(X11_Xfixes_LIB) - list(APPEND PLATFORM_LINKLIBS ${X11_Xfixes_LIB}) - else() + if(NOT X11_Xfixes_LIB) message(FATAL_ERROR "libXfixes not found. Disable WITH_X11_XFIXES if you want to build without") endif() @@ -866,9 +862,7 @@ if(WITH_GHOST_X11) if(WITH_X11_ALPHA) find_library(X11_Xrender_LIB Xrender ${X11_LIB_SEARCH_PATH}) mark_as_advanced(X11_Xrender_LIB) - if(X11_Xrender_LIB) - list(APPEND PLATFORM_LINKLIBS ${X11_Xrender_LIB}) - else() + if(NOT X11_Xrender_LIB) message(FATAL_ERROR "libXrender not found. Disable WITH_X11_ALPHA if you want to build without") endif() diff --git a/doc/python_api/requirements.txt b/doc/python_api/requirements.txt index 7d9bb497329..bf120f24995 100644 --- a/doc/python_api/requirements.txt +++ b/doc/python_api/requirements.txt @@ -1,4 +1,4 @@ -sphinx==5.1.1 +sphinx==5.2.3 # Sphinx dependencies that are important Jinja2==3.1.2 @@ -6,7 +6,7 @@ Pygments==2.13.0 docutils==0.17.1 snowballstemmer==2.2.0 babel==2.10.3 -requests==2.27.1 +requests==2.28.1 # Only needed to match the theme used for the official documentation. # Without this theme, the default theme will be used. diff --git a/intern/cycles/blender/id_map.h b/intern/cycles/blender/id_map.h index e77d2f647bf..5fb17bb0d50 100644 --- a/intern/cycles/blender/id_map.h +++ b/intern/cycles/blender/id_map.h @@ -20,7 +20,7 @@ CCL_NAMESPACE_BEGIN * Utility class to map between Blender datablocks and Cycles data structures, * and keep track of recalc tags from the dependency graph. */ -template<typename K, typename T> class id_map { +template<typename K, typename T, typename Flags = uint> class id_map { public: id_map(Scene *scene_) : scene(scene_) { @@ -63,6 +63,11 @@ template<typename K, typename T> class id_map { b_recalc.insert(id_ptr); } + bool check_recalc(const BL::ID &id) + { + return id.ptr.data && b_recalc.find(id.ptr.data) != b_recalc.end(); + } + bool has_recalc() { return !(b_recalc.empty()); @@ -154,6 +159,7 @@ template<typename K, typename T> class id_map { TMapPair &pair = *jt; if (do_delete && used_set.find(pair.second) == used_set.end()) { + flags.erase(pair.second); scene->delete_node(pair.second); } else { @@ -171,9 +177,33 @@ template<typename K, typename T> class id_map { return b_map; } + bool test_flag(T *data, Flags val) + { + typename map<T *, uint>::iterator it = flags.find(data); + return it != flags.end() && (it->second & (1 << val)) != 0; + } + + void set_flag(T *data, Flags val) + { + flags[data] |= (1 << val); + } + + void clear_flag(T *data, Flags val) + { + typename map<T *, uint>::iterator it = flags.find(data); + if (it != flags.end()) { + it->second &= ~(1 << val); + + if (it->second == 0) { + flags.erase(it); + } + } + } + protected: map<K, T *> b_map; set<T *> used_set; + map<T *, uint> flags; set<void *> b_recalc; Scene *scene; }; diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp index 8a3c1136104..5af1e18a597 100644 --- a/intern/cycles/blender/object.cpp +++ b/intern/cycles/blender/object.cpp @@ -96,6 +96,13 @@ bool BlenderSync::object_is_light(BL::Object &b_ob) return (b_ob_data && b_ob_data.is_a(&RNA_Light)); } +bool BlenderSync::object_is_camera(BL::Object &b_ob) +{ + BL::ID b_ob_data = b_ob.data(); + + return (b_ob_data && b_ob_data.is_a(&RNA_Camera)); +} + void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object) { /* Initialize motion blur for object, detecting if it's enabled and creating motion @@ -400,7 +407,8 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance std::string real_name; BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name); - if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) { + if (type == BL::ShaderNodeAttribute::attribute_type_OBJECT || + type == BL::ShaderNodeAttribute::attribute_type_INSTANCER) { bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER); float4 value = lookup_instance_property(b_instance, real_name, use_instancer); diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp index 35be2916e43..a679a92d997 100644 --- a/intern/cycles/blender/pointcloud.cpp +++ b/intern/cycles/blender/pointcloud.cpp @@ -194,7 +194,7 @@ static void export_pointcloud(Scene *scene, /* Export points. */ for (int i = 0; i < num_points; i++) { const float3 co = get_float3(b_attr_position.data[i].vector()); - const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f; + const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f; pointcloud->add_point(co, radius); /* Random number per point. */ @@ -232,7 +232,7 @@ static void export_pointcloud_motion(PointCloud *pointcloud, for (int i = 0; i < std::min(num_points, b_points_num); i++) { const float3 co = get_float3(b_attr_position.data[i].vector()); - const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f; + const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f; float3 P = co; P.w = radius; mP[i] = P; diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 9505f4ba58f..dbc49df7f22 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -22,6 +22,8 @@ #include "util/string.h" #include "util/task.h" +#include "BKE_duplilist.h" + CCL_NAMESPACE_BEGIN typedef map<void *, ShaderInput *> PtrInputMap; @@ -103,6 +105,7 @@ static ImageAlphaType get_image_alpha_type(BL::Image &b_image) static const string_view object_attr_prefix("\x01object:"); static const string_view instancer_attr_prefix("\x01instancer:"); +static const string_view view_layer_attr_prefix("\x01layer:"); static ustring blender_attribute_name_add_type(const string &name, BlenderAttributeType type) { @@ -111,6 +114,8 @@ static ustring blender_attribute_name_add_type(const string &name, BlenderAttrib return ustring::concat(object_attr_prefix, name); case BL::ShaderNodeAttribute::attribute_type_INSTANCER: return ustring::concat(instancer_attr_prefix, name); + case BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER: + return ustring::concat(view_layer_attr_prefix, name); default: return ustring(name); } @@ -130,6 +135,11 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r return BL::ShaderNodeAttribute::attribute_type_INSTANCER; } + if (sname.substr(0, view_layer_attr_prefix.size()) == view_layer_attr_prefix) { + *r_real_name = sname.substr(view_layer_attr_prefix.size()); + return BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER; + } + return BL::ShaderNodeAttribute::attribute_type_GEOMETRY; } @@ -205,7 +215,9 @@ static void set_default_value(ShaderInput *input, } case SocketType::INT: { if (b_sock.type() == BL::NodeSocket::type_BOOLEAN) { - node->set(socket, get_boolean(b_sock.ptr, "default_value")); + /* Make sure to call the int overload of set() since this is an integer socket as far as + * Cycles is concerned. */ + node->set(socket, get_boolean(b_sock.ptr, "default_value") ? 1 : 0); } else { node->set(socket, get_int(b_sock.ptr, "default_value")); @@ -1420,6 +1432,89 @@ static void add_nodes(Scene *scene, empty_proxy_map); } +/* Look up and constant fold all references to View Layer attributes. */ +void BlenderSync::resolve_view_layer_attributes(Shader *shader, + ShaderGraph *graph, + BL::Depsgraph &b_depsgraph) +{ + bool updated = false; + + foreach (ShaderNode *node, graph->nodes) { + if (node->is_a(AttributeNode::node_type)) { + AttributeNode *attr_node = static_cast<AttributeNode *>(node); + + std::string real_name; + BlenderAttributeType type = blender_attribute_name_split_type(attr_node->get_attribute(), + &real_name); + + if (type == BL::ShaderNodeAttribute::attribute_type_VIEW_LAYER) { + /* Look up the value. */ + BL::ViewLayer b_layer = b_depsgraph.view_layer_eval(); + BL::Scene b_scene = b_depsgraph.scene_eval(); + float4 value; + + BKE_view_layer_find_rgba_attribute((::Scene *)b_scene.ptr.data, + (::ViewLayer *)b_layer.ptr.data, + real_name.c_str(), + &value.x); + + /* Replace all outgoing links, using appropriate output types. */ + float val_avg = (value.x + value.y + value.z) / 3.0f; + + foreach (ShaderOutput *output, node->outputs) { + float val_float; + float3 val_float3; + + if (output->type() == SocketType::FLOAT) { + val_float = (output->name() == "Alpha") ? value.w : val_avg; + val_float3 = make_float3(val_float); + } + else { + val_float = val_avg; + val_float3 = float4_to_float3(value); + } + + foreach (ShaderInput *sock, output->links) { + if (sock->type() == SocketType::FLOAT) { + sock->set(val_float); + } + else if (SocketType::is_float3(sock->type())) { + sock->set(val_float3); + } + + sock->constant_folded_in = true; + } + + graph->disconnect(output); + } + + /* Clear the attribute name to avoid further attempts to look up. */ + attr_node->set_attribute(ustring()); + updated = true; + } + } + } + + if (updated) { + shader_map.set_flag(shader, SHADER_WITH_LAYER_ATTRS); + } + else { + shader_map.clear_flag(shader, SHADER_WITH_LAYER_ATTRS); + } +} + +bool BlenderSync::scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph) +{ + if (shader && shader_map.test_flag(shader, SHADER_WITH_LAYER_ATTRS)) { + BL::Scene scene = b_depsgraph.scene_eval(); + + return shader_map.check_recalc(scene) || shader_map.check_recalc(scene.world()) || + shader_map.check_recalc(scene.camera()); + } + + return false; +} + /* Sync Materials */ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) @@ -1438,7 +1533,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) Shader *shader; /* test if we need to sync */ - if (shader_map.add_or_update(&shader, b_mat) || update_all) { + if (shader_map.add_or_update(&shader, b_mat) || update_all || + scene_attr_needs_recalc(shader, b_depsgraph)) { ShaderGraph *graph = new ShaderGraph(); shader->name = b_mat.name().c_str(); @@ -1459,6 +1555,8 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) graph->connect(diffuse->output("BSDF"), out->input("Surface")); } + resolve_view_layer_attributes(shader, graph, b_depsgraph); + /* settings */ PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles"); shader->set_use_mis(get_boolean(cmat, "sample_as_light")); @@ -1515,9 +1613,11 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui); + Shader *shader = scene->default_background; + if (world_recalc || update_all || b_world.ptr.data != world_map || - viewport_parameters.shader_modified(new_viewport_parameters)) { - Shader *shader = scene->default_background; + viewport_parameters.shader_modified(new_viewport_parameters) || + scene_attr_needs_recalc(shader, b_depsgraph)) { ShaderGraph *graph = new ShaderGraph(); /* create nodes */ @@ -1615,6 +1715,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, background->set_visibility(visibility); } + resolve_view_layer_attributes(shader, graph, b_depsgraph); + shader->set_graph(graph); shader->tag_update(scene); } @@ -1681,7 +1783,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all) Shader *shader; /* test if we need to sync */ - if (shader_map.add_or_update(&shader, b_light) || update_all) { + if (shader_map.add_or_update(&shader, b_light) || update_all || + scene_attr_needs_recalc(shader, b_depsgraph)) { ShaderGraph *graph = new ShaderGraph(); /* create nodes */ @@ -1702,6 +1805,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all) graph->connect(emission->output("Emission"), out->input("Surface")); } + resolve_view_layer_attributes(shader, graph, b_depsgraph); + shader->set_graph(graph); shader->tag_update(scene); } diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp index 23bc92de022..a69a94614d3 100644 --- a/intern/cycles/blender/sync.cpp +++ b/intern/cycles/blender/sync.cpp @@ -206,6 +206,9 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d } } } + else if (object_is_camera(b_ob)) { + shader_map.set_recalc(b_ob); + } } /* Mesh */ else if (b_id.is_a(&RNA_Mesh)) { @@ -218,6 +221,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d if (world_map == b_world.ptr.data) { world_recalc = true; } + shader_map.set_recalc(b_world); + } + /* World */ + else if (b_id.is_a(&RNA_Scene)) { + shader_map.set_recalc(b_id); } /* Volume */ else if (b_id.is_a(&RNA_Volume)) { diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h index ae6c2420e55..fbb17bab0c8 100644 --- a/intern/cycles/blender/sync.h +++ b/intern/cycles/blender/sync.h @@ -120,6 +120,11 @@ class BlenderSync { void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all); void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree); + bool scene_attr_needs_recalc(Shader *shader, BL::Depsgraph &b_depsgraph); + void resolve_view_layer_attributes(Shader *shader, + ShaderGraph *graph, + BL::Depsgraph &b_depsgraph); + /* Object */ Object *sync_object(BL::Depsgraph &b_depsgraph, BL::ViewLayer &b_view_layer, @@ -207,13 +212,16 @@ class BlenderSync { bool object_is_geometry(BObjectInfo &b_ob_info); bool object_can_have_geometry(BL::Object &b_ob); bool object_is_light(BL::Object &b_ob); + bool object_is_camera(BL::Object &b_ob); /* variables */ BL::RenderEngine b_engine; BL::BlendData b_data; BL::Scene b_scene; - id_map<void *, Shader> shader_map; + enum ShaderFlags { SHADER_WITH_LAYER_ATTRS }; + + id_map<void *, Shader, ShaderFlags> shader_map; id_map<ObjectKey, Object> object_map; id_map<void *, Procedural> procedural_map; id_map<GeometryKey, Geometry> geometry_map; diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index d1250b83d22..6a16d4bb3b4 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -254,6 +254,10 @@ void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_feat break; } + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + NSOperatingSystemVersion macos_ver = [processInfo operatingSystemVersion]; + global_defines += "#define __KERNEL_METAL_MACOS__ " + to_string(macos_ver.majorVersion) + "\n"; + string &source = this->source[pso_type]; source = "\n#include \"kernel/device/metal/kernel.metal\"\n"; source = path_source_replace_includes(source, path_get("source")); diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp index 2df605fa047..91f53fd1eae 100644 --- a/intern/cycles/device/oneapi/device_impl.cpp +++ b/intern/cycles/device/oneapi/device_impl.cpp @@ -43,7 +43,7 @@ OneapiDevice::OneapiDevice(const DeviceInfo &info, Stats &stats, Profiler &profi } size_t globals_segment_size; - is_finished_ok = kernel_globals_size(device_queue_, globals_segment_size); + is_finished_ok = kernel_globals_size(globals_segment_size); if (is_finished_ok == false) { set_error("oneAPI constant memory initialization got runtime exception \"" + oneapi_error_string_ + "\""); @@ -88,18 +88,26 @@ BVHLayoutMask OneapiDevice::get_bvh_layout_mask() const bool OneapiDevice::load_kernels(const uint requested_features) { assert(device_queue_); - /* NOTE(@nsirgien): oneAPI can support compilation of kernel code with certain feature set - * with specialization constants, but it hasn't been implemented yet. */ - (void)requested_features; bool is_finished_ok = oneapi_run_test_kernel(device_queue_); if (is_finished_ok == false) { - set_error("oneAPI kernel load: got runtime exception \"" + oneapi_error_string_ + "\""); + set_error("oneAPI test kernel execution: got a runtime exception \"" + oneapi_error_string_ + + "\""); + return false; } else { - VLOG_INFO << "Runtime compilation done for \"" << info.description << "\""; + VLOG_INFO << "Test kernel has been executed successfully for \"" << info.description << "\""; assert(device_queue_); } + + is_finished_ok = oneapi_load_kernels(device_queue_, (const unsigned int)requested_features); + if (is_finished_ok == false) { + set_error("oneAPI kernels loading: got a runtime exception \"" + oneapi_error_string_ + "\""); + } + else { + VLOG_INFO << "Kernels loading (compilation) has been done for \"" << info.description << "\""; + } + return is_finished_ok; } @@ -425,6 +433,11 @@ void OneapiDevice::check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_ ((device_type == sycl::info::device_type::host || device_type == sycl::info::device_type::cpu || allow_host) && usm_type == sycl::usm::alloc::host)); +# else + /* Silence warning about unused arguments. */ + (void)queue_; + (void)usm_ptr; + (void)allow_host; # endif } @@ -552,7 +565,7 @@ bool OneapiDevice::queue_synchronize(SyclQueue *queue_) } } -bool OneapiDevice::kernel_globals_size(SyclQueue *queue_, size_t &kernel_global_size) +bool OneapiDevice::kernel_globals_size(size_t &kernel_global_size) { kernel_global_size = sizeof(KernelGlobalsGPU); diff --git a/intern/cycles/device/oneapi/device_impl.h b/intern/cycles/device/oneapi/device_impl.h index 3589e881a6e..62034150eac 100644 --- a/intern/cycles/device/oneapi/device_impl.h +++ b/intern/cycles/device/oneapi/device_impl.h @@ -104,7 +104,7 @@ class OneapiDevice : public Device { int get_num_multiprocessors(); int get_max_num_threads_per_multiprocessor(); bool queue_synchronize(SyclQueue *queue); - bool kernel_globals_size(SyclQueue *queue, size_t &kernel_global_size); + bool kernel_globals_size(size_t &kernel_global_size); void set_global_memory(SyclQueue *queue, void *kernel_globals, const char *memory_name, diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp index 6b033cfd051..506d962f13d 100644 --- a/intern/cycles/integrator/path_trace.cpp +++ b/intern/cycles/integrator/path_trace.cpp @@ -43,8 +43,11 @@ PathTrace::PathTrace(Device *device, /* Create path tracing work in advance, so that it can be reused by incremental sampling as much * as possible. */ device_->foreach_device([&](Device *path_trace_device) { - path_trace_works_.emplace_back(PathTraceWork::create( - path_trace_device, film, device_scene, &render_cancel_.is_requested)); + unique_ptr<PathTraceWork> work = PathTraceWork::create( + path_trace_device, film, device_scene, &render_cancel_.is_requested); + if (work) { + path_trace_works_.emplace_back(std::move(work)); + } }); work_balance_infos_.resize(path_trace_works_.size()); diff --git a/intern/cycles/integrator/path_trace_work.cpp b/intern/cycles/integrator/path_trace_work.cpp index bb5c6e1a61a..a5f98b5475a 100644 --- a/intern/cycles/integrator/path_trace_work.cpp +++ b/intern/cycles/integrator/path_trace_work.cpp @@ -23,6 +23,10 @@ unique_ptr<PathTraceWork> PathTraceWork::create(Device *device, if (device->info.type == DEVICE_CPU) { return make_unique<PathTraceWorkCPU>(device, film, device_scene, cancel_requested_flag); } + if (device->info.type == DEVICE_DUMMY) { + /* Dummy devices can't perform any work. */ + return nullptr; + } return make_unique<PathTraceWorkGPU>(device, film, device_scene, cancel_requested_flag); } diff --git a/intern/cycles/integrator/path_trace_work_cpu.cpp b/intern/cycles/integrator/path_trace_work_cpu.cpp index d5ac830db58..188ec28cf65 100644 --- a/intern/cycles/integrator/path_trace_work_cpu.cpp +++ b/intern/cycles/integrator/path_trace_work_cpu.cpp @@ -285,7 +285,7 @@ void PathTraceWorkCPU::cryptomatte_postproces() } #ifdef WITH_PATH_GUIDING -/* Note: It seems that this is called before every rendering iteration/progression and not once per +/* NOTE: It seems that this is called before every rendering iteration/progression and not once per * rendering. May be we find a way to call it only once per rendering. */ void PathTraceWorkCPU::guiding_init_kernel_globals(void *guiding_field, void *sample_data_storage, diff --git a/intern/cycles/integrator/work_balancer.cpp b/intern/cycles/integrator/work_balancer.cpp index 5f1c6c92b9d..0fe170b2791 100644 --- a/intern/cycles/integrator/work_balancer.cpp +++ b/intern/cycles/integrator/work_balancer.cpp @@ -17,6 +17,9 @@ void work_balance_do_initial(vector<WorkBalanceInfo> &work_balance_infos) work_balance_infos[0].weight = 1.0; return; } + else if (num_infos == 0) { + return; + } /* There is no statistics available, so start with an equal distribution. */ const double weight = 1.0 / num_infos; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 8f50c7586b8..36c8b23d983 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -727,16 +727,9 @@ if(WITH_CYCLES_DEVICE_ONEAPI) ${SRC_UTIL_HEADERS} ) - set (ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS 1) + set (SYCL_OFFLINE_COMPILER_PARALLEL_JOBS 1 CACHE STRING "Number of parallel compiler instances to use for device binaries compilation (expect ~8GB peak memory usage per instance).") if (WITH_CYCLES_ONEAPI_BINARIES) - cmake_host_system_information(RESULT AVAILABLE_MEMORY_AMOUNT QUERY AVAILABLE_PHYSICAL_MEMORY) - # Conservative value of peak consumption here, just to be fully sure that other backend compilers will have enough memory as well - set(ONEAPI_GPU_COMPILER_MEMORY_AT_PEAK_MB 8150) - math(EXPR ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS "${AVAILABLE_MEMORY_AMOUNT} / ${ONEAPI_GPU_COMPILER_MEMORY_AT_PEAK_MB}") - if (ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS LESS 1) - set(ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS 1) - endif() - message(STATUS "${ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS} instance(s) of oneAPI offline compiler will be used.") + message(STATUS "${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS} instance(s) of oneAPI offline compiler will be used.") endif() # SYCL_CPP_FLAGS is a variable that the user can set to pass extra compiler options set(sycl_compiler_flags @@ -747,7 +740,7 @@ if(WITH_CYCLES_DEVICE_ONEAPI) -mllvm -inlinedefault-threshold=250 -mllvm -inlinehint-threshold=350 -fsycl-device-code-split=per_kernel - -fsycl-max-parallel-link-jobs=${ONEAPI_OFFLINE_COMPILER_PARALLEL_JOBS} + -fsycl-max-parallel-link-jobs=${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS} -shared -DWITH_ONEAPI -ffast-math diff --git a/intern/cycles/kernel/device/oneapi/kernel.cpp b/intern/cycles/kernel/device/oneapi/kernel.cpp index 1d1700f036d..40e0b1f0b2b 100644 --- a/intern/cycles/kernel/device/oneapi/kernel.cpp +++ b/intern/cycles/kernel/device/oneapi/kernel.cpp @@ -25,38 +25,57 @@ void oneapi_set_error_cb(OneAPIErrorCallback cb, void *user_ptr) s_error_user_ptr = user_ptr; } -/* NOTE(@nsirgien): Execution of this simple kernel will check basic functionality and - * also trigger runtime compilation of all existing oneAPI kernels */ +/* NOTE(@nsirgien): Execution of this simple kernel will check basic functionality like + * memory allocations, memory transfers and execution of kernel with USM memory. */ bool oneapi_run_test_kernel(SyclQueue *queue_) { assert(queue_); sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_); - size_t N = 8; - sycl::buffer<float, 1> A(N); - sycl::buffer<float, 1> B(N); - - { - sycl::host_accessor A_host_acc(A, sycl::write_only); - for (size_t i = (size_t)0; i < N; i++) - A_host_acc[i] = rand() % 32; - } + const size_t N = 8; + const size_t memory_byte_size = sizeof(int) * N; + bool is_computation_correct = true; try { - queue->submit([&](sycl::handler &cgh) { - sycl::accessor A_acc(A, cgh, sycl::read_only); - sycl::accessor B_acc(B, cgh, sycl::write_only, sycl::no_init); + int *A_host = (int *)sycl::aligned_alloc_host(16, memory_byte_size, *queue); + + for (size_t i = (size_t)0; i < N; i++) { + A_host[i] = rand() % 32; + } - cgh.parallel_for(N, [=](sycl::id<1> idx) { B_acc[idx] = A_acc[idx] + idx.get(0); }); + int *A_device = (int *)sycl::malloc_device(memory_byte_size, *queue); + int *B_device = (int *)sycl::malloc_device(memory_byte_size, *queue); + + queue->memcpy(A_device, A_host, memory_byte_size); + queue->wait_and_throw(); + + queue->submit([&](sycl::handler &cgh) { + cgh.parallel_for(N, [=](sycl::id<1> idx) { B_device[idx] = A_device[idx] + idx.get(0); }); }); queue->wait_and_throw(); - sycl::host_accessor A_host_acc(A, sycl::read_only); - sycl::host_accessor B_host_acc(B, sycl::read_only); + int *B_host = (int *)sycl::aligned_alloc_host(16, memory_byte_size, *queue); + + queue->memcpy(B_host, B_device, memory_byte_size); + queue->wait_and_throw(); for (size_t i = (size_t)0; i < N; i++) { - float result = A_host_acc[i] + B_host_acc[i]; - (void)result; + const int expected_result = i + A_host[i]; + if (B_host[i] != expected_result) { + is_computation_correct = false; + if (s_error_cb) { + s_error_cb(("Incorrect result in test kernel execution - expected " + + std::to_string(expected_result) + ", got " + std::to_string(B_host[i])) + .c_str(), + s_error_user_ptr); + } + } } + + sycl::free(A_host, *queue); + sycl::free(B_host, *queue); + sycl::free(A_device, *queue); + sycl::free(B_device, *queue); + queue->wait_and_throw(); } catch (sycl::exception const &e) { if (s_error_cb) { @@ -65,7 +84,7 @@ bool oneapi_run_test_kernel(SyclQueue *queue_) return false; } - return true; + return is_computation_correct; } /* TODO: Move device information to OneapiDevice initialized on creation and use it. */ @@ -123,6 +142,52 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue, return std::min(limit_work_group_size, preferred_work_group_size); } +bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features) +{ + assert(queue_); + sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_); + + try { + sycl::kernel_bundle<sycl::bundle_state::input> all_kernels_bundle = + sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), + {queue->get_device()}); + + for (const sycl::kernel_id &kernel_id : all_kernels_bundle.get_kernel_ids()) { + const std::string &kernel_name = kernel_id.get_name(); + + /* NOTE(@nsirgien): Names in this conditions below should match names from + * oneapi_call macro in oneapi_enqueue_kernel below */ + if (((requested_features & KERNEL_FEATURE_VOLUME) == 0) && + kernel_name.find("oneapi_kernel_integrator_shade_volume") != std::string::npos) { + continue; + } + + if (((requested_features & KERNEL_FEATURE_MNEE) == 0) && + kernel_name.find("oneapi_kernel_integrator_shade_surface_mnee") != std::string::npos) { + continue; + } + + if (((requested_features & KERNEL_FEATURE_NODE_RAYTRACE) == 0) && + kernel_name.find("oneapi_kernel_integrator_shade_surface_raytrace") != + std::string::npos) { + continue; + } + + sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle = + sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id}); + sycl::build(one_kernel_bundle, {queue->get_device()}, sycl::property::queue::in_order()); + } + } + catch (sycl::exception const &e) { + if (s_error_cb) { + s_error_cb(e.what(), s_error_user_ptr); + } + return false; + } + + return true; +} + bool oneapi_enqueue_kernel(KernelContext *kernel_context, int kernel, size_t global_size, diff --git a/intern/cycles/kernel/device/oneapi/kernel.h b/intern/cycles/kernel/device/oneapi/kernel.h index 7456d0e4902..2bfc0b89c87 100644 --- a/intern/cycles/kernel/device/oneapi/kernel.h +++ b/intern/cycles/kernel/device/oneapi/kernel.h @@ -48,6 +48,8 @@ CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_enqueue_kernel(KernelContext *context, int kernel, size_t global_size, void **args); +CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_load_kernels(SyclQueue *queue, + const unsigned int requested_features); # ifdef __cplusplus } # endif diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h index 038f0379bbc..23885306885 100644 --- a/intern/cycles/kernel/integrator/mnee.h +++ b/intern/cycles/kernel/integrator/mnee.h @@ -279,7 +279,15 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg, } /* Compute constraint derivatives. */ -ccl_device_forceinline bool mnee_compute_constraint_derivatives( + +# if defined(__KERNEL_METAL__) +/* Temporary workaround for front-end compilation bug (incorrect MNEE rendering when this is + * inlined). */ +__attribute__((noinline)) +# else +ccl_device_forceinline +# endif +bool mnee_compute_constraint_derivatives( int vertex_count, ccl_private ManifoldVertex *vertices, ccl_private const float3 &surface_sample_pos, diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h index ebdecc1bff9..e12f333b3a5 100644 --- a/intern/cycles/kernel/sample/pattern.h +++ b/intern/cycles/kernel/sample/pattern.h @@ -100,7 +100,7 @@ ccl_device_inline bool sample_is_class_A(int pattern, int sample) if (!(pattern == SAMPLING_PATTERN_PMJ || pattern == SAMPLING_PATTERN_SOBOL_BURLEY)) { /* Fallback: assign samples randomly. * This is guaranteed to work "okay" for any sampler, but isn't good. - * (Note: the seed constant is just a random number to guard against + * (NOTE: the seed constant is just a random number to guard against * possible interactions with other uses of the hash. There's nothing * special about it.) */ diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 1469d915d15..8f7cfd19169 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -85,9 +85,9 @@ CCL_NAMESPACE_BEGIN # define __VOLUME_RECORD_ALL__ #endif /* !__KERNEL_GPU__ */ -/* MNEE currently causes "Compute function exceeds available temporary registers" - * on Metal, disabled for now. */ -#ifndef __KERNEL_METAL__ +/* MNEE caused "Compute function exceeds available temporary registers" in macOS < 13 due to a bug + * in spill buffer allocation sizing. */ +#if !defined(__KERNEL_METAL__) || (__KERNEL_METAL_MACOS__ >= 13) # define __MNEE__ #endif diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp index a0eb3196a34..acaa55f4990 100644 --- a/intern/cycles/session/session.cpp +++ b/intern/cycles/session/session.cpp @@ -43,6 +43,10 @@ Session::Session(const SessionParams ¶ms_, const SceneParams &scene_params) device = Device::create(params.device, stats, profiler); + if (device->have_error()) { + progress.set_error(device->error_message()); + } + scene = new Scene(scene_params, device); /* Configure path tracer. */ diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index aa23618ca39..2f8ea1f9065 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -262,6 +262,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) ${xkbcommon_INCLUDE_DIRS} ${wayland-cursor_INCLUDE_DIRS} ) + list(APPEND LIB + ${xkbcommon_LINK_LIBRARIES} + ) if(WITH_GHOST_WAYLAND_DYNLOAD) list(APPEND INC_SYS @@ -271,18 +274,32 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) bf_intern_wayland_dynload ) add_definitions(-DWITH_GHOST_WAYLAND_DYNLOAD) + else() + list(APPEND LIB + ${wayland-client_LINK_LIBRARIES} + ${wayland-egl_LINK_LIBRARIES} + ${wayland-cursor_LINK_LIBRARIES} + ) endif() if(WITH_GHOST_WAYLAND_DBUS) list(APPEND INC_SYS ${dbus_INCLUDE_DIRS} ) + list(APPEND LIB + ${dbus_LINK_LIBRARIES} + ) endif() if(WITH_GHOST_WAYLAND_LIBDECOR) list(APPEND INC_SYS ${libdecor_INCLUDE_DIRS} ) + if(NOT WITH_GHOST_WAYLAND_DYNLOAD) + list(APPEND LIB + ${libdecor_LIBRARIES} + ) + endif() endif() include(CheckSymbolExists) @@ -332,16 +349,16 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) ${INC_DST} ) - if(NOT WITH_GHOST_WAYLAND_LIBDECOR) - # `xdg-shell`. - generate_protocol_bindings( - "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml" - ) - # `xdg-decoration`. - generate_protocol_bindings( - "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" - ) - endif() + # Used when: LIBDECOR is not needed. + # `xdg-shell`. + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml" + ) + # `xdg-decoration`. + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" + ) + # End LIBDECOR alternative. # `xdg-output`. generate_protocol_bindings( diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index c9d18be750d..7fda535a7ac 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -36,6 +36,10 @@ extern GHOST_SystemHandle GHOST_CreateSystemBackground(void); */ extern void GHOST_SystemInitDebug(GHOST_SystemHandle systemhandle, GHOST_Debug debug); +#if !(defined(WIN32) || defined(__APPLE__)) +extern const char *GHOST_SystemBackend(void); +#endif + /** * Disposes the one and only system. * \param systemhandle: The handle to the system. diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 0bf540bd4b6..9fb94ed1525 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -134,6 +134,15 @@ class GHOST_ISystem { * \return A pointer to the system. */ static GHOST_ISystem *getSystem(); + /** + * Return an identifier for the one and only system. + * \warning while it may be tempting this should never be used to check for supported features, + * in that case, the GHOST API should be extended to query capabilities. + * This is needed for X11/WAYLAND on Unix, without this - there is no convenient way for users to + * check if WAYLAND or XWAYLAND are in use since they are dynamically selected at startup. + * When dynamically switching between X11/WAYLAND is removed, this function can go too. + */ + static const char *getSystemBackend(); static GHOST_TBacktraceFn getBacktraceFn(); static void setBacktraceFn(GHOST_TBacktraceFn backtrace_fn); @@ -515,6 +524,7 @@ class GHOST_ISystem { /** The one and only system */ static GHOST_ISystem *m_system; + static const char *m_system_backend_id; /** Function to call that sets the back-trace. */ static GHOST_TBacktraceFn m_backtrace_fn; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 69fc6b5f2d0..158e979cdf2 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -52,6 +52,13 @@ GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle) return system->disposeSystem(); } +#if !(defined(WIN32) || defined(__APPLE__)) +const char *GHOST_SystemBackend() +{ + return GHOST_ISystem::getSystemBackend(); +} +#endif + void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle, const char *title, const char *message, diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index 4c1e2705b50..93708983f37 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -306,7 +306,7 @@ GHOST_TSuccess GHOST_ContextGLX::releaseNativeHandles() GHOST_TSuccess GHOST_ContextGLX::setSwapInterval(int interval) { - if (!epoxy_has_glx_extension(m_display, DefaultScreen(m_display), "GLX_EXT_swap_control")) { + if (epoxy_has_glx_extension(m_display, DefaultScreen(m_display), "GLX_EXT_swap_control")) { ::glXSwapIntervalEXT(m_display, m_window, interval); return GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 304d7f0abe6..8e2859ca1e1 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -30,6 +30,7 @@ #endif GHOST_ISystem *GHOST_ISystem::m_system = nullptr; +const char *GHOST_ISystem::m_system_backend_id = nullptr; GHOST_TBacktraceFn GHOST_ISystem::m_backtrace_fn = nullptr; @@ -47,7 +48,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) /* Pass. */ #elif defined(WITH_GHOST_WAYLAND) # if defined(WITH_GHOST_WAYLAND_DYNLOAD) - const bool has_wayland_libraries = ghost_wl_dynload_libraries(); + const bool has_wayland_libraries = ghost_wl_dynload_libraries_init(); # else const bool has_wayland_libraries = true; # endif @@ -65,6 +66,9 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) catch (const std::runtime_error &) { delete m_system; m_system = nullptr; +# ifdef WITH_GHOST_WAYLAND_DYNLOAD + ghost_wl_dynload_libraries_exit(); +# endif } } else { @@ -100,6 +104,9 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) catch (const std::runtime_error &) { delete m_system; m_system = nullptr; +# ifdef WITH_GHOST_WAYLAND_DYNLOAD + ghost_wl_dynload_libraries_exit(); +# endif } } else { @@ -122,7 +129,10 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) m_system = new GHOST_SystemCocoa(); #endif - if ((m_system == nullptr) && verbose) { + if (m_system) { + m_system_backend_id = backends_attempted[backends_attempted_num - 1]; + } + else if (verbose) { fprintf(stderr, "GHOST: failed to initialize display for back-end(s): ["); for (int i = 0; i < backends_attempted_num; i++) { if (i != 0) { @@ -186,6 +196,11 @@ GHOST_ISystem *GHOST_ISystem::getSystem() return m_system; } +const char *GHOST_ISystem::getSystemBackend() +{ + return m_system_backend_id; +} + GHOST_TBacktraceFn GHOST_ISystem::getBacktraceFn() { return GHOST_ISystem::m_backtrace_fn; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 0721ca78603..250c7a48899 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -54,6 +54,11 @@ #include <tablet-unstable-v2-client-protocol.h> #include <xdg-output-unstable-v1-client-protocol.h> +/* Decorations `xdg_decor`. */ +#include <xdg-decoration-unstable-v1-client-protocol.h> +#include <xdg-shell-client-protocol.h> +/* End `xdg_decor`. */ + #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> @@ -64,6 +69,15 @@ /* Logging, use `ghost.wl.*` prefix. */ #include "CLG_log.h" +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +static bool use_libdecor = true; +# ifdef WITH_GHOST_WAYLAND_DYNLOAD +static bool has_libdecor = false; +# else +static bool has_libdecor = true; +# endif +#endif + static void keyboard_handle_key_repeat_cancel(struct GWL_Seat *seat); static void output_handle_done(void *data, struct wl_output *wl_output); @@ -106,6 +120,15 @@ static bool use_gnome_confine_hack = false; */ #define USE_GNOME_KEYBOARD_SUPPRESS_WARNING +/** + * When GNOME is found, require `libdecor`. + * This is a hack because it seems there is no way to check if the compositor supports + * server side decorations when initializing WAYLAND. + */ +#if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(WITH_GHOST_X11) +# define USE_GNOME_NEEDS_LIBDECOR_HACK +#endif + /** \} */ /* -------------------------------------------------------------------- */ @@ -357,6 +380,36 @@ struct WGL_KeyboardDepressedState { int16_t mods[GHOST_KEY_MODIFIER_NUM] = {0}; }; +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +struct WGL_LibDecor_System { + struct libdecor *context = nullptr; +}; + +static void wgl_libdecor_system_destroy(WGL_LibDecor_System *decor) +{ + if (decor->context) { + libdecor_unref(decor->context); + } + delete decor; +} +#endif + +struct WGL_XDG_Decor_System { + struct xdg_wm_base *shell = nullptr; + struct zxdg_decoration_manager_v1 *manager = nullptr; +}; + +static void wgl_xdg_decor_system_destroy(WGL_XDG_Decor_System *decor) +{ + if (decor->manager) { + zxdg_decoration_manager_v1_destroy(decor->manager); + } + if (decor->shell) { + xdg_wm_base_destroy(decor->shell); + } + delete decor; +} + struct GWL_Seat { GHOST_SystemWayland *system = nullptr; @@ -455,11 +508,10 @@ struct GWL_Display { struct wl_compositor *compositor = nullptr; #ifdef WITH_GHOST_WAYLAND_LIBDECOR - struct libdecor *decor_context = nullptr; -#else - struct xdg_wm_base *xdg_shell = nullptr; - struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr; + WGL_LibDecor_System *libdecor = nullptr; + bool libdecor_required = false; #endif + WGL_XDG_Decor_System *xdg_decor = nullptr; struct zxdg_output_manager_v1 *xdg_output_manager = nullptr; struct wl_shm *shm = nullptr; @@ -626,18 +678,18 @@ static void display_destroy(GWL_Display *d) } #ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (d->decor_context) { - libdecor_unref(d->decor_context); - } -#else - if (d->xdg_decoration_manager) { - zxdg_decoration_manager_v1_destroy(d->xdg_decoration_manager); + if (use_libdecor) { + if (d->libdecor) { + wgl_libdecor_system_destroy(d->libdecor); + } } - - if (d->xdg_shell) { - xdg_wm_base_destroy(d->xdg_shell); + else +#endif + { + if (d->xdg_decor) { + wgl_xdg_decor_system_destroy(d->xdg_decor); + } } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ if (eglGetDisplay) { ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display))); @@ -2903,10 +2955,8 @@ static const struct wl_output_listener output_listener = { /** \name Listener (XDG WM Base), #xdg_wm_base_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_WM_BASE = {"ghost.wl.handle.xdg_wm_base"}; -# define LOG (&LOG_WL_XDG_WM_BASE) +#define LOG (&LOG_WL_XDG_WM_BASE) static void shell_handle_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, @@ -2920,9 +2970,7 @@ static const struct xdg_wm_base_listener shell_listener = { shell_handle_ping, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -2978,19 +3026,17 @@ static void global_handle_add(void *data, display->compositor = static_cast<wl_compositor *>( wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3)); } -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - /* Pass. */ -#else else if (STREQ(interface, xdg_wm_base_interface.name)) { - display->xdg_shell = static_cast<xdg_wm_base *>( + WGL_XDG_Decor_System &decor = *display->xdg_decor; + decor.shell = static_cast<xdg_wm_base *>( wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1)); - xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr); + xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr); } else if (STREQ(interface, zxdg_decoration_manager_v1_interface.name)) { - display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>( + WGL_XDG_Decor_System &decor = *display->xdg_decor; + decor.manager = static_cast<zxdg_decoration_manager_v1 *>( wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1)); } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ else if (STREQ(interface, zxdg_output_manager_v1_interface.name)) { display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>( wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 2)); @@ -3048,6 +3094,14 @@ static void global_handle_add(void *data, } else { found = false; + +#ifdef USE_GNOME_NEEDS_LIBDECOR_HACK + if (STRPREFIX(interface, "gtk_shell")) { /* `gtk_shell1` at time of writing. */ + /* Only require `libdecor` when built with X11 support, + * otherwise there is nothing to fall back on. */ + display->libdecor_required = true; + } +#endif } CLOG_INFO(LOG, @@ -3102,6 +3156,9 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display) throw std::runtime_error("Wayland: unable to connect to display!"); } + /* This may be removed later if decorations are required, needed as part of registration. */ + d->xdg_decor = new WGL_XDG_Decor_System; + /* Register interfaces. */ struct wl_registry *registry = wl_display_get_registry(d->display); wl_registry_add_listener(registry, ®istry_listener, d); @@ -3112,17 +3169,45 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display) wl_registry_destroy(registry); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - d->decor_context = libdecor_new(d->display, &libdecor_interface); - if (!d->decor_context) { - display_destroy(d); - throw std::runtime_error("Wayland: unable to create window decorations!"); + if (d->libdecor_required) { + wgl_xdg_decor_system_destroy(d->xdg_decor); + d->xdg_decor = nullptr; + + if (!has_libdecor) { +# ifdef WITH_GHOST_X11 + /* LIBDECOR was the only reason X11 was used, let the user know they need it installed. */ + fprintf(stderr, + "WAYLAND found but libdecor was not, install libdecor for Wayland support, " + "falling back to X11\n"); +# endif + display_destroy(d); + throw std::runtime_error("Wayland: unable to find libdecor!"); + } } -#else - if (!d->xdg_shell) { - display_destroy(d); - throw std::runtime_error("Wayland: unable to access xdg_shell!"); + else { + use_libdecor = false; + } +#endif /* WITH_GHOST_WAYLAND_LIBDECOR */ + +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (use_libdecor) { + d->libdecor = new WGL_LibDecor_System; + WGL_LibDecor_System &decor = *d->libdecor; + decor.context = libdecor_new(d->display, &libdecor_interface); + if (!decor.context) { + display_destroy(d); + throw std::runtime_error("Wayland: unable to create window decorations!"); + } } + else #endif + { + WGL_XDG_Decor_System &decor = *d->xdg_decor; + if (!decor.shell) { + display_destroy(d); + throw std::runtime_error("Wayland: unable to access xdg_shell!"); + } + } /* Register data device per seat for IPC between Wayland clients. */ if (d->data_device_manager) { @@ -4052,24 +4137,24 @@ wl_compositor *GHOST_SystemWayland::compositor() #ifdef WITH_GHOST_WAYLAND_LIBDECOR -libdecor *GHOST_SystemWayland::decor_context() +libdecor *GHOST_SystemWayland::libdecor_context() { - return d->decor_context; + return d->libdecor->context; } -#else /* WITH_GHOST_WAYLAND_LIBDECOR */ +#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ -xdg_wm_base *GHOST_SystemWayland::xdg_shell() +xdg_wm_base *GHOST_SystemWayland::xdg_decor_shell() { - return d->xdg_shell; + return d->xdg_decor->shell; } -zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager() +zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decor_manager() { - return d->xdg_decoration_manager; + return d->xdg_decor->manager; } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ +/* End `xdg_decor`. */ const std::vector<GWL_Output *> &GHOST_SystemWayland::outputs() const { @@ -4317,35 +4402,52 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod return GHOST_kSuccess; } +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +bool GHOST_SystemWayland::use_libdecor_runtime() +{ + return use_libdecor; +} +#endif + #ifdef WITH_GHOST_WAYLAND_DYNLOAD -bool ghost_wl_dynload_libraries() +bool ghost_wl_dynload_libraries_init() { - /* Only report when `libwayland-client` is not found when building without X11, - * which will be used as a fallback. */ # ifdef WITH_GHOST_X11 - bool verbose = false; + /* When running in WAYLAND, let the user know when a missing library is the only reason + * WAYLAND could not be used. Otherwise it's not obvious why X11 is used as a fallback. + * Otherwise when X11 is used, reporting WAYLAND library warnings is unwelcome noise. */ + bool verbose = getenv("WAYLAND_DISPLAY") != nullptr; # else bool verbose = true; -# endif +# endif /* !WITH_GHOST_X11 */ if (wayland_dynload_client_init(verbose) && /* `libwayland-client`. */ wayland_dynload_cursor_init(verbose) && /* `libwayland-cursor`. */ - wayland_dynload_egl_init(verbose) && /* `libwayland-egl`. */ + wayland_dynload_egl_init(verbose) /* `libwayland-egl`. */ + ) { # ifdef WITH_GHOST_WAYLAND_LIBDECOR - wayland_dynload_libdecor_init(verbose) && /* `libdecor-0`. */ + has_libdecor = wayland_dynload_libdecor_init(verbose); /* `libdecor-0`. */ # endif - true) { return true; } -# ifdef WITH_GHOST_WAYLAND_LIBDECOR - wayland_dynload_libdecor_exit(); -# endif + wayland_dynload_client_exit(); wayland_dynload_cursor_exit(); wayland_dynload_egl_exit(); return false; } + +void ghost_wl_dynload_libraries_exit() +{ + wayland_dynload_client_exit(); + wayland_dynload_cursor_exit(); + wayland_dynload_egl_exit(); +# ifdef WITH_GHOST_WAYLAND_LIBDECOR + wayland_dynload_libdecor_exit(); +# endif +} + #endif /* WITH_GHOST_WAYLAND_DYNLOAD */ /** \} */ diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index caea7b0d748..7d19a5cf8b9 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -21,18 +21,12 @@ # include <wayland_dynload_libdecor.h> # endif # include <libdecor.h> -#else -/* Generated by `wayland-scanner`. */ -# include <xdg-decoration-unstable-v1-client-protocol.h> -# include <xdg-shell-client-protocol.h> #endif #include <string> class GHOST_WindowWayland; -struct GWL_Display; - bool ghost_wl_output_own(const struct wl_output *wl_output); void ghost_wl_output_tag(struct wl_output *wl_output); struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output); @@ -52,7 +46,8 @@ void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface); * Return true when all required WAYLAND libraries are present, * Performs dynamic loading when `WITH_GHOST_WAYLAND_DYNLOAD` is in use. */ -bool ghost_wl_dynload_libraries(); +bool ghost_wl_dynload_libraries_init(); +void ghost_wl_dynload_libraries_exit(); #endif struct GWL_Output { @@ -167,11 +162,11 @@ class GHOST_SystemWayland : public GHOST_System { wl_compositor *compositor(); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor *decor_context(); -#else - xdg_wm_base *xdg_shell(); - zxdg_decoration_manager_v1 *xdg_decoration_manager(); + libdecor *libdecor_context(); #endif + struct xdg_wm_base *xdg_decor_shell(); + struct zxdg_decoration_manager_v1 *xdg_decor_manager(); + /* End `xdg_decor`. */ const std::vector<GWL_Output *> &outputs() const; @@ -192,6 +187,10 @@ class GHOST_SystemWayland : public GHOST_System { wl_surface *wl_surface, int scale); +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + static bool use_libdecor_runtime(); +#endif + private: struct GWL_Display *d; std::string selection; diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 6b468f041c1..4523f6fa37c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -2435,11 +2435,11 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title, utf8Str, 8, PropModeReplace, - (const unsigned char *)title, + (const uchar *)title, int(strlen(title))); XChangeProperty( - m_display, window, winType, XA_ATOM, 32, PropModeReplace, (unsigned char *)&typeDialog, 1); + m_display, window, winType, XA_ATOM, 32, PropModeReplace, (uchar *)&typeDialog, 1); } /* Create buttons GC */ diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index 5f3cb3e3f3a..5f9202f1227 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -31,13 +31,52 @@ # include <libdecor.h> #endif +/* Generated by `wayland-scanner`. */ +#include <xdg-decoration-unstable-v1-client-protocol.h> +#include <xdg-shell-client-protocol.h> + /* Logging, use `ghost.wl.*` prefix. */ #include "CLG_log.h" static constexpr size_t base_dpi = 96; +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +/* Access `use_libdecor` in #GHOST_SystemWayland. */ +# define use_libdecor GHOST_SystemWayland::use_libdecor_runtime() +#endif + static GHOST_WindowManager *window_manager = nullptr; +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +struct WGL_LibDecor_Window { + struct libdecor_frame *frame = nullptr; + bool configured = false; +}; + +static void wgl_libdecor_window_destroy(WGL_LibDecor_Window *decor) +{ + libdecor_frame_unref(decor->frame); + delete decor; +} +#endif /* WITH_GHOST_WAYLAND_LIBDECOR */ + +struct WGL_XDG_Decor_Window { + struct xdg_surface *surface = nullptr; + struct zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr; + struct xdg_toplevel *toplevel = nullptr; + enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0; +}; + +static void wgl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor) +{ + if (decor->toplevel_decor) { + zxdg_toplevel_decoration_v1_destroy(decor->toplevel_decor); + } + xdg_toplevel_destroy(decor->toplevel); + xdg_surface_destroy(decor->surface); + delete decor; +} + struct GWL_Window { GHOST_WindowWayland *w = nullptr; struct wl_surface *wl_surface = nullptr; @@ -60,15 +99,9 @@ struct GWL_Window { uint32_t dpi = 0; #ifdef WITH_GHOST_WAYLAND_LIBDECOR - struct libdecor_frame *decor_frame = nullptr; - bool decor_configured = false; -#else - struct xdg_surface *xdg_surface = nullptr; - struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr; - struct xdg_toplevel *xdg_toplevel = nullptr; - - enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0; + WGL_LibDecor_Window *libdecor = nullptr; #endif + WGL_XDG_Decor_Window *xdg_decor = nullptr; wl_egl_window *egl_window = nullptr; bool is_maximised = false; @@ -146,10 +179,8 @@ static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs /** \name Listener (XDG Top Level), #xdg_toplevel_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_TOPLEVEL = {"ghost.wl.handle.xdg_toplevel"}; -# define LOG (&LOG_WL_XDG_TOPLEVEL) +#define LOG (&LOG_WL_XDG_TOPLEVEL) static void xdg_toplevel_handle_configure(void *data, xdg_toplevel * /*xdg_toplevel*/, @@ -197,9 +228,7 @@ static const xdg_toplevel_listener toplevel_listener = { xdg_toplevel_handle_close, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -250,7 +279,7 @@ static void frame_handle_configure(struct libdecor_frame *frame, libdecor_frame_commit(frame, state, configuration); libdecor_state_free(state); - win->decor_configured = true; + win->libdecor->configured = true; } static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data) @@ -285,10 +314,8 @@ static struct libdecor_frame_interface libdecor_frame_iface = { /** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION = {"ghost.wl.handle.xdg_toplevel_decoration"}; -# define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION) +#define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION) static void xdg_toplevel_decoration_handle_configure( void *data, @@ -296,16 +323,14 @@ static void xdg_toplevel_decoration_handle_configure( const uint32_t mode) { CLOG_INFO(LOG, 2, "configure (mode=%u)", mode); - static_cast<GWL_Window *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode; + static_cast<GWL_Window *>(data)->xdg_decor->mode = (zxdg_toplevel_decoration_v1_mode)mode; } static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = { xdg_toplevel_decoration_handle_configure, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -313,10 +338,8 @@ static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listene /** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener * \{ */ -#ifndef WITH_GHOST_WAYLAND_LIBDECOR - static CLG_LogRef LOG_WL_XDG_SURFACE = {"ghost.wl.handle.xdg_surface"}; -# define LOG (&LOG_WL_XDG_SURFACE) +#define LOG (&LOG_WL_XDG_SURFACE) static void xdg_surface_handle_configure(void *data, xdg_surface *xdg_surface, @@ -324,7 +347,7 @@ static void xdg_surface_handle_configure(void *data, { GWL_Window *win = static_cast<GWL_Window *>(data); - if (win->xdg_surface != xdg_surface) { + if (win->xdg_decor->surface != xdg_surface) { CLOG_INFO(LOG, 2, "configure (skipped)"); return; } @@ -354,9 +377,7 @@ static const xdg_surface_listener xdg_surface_listener = { xdg_surface_handle_configure, }; -# undef LOG - -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ +#undef LOG /** \} */ @@ -476,43 +497,64 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, * when the `w->scale` changed. */ const int32_t size_min[2] = {320, 240}; -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - /* create window decorations */ - w->decor_frame = libdecor_decorate( - m_system->decor_context(), w->wl_surface, &libdecor_frame_iface, w); - libdecor_frame_map(w->decor_frame); - - libdecor_frame_set_min_content_size(w->decor_frame, UNPACK2(size_min)); - - if (parentWindow) { - libdecor_frame_set_parent( - w->decor_frame, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->decor_frame); - } -#else - w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface); - w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface); - - xdg_toplevel_set_min_size(w->xdg_toplevel, UNPACK2(size_min)); + /* This value is expected to match the base name of the `.desktop` file. see T101805. + * + * NOTE: the XDG desktop-entry-spec defines that this should follow the "reverse DNS" convention. + * For e.g. `org.blender.Blender` - however the `.desktop` file distributed with Blender is + * simply called `blender.desktop`, so the it's important to follow that name. + * Other distributions such as SNAP & FLATPAK may need to change this value T101779. + * Currently there isn't a way to configure this, we may want to support that. */ + const char *xdg_app_id = "blender"; - if (m_system->xdg_decoration_manager()) { - w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - m_system->xdg_decoration_manager(), w->xdg_toplevel); - zxdg_toplevel_decoration_v1_add_listener( - w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w); - zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration, - ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (use_libdecor) { + w->libdecor = new WGL_LibDecor_Window; + WGL_LibDecor_Window &decor = *w->libdecor; + + /* create window decorations */ + decor.frame = libdecor_decorate( + m_system->libdecor_context(), w->wl_surface, &libdecor_frame_iface, w); + libdecor_frame_map(w->libdecor->frame); + + libdecor_frame_set_min_content_size(decor.frame, UNPACK2(size_min)); + libdecor_frame_set_app_id(decor.frame, xdg_app_id); + + if (parentWindow) { + WGL_LibDecor_Window &decor_parent = + *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->libdecor; + libdecor_frame_set_parent(decor.frame, decor_parent.frame); + } } + else +#endif + { + w->xdg_decor = new WGL_XDG_Decor_Window; + WGL_XDG_Decor_Window &decor = *w->xdg_decor; + decor.surface = xdg_wm_base_get_xdg_surface(m_system->xdg_decor_shell(), w->wl_surface); + decor.toplevel = xdg_surface_get_toplevel(decor.surface); + + xdg_toplevel_set_min_size(decor.toplevel, UNPACK2(size_min)); + xdg_toplevel_set_app_id(decor.toplevel, xdg_app_id); + + if (m_system->xdg_decor_manager()) { + decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration( + m_system->xdg_decor_manager(), decor.toplevel); + zxdg_toplevel_decoration_v1_add_listener( + decor.toplevel_decor, &toplevel_decoration_v1_listener, w); + zxdg_toplevel_decoration_v1_set_mode(decor.toplevel_decor, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } - xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w); - xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w); + xdg_surface_add_listener(decor.surface, &xdg_surface_listener, w); + xdg_toplevel_add_listener(decor.toplevel, &toplevel_listener, w); - if (parentWindow && is_dialog) { - xdg_toplevel_set_parent( - w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel); + if (parentWindow && is_dialog) { + WGL_XDG_Decor_Window &decor_parent = + *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_decor; + xdg_toplevel_set_parent(decor.toplevel, decor_parent.toplevel); + } } -#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ - setTitle(title); wl_surface_set_user_data(w->wl_surface, this); @@ -522,11 +564,14 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, wl_display_roundtrip(m_system->display()); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - /* It's important not to return until the window is configured or - * calls to `setState` from Blender will crash `libdecor`. */ - while (!w->decor_configured) { - if (libdecor_dispatch(m_system->decor_context(), 0) < 0) { - break; + if (use_libdecor) { + WGL_LibDecor_Window &decor = *w->libdecor; + /* It's important not to return until the window is configured or + * calls to `setState` from Blender will crash `libdecor`. */ + while (!decor.configured) { + if (libdecor_dispatch(m_system->libdecor_context(), 0) < 0) { + break; + } } } #endif @@ -535,9 +580,13 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, setOpaque(); #endif -#ifndef WITH_GHOST_WAYLAND_LIBDECOR /* Causes a glitch with `libdecor` for some reason. */ - setState(state); + /* Causes a glitch with `libdecor` for some reason. */ +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (use_libdecor == false) #endif + { + setState(state); + } /* EGL context. */ if (setDrawingContextType(type) == GHOST_kFailure) { @@ -596,12 +645,16 @@ GHOST_TSuccess GHOST_WindowWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma void GHOST_WindowWayland::setTitle(const char *title) { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_app_id(w->decor_frame, title); - libdecor_frame_set_title(w->decor_frame, title); -#else - xdg_toplevel_set_title(w->xdg_toplevel, title); - xdg_toplevel_set_app_id(w->xdg_toplevel, title); + if (use_libdecor) { + WGL_LibDecor_Window &decor = *w->libdecor; + libdecor_frame_set_title(decor.frame, title); + } + else #endif + { + WGL_XDG_Decor_Window &decor = *w->xdg_decor; + xdg_toplevel_set_title(decor.toplevel, title); + } this->title = title; } @@ -672,14 +725,14 @@ GHOST_WindowWayland::~GHOST_WindowWayland() wl_egl_window_destroy(w->egl_window); #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unref(w->decor_frame); -#else - if (w->xdg_toplevel_decoration) { - zxdg_toplevel_decoration_v1_destroy(w->xdg_toplevel_decoration); + if (use_libdecor) { + wgl_libdecor_window_destroy(w->libdecor); } - xdg_toplevel_destroy(w->xdg_toplevel); - xdg_surface_destroy(w->xdg_surface); + else #endif + { + wgl_xdg_decor_window_destroy(w->xdg_decor); + } /* Clear any pointers to this window. This is needed because there are no guarantees * that flushing the display will the "leave" handlers before handling events. */ @@ -711,47 +764,74 @@ GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state) case GHOST_kWindowStateNormal: /* Unset states. */ switch (getState()) { - case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateMaximized: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unset_maximized(w->decor_frame); -#else - xdg_toplevel_unset_maximized(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_unset_maximized(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_unset_maximized(w->xdg_decor->toplevel); + } break; - case GHOST_kWindowStateFullScreen: + } + case GHOST_kWindowStateFullScreen: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unset_fullscreen(w->decor_frame); -#else - xdg_toplevel_unset_fullscreen(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_unset_fullscreen(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_unset_fullscreen(w->xdg_decor->toplevel); + } break; - default: + } + default: { break; + } } break; - case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateMaximized: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_maximized(w->decor_frame); -#else - xdg_toplevel_set_maximized(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_set_maximized(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_set_maximized(w->xdg_decor->toplevel); + } break; - case GHOST_kWindowStateMinimized: + } + case GHOST_kWindowStateMinimized: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_minimized(w->decor_frame); -#else - xdg_toplevel_set_minimized(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_set_minimized(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_set_minimized(w->xdg_decor->toplevel); + } break; - case GHOST_kWindowStateFullScreen: + } + case GHOST_kWindowStateFullScreen: { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_fullscreen(w->decor_frame, nullptr); -#else - xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr); + if (use_libdecor) { + libdecor_frame_set_fullscreen(w->libdecor->frame, nullptr); + } + else #endif + { + xdg_toplevel_set_fullscreen(w->xdg_decor->toplevel, nullptr); + } break; - case GHOST_kWindowStateEmbedded: + } + case GHOST_kWindowStateEmbedded: { return GHOST_kFailure; + } } return GHOST_kSuccess; } @@ -780,20 +860,29 @@ GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/) GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_set_fullscreen(w->decor_frame, nullptr); -#else - xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr); + if (use_libdecor) { + libdecor_frame_set_fullscreen(w->libdecor->frame, nullptr); + } + else #endif + { + xdg_toplevel_set_fullscreen(w->xdg_decor->toplevel, nullptr); + } + return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const { #ifdef WITH_GHOST_WAYLAND_LIBDECOR - libdecor_frame_unset_fullscreen(w->decor_frame); -#else - xdg_toplevel_unset_fullscreen(w->xdg_toplevel); + if (use_libdecor) { + libdecor_frame_unset_fullscreen(w->libdecor->frame); + } + else #endif + { + xdg_toplevel_unset_fullscreen(w->xdg_decor->toplevel); + } return GHOST_kSuccess; } diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c index 63f06ced31d..984e641e7c1 100644 --- a/intern/guardedalloc/intern/mallocn.c +++ b/intern/guardedalloc/intern/mallocn.c @@ -43,7 +43,7 @@ void (*MEM_set_error_callback)(void (*func)(const char *)) = MEM_lockfree_set_er bool (*MEM_consistency_check)(void) = MEM_lockfree_consistency_check; void (*MEM_set_memory_debug)(void) = MEM_lockfree_set_memory_debug; size_t (*MEM_get_memory_in_use)(void) = MEM_lockfree_get_memory_in_use; -unsigned int (*MEM_get_memory_blocks_in_use)(void) = MEM_lockfree_get_memory_blocks_in_use; +uint (*MEM_get_memory_blocks_in_use)(void) = MEM_lockfree_get_memory_blocks_in_use; void (*MEM_reset_peak_memory)(void) = MEM_lockfree_reset_peak_memory; size_t (*MEM_get_peak_memory)(void) = MEM_lockfree_get_peak_memory; diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c index b5ee539ff4d..5a969186b19 100644 --- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c +++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c @@ -233,7 +233,7 @@ void *MEM_lockfree_callocN(size_t len, const char *str) print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, - (unsigned int)mem_in_use); + (uint)mem_in_use); return NULL; } @@ -278,7 +278,7 @@ void *MEM_lockfree_mallocN(size_t len, const char *str) print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, - (unsigned int)mem_in_use); + (uint)mem_in_use); return NULL; } @@ -292,7 +292,7 @@ void *MEM_lockfree_malloc_arrayN(size_t len, size_t size, const char *str) SIZET_ARG(len), SIZET_ARG(size), str, - (unsigned int)mem_in_use); + (uint)mem_in_use); abort(); return NULL; } @@ -349,7 +349,7 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, - (unsigned int)mem_in_use); + (uint)mem_in_use); return NULL; } @@ -401,7 +401,7 @@ size_t MEM_lockfree_get_memory_in_use(void) return mem_in_use; } -unsigned int MEM_lockfree_get_memory_blocks_in_use(void) +uint MEM_lockfree_get_memory_blocks_in_use(void) { return totblock; } diff --git a/intern/mikktspace/mikktspace.hh b/intern/mikktspace/mikktspace.hh index e2c7084566f..9bfa6881f0d 100644 --- a/intern/mikktspace/mikktspace.hh +++ b/intern/mikktspace/mikktspace.hh @@ -723,12 +723,11 @@ template<typename Mesh> class Mikktspace { void build4RuleGroups() { - /* Note: This could be parallelized by grouping all [t, i] pairs into + /* NOTE: This could be parallelized by grouping all [t, i] pairs into * shards by hash(triangles[t].vertices[i]). This way, each shard can be processed * independently and in parallel. - * However, the groupWithAny logic needs special handling (e.g. lock a mutex when - * encountering a groupWithAny triangle, then sort it out, then unlock and proceed). - */ + * However, the `groupWithAny` logic needs special handling (e.g. lock a mutex when + * encountering a `groupWithAny` triangle, then sort it out, then unlock and proceed). */ for (uint t = 0; t < nrTriangles; t++) { Triangle &triangle = triangles[t]; for (uint i = 0; i < 3; i++) { diff --git a/intern/wayland_dynload/intern/wayland_dynload_egl.c b/intern/wayland_dynload/intern/wayland_dynload_egl.c index b62adb6c90e..cfc195c0408 100644 --- a/intern/wayland_dynload/intern/wayland_dynload_egl.c +++ b/intern/wayland_dynload/intern/wayland_dynload_egl.c @@ -22,7 +22,7 @@ bool wayland_dynload_egl_init(const bool verbose) { /* Library paths. */ const char *paths[] = { - "libwayland-egl.so.0", + "libwayland-egl.so.1", "libwayland-egl.so", }; const int paths_num = sizeof(paths) / sizeof(*paths); diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py index 95de2abc709..d8f8d58f609 100644 --- a/release/scripts/modules/bl_i18n_utils/settings.py +++ b/release/scripts/modules/bl_i18n_utils/settings.py @@ -367,9 +367,9 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = { "all and invert unselected", "and AMD driver version 22.10 or newer", "and AMD Radeon Pro 21.Q4 driver or newer", - "and Linux driver version xx.xx.23570 or newer", + "and Linux driver version xx.xx.23904 or newer", "and NVIDIA driver version 470 or newer", - "and Windows driver version 101.3268 or newer", + "and Windows driver version 101.3430 or newer", "available with", "brown fox", "can't save image while rendering", diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index a93f1323562..7fe4d0da0a4 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -389,6 +389,8 @@ class SpellChecker: "albedo", "anamorphic", "anisotropic", "anisotropy", + "arcminute", "arcminutes", + "arcsecond", "arcseconds", "bimanual", # OpenXR? "bitangent", "boid", "boids", @@ -449,7 +451,7 @@ class SpellChecker: "superellipse", "thumbstick", "tooltip", "tooltips", - "trackpad", + "touchpad", "trackpad", "tuple", "unicode", "viewport", "viewports", @@ -650,6 +652,7 @@ class SpellChecker: "mikktspace", "minkowski", "minnaert", + "mises", # von Mises-Fisher "moskowitz", # Pierson-Moskowitz "musgrave", "nayar", @@ -665,6 +668,7 @@ class SpellChecker: "runge", "sobol", "verlet", + "von", # von Mises-Fisher "wilkie", "worley", @@ -724,6 +728,7 @@ class SpellChecker: "lmb", "mmb", "rmb", "lscm", "kb", + "mis", "mocap", "msgid", "msgids", "mux", @@ -751,6 +756,7 @@ class SpellChecker: "uuid", "vbo", "vbos", "vfx", + "vmm", "vr", "wxyz", "xr", diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py index 026c39908c0..7f6d0b1e9bf 100644 --- a/release/scripts/modules/sys_info.py +++ b/release/scripts/modules/sys_info.py @@ -53,6 +53,13 @@ def write_sysinfo(filepath): output.write("build linkflags: %s\n" % prepr(bpy.app.build_linkflags)) output.write("build system: %s\n" % prepr(bpy.app.build_system)) + # Windowing Environment (include when dynamically selectable). + from _bpy import _ghost_backend + ghost_backend = _ghost_backend() + if ghost_backend not in {'NONE', 'DEFAULT'}: + output.write("windowing environment: %s\n" % prepr(ghost_backend)) + del _ghost_backend, ghost_backend + # Python info. output.write(title("Python")) output.write("version: %s\n" % (sys.version.replace("\n", " "))) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 5ab9cdb542a..b83c4916330 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -2073,6 +2073,8 @@ def km_node_editor(params): op_menu("NODE_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}), ("node.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, {"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}), + ("node.duplicate_move_linked", {"type": 'D', "value": 'PRESS', "alt": True}, + {"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}), ("node.duplicate_move_keep_inputs", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True}, {"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}), ("node.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py index ce23024fed5..6a027c0ce1f 100644 --- a/release/scripts/startup/bl_operators/userpref.py +++ b/release/scripts/startup/bl_operators/userpref.py @@ -89,6 +89,17 @@ class PREFERENCES_OT_copy_prev(Operator): if os.path.isdir(cls._old_version_path(version_split)): return version_split version_old = version_old - 1 + + # Support loading 2.8x..2.9x startup (any older isn't so useful to load). + # NOTE: remove this block for Blender 4.0 and later. + if version_old == 299: + version_old = 294 + while version_old >= 280: + version_split = version_old // 100, version_old % 100 + if os.path.isdir(cls._old_version_path(version_split)): + return version_split + version_old = version_old - 1 + return None @classmethod diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 9d04cfd5bc8..3b81f75b08a 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -3158,6 +3158,15 @@ class WM_MT_splash_about(Menu): bpy.app.build_commit_time.decode('utf-8', 'replace')), translate=False) col.label(text=iface_("Hash: %s") % bpy.app.build_hash.decode('ascii'), translate=False) col.label(text=iface_("Branch: %s") % bpy.app.build_branch.decode('utf-8', 'replace'), translate=False) + + # This isn't useful information on MS-Windows or Apple systems as dynamically switching + # between windowing systems is only supported between X11/WAYLAND. + from _bpy import _ghost_backend + ghost_backend = _ghost_backend() + if ghost_backend not in {'NONE', 'DEFAULT'}: + col.label(text=iface_("Windowing Environment: %s") % _ghost_backend(), translate=False) + del _ghost_backend, ghost_backend + col.separator(factor=2.0) col.label(text="Blender is free software") col.label(text="Licensed under the GNU General Public License") diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index c42275fcd54..8567ddb9372 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -239,6 +239,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): class PARTICLE_PT_emission(ParticleButtonsPanel, Panel): bl_label = "Emission" + bl_translation_context = i18n_contexts.id_particlesettings COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH'} @classmethod diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index c337e8018e6..54b3a20f966 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -2,7 +2,10 @@ import bpy from bpy.types import Panel, Header, Menu, UIList -from bpy.app.translations import pgettext_iface as iface_ +from bpy.app.translations import ( + pgettext_iface as iface_, + contexts as i18n_contexts, +) from bl_ui.utils import PresetPanel from bl_ui.properties_grease_pencil_common import ( AnnotationDrawingToolsPanel, @@ -1751,6 +1754,7 @@ class CLIP_MT_marker_pie(Menu): class CLIP_MT_tracking_pie(Menu): # Tracking Operators bl_label = "Tracking" + bl_translation_context = i18n_contexts.id_movieclip @classmethod def poll(cls, context): diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index cefa4bf7d1d..fcbd7bb423d 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -1528,36 +1528,23 @@ class IMAGE_PT_overlay_guides(Panel): layout.active = overlay.show_overlays row = layout.row() - row_el = row.column() - row_el.prop(overlay, "show_grid_background", text="Grid") + row.prop(overlay, "show_grid_background", text="Grid") if overlay.show_grid_background: - layout.use_property_split = True - - col = layout.column(align=False, heading="Grid Over Image") - col.use_property_decorate = False - row = col.row(align=True) - sub = row.row(align=True) - sub.prop(uvedit, "show_grid_over_image", text="") + sub = row.row() + sub.prop(uvedit, "show_grid_over_image", text="Over Image") sub.active = sima.image is not None - col = layout.column(align=False, heading="Fixed Subdivisions") - col.use_property_decorate = False + layout.row().prop(uvedit, "grid_shape_source", expand=True) - row = col.row(align=True) - sub = row.row(align=True) - sub.prop(uvedit, "use_custom_grid", text="") - if uvedit.use_custom_grid: - row = layout.row() - row.use_property_split = True - row.use_property_decorate = False - sub = sub.row(align=True) - sub.prop(uvedit, "custom_grid_subdivisions", text="") + layout.use_property_split = True + layout.use_property_decorate = False row = layout.row() - row.use_property_split = True - row.use_property_decorate = False - row.prop(uvedit, "tile_grid_shape", text="Tiles") + row.prop(uvedit, "custom_grid_subdivisions", text="Fixed Subdivisions") + row.active = uvedit.grid_shape_source == 'FIXED' + + layout.prop(uvedit, "tile_grid_shape", text="Tiles") class IMAGE_PT_overlay_uv_edit(Panel): diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index f4070a8289d..593c6400529 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -318,6 +318,7 @@ class NODE_MT_node(Menu): layout.operator("node.clipboard_copy", text="Copy") layout.operator("node.clipboard_paste", text="Paste") layout.operator("node.duplicate_move") + layout.operator("node.duplicate_move_linked") layout.operator("node.delete") layout.operator("node.delete_reconnect") diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index a99df1164a0..e703cf7f9c6 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -683,7 +683,7 @@ class SEQUENCER_MT_add(Menu): elif bpy_data_movieclips_len > 0: layout.operator_menu_enum("sequencer.movieclip_strip_add", "clip", text="Clip", icon='TRACKER') else: - layout.menu("SEQUENCER_MT_add_empty", text="Clip", icon='TRACKER') + layout.menu("SEQUENCER_MT_add_empty", text="Clip", text_ctxt=i18n_contexts.id_movieclip, icon='TRACKER') del bpy_data_movieclips_len bpy_data_masks_len = len(bpy.data.masks) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index a9736feb057..53999f3c154 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -397,17 +397,18 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa # col.prop(edit, "use_duplicate_fcurve", text="F-Curve") # Not implemented. col.prop(edit, "use_duplicate_curves", text="Curves") col.prop(edit, "use_duplicate_grease_pencil", text="Grease Pencil") + col.prop(edit, "use_duplicate_lattice", text="Lattice") col = flow.column() - col.prop(edit, "use_duplicate_lattice", text="Lattice") col.prop(edit, "use_duplicate_light", text="Light") col.prop(edit, "use_duplicate_lightprobe", text="Light Probe") col.prop(edit, "use_duplicate_material", text="Material") col.prop(edit, "use_duplicate_mesh", text="Mesh") col.prop(edit, "use_duplicate_metaball", text="Metaball") + col.prop(edit, "use_duplicate_node_tree", text="Node Tree") + col.prop(edit, "use_duplicate_particle", text="Particle") col = flow.column() - col.prop(edit, "use_duplicate_particle", text="Particle") if hasattr(edit, "use_duplicate_pointcloud"): col.prop(edit, "use_duplicate_pointcloud", text="Point Cloud") col.prop(edit, "use_duplicate_speaker", text="Speaker") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index ada2993a16f..3a02492635a 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3356,8 +3356,7 @@ class VIEW3D_MT_face_sets(Menu): op = layout.operator("sculpt.face_set_change_visibility", text='Invert Visible Face Sets') op.mode = 'INVERT' - op = layout.operator("sculpt.face_set_change_visibility", text='Show All Face Sets') - op.mode = 'SHOW_ALL' + op = layout.operator("sculpt.reveal_all", text='Show All Face Sets') layout.separator() @@ -5518,8 +5517,7 @@ class VIEW3D_MT_sculpt_face_sets_edit_pie(Menu): op = pie.operator("sculpt.face_set_change_visibility", text='Invert Visible') op.mode = 'INVERT' - op = pie.operator("sculpt.face_set_change_visibility", text='Show All') - op.mode = 'SHOW_ALL' + op = pie.operator("sculpt.reveal_all", text='Show All') class VIEW3D_MT_wpaint_vgroup_lock_pie(Menu): diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index d22abd235df..a0a6ac58c58 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -11,6 +11,10 @@ #include "BLI_threads.h" #ifdef __cplusplus +# include <mutex> +#endif + +#ifdef __cplusplus extern "C" { #endif @@ -196,6 +200,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, BVHCacheType bvh_cache_type, int tree_type); +#ifdef __cplusplus + /** * Builds or queries a BVH-cache for the cache BVH-tree of the request type. */ @@ -204,7 +210,9 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data, int tree_type, BVHCacheType bvh_cache_type, struct BVHCache **bvh_cache_p, - ThreadMutex *mesh_eval_mutex); + std::mutex *mesh_eval_mutex); + +#endif /** * Frees data allocated by a call to `bvhtree_from_editmesh_*`. diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 61f3a0e1d5e..f761e28cbb4 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -146,15 +146,6 @@ void CustomData_copy(const struct CustomData *source, eCDAllocType alloctype, int totelem); -/** - * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh. - */ -void CustomData_copy_mesh_to_bmesh(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem); - /* BMESH_TODO, not really a public function but readfile.c needs it */ void CustomData_update_typemap(struct CustomData *data); @@ -169,15 +160,6 @@ bool CustomData_merge(const struct CustomData *source, int totelem); /** - * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh. - */ -bool CustomData_merge_mesh_to_bmesh(const struct CustomData *source, - struct CustomData *dest, - eCustomDataMask mask, - eCDAllocType alloctype, - int totelem); - -/** * Reallocate custom data to a new element count. If the new size is larger, the new values use * the #CD_CONSTRUCT behavior, so trivial types must be initialized by the caller. After being * resized, the #CustomData does not contain any referenced layers. @@ -197,6 +179,14 @@ bool CustomData_bmesh_merge(const struct CustomData *source, char htype); /** + * Remove layers that aren't stored in BMesh or are stored as flags on BMesh. + * The `layers` array of the returned #CustomData must be freed, but may be null. + * Used during conversion of #Mesh data to #BMesh storage format. + */ +CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, + eCustomDataMask mask); + +/** * NULL's all members and resets the #CustomData.typemap. */ void CustomData_reset(struct CustomData *data); diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index 8a37348377a..44c4df1fc2e 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -16,6 +16,7 @@ struct ListBase; struct Object; struct ParticleSystem; struct Scene; +struct ViewLayer; struct ViewerPath; struct GeometrySet; @@ -83,6 +84,13 @@ bool BKE_object_dupli_find_rgba_attribute(struct Object *ob, const char *name, float r_value[4]); +/** Look up the RGBA value of a view layer/scene/world shader attribute. + * \return true if the attribute was found; if not, r_value is also set to zero. */ +bool BKE_view_layer_find_rgba_attribute(struct Scene *scene, + struct ViewLayer *layer, + const char *name, + float r_value[4]); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_editmesh_cache.h b/source/blender/blenkernel/BKE_editmesh_cache.h index 2640356ccf6..454a07be4e3 100644 --- a/source/blender/blenkernel/BKE_editmesh_cache.h +++ b/source/blender/blenkernel/BKE_editmesh_cache.h @@ -11,15 +11,25 @@ extern "C" { #endif struct BMEditMesh; -struct EditMeshData; -void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, struct EditMeshData *emd); -void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMeshData *emd); +typedef struct EditMeshData { + /** when set, \a vertexNos, polyNos are lazy initialized */ + const float (*vertexCos)[3]; -void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd); + /** lazy initialize (when \a vertexCos is set) */ + float const (*vertexNos)[3]; + float const (*polyNos)[3]; + /** also lazy init but don't depend on \a vertexCos */ + const float (*polyCos)[3]; +} EditMeshData; + +void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, EditMeshData *emd); +void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, EditMeshData *emd); + +void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, EditMeshData *emd); bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em, - struct EditMeshData *emd, + EditMeshData *emd, float min[3], float max[3]); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 0a000f4543a..0ff7f50f71c 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -490,7 +490,7 @@ void BKE_mesh_calc_normals(struct Mesh *me); * Called after calculating all modifiers. */ void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh); -void BKE_mesh_calc_normals_looptri(struct MVert *mverts, +void BKE_mesh_calc_normals_looptri(const struct MVert *mverts, int numVerts, const struct MLoop *mloop, const struct MLoopTri *looptri, diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index da8431d4f27..9d9c2f57f89 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -336,7 +336,7 @@ int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge, #endif #ifdef __cplusplus -namespace blender::mesh_topology { +namespace blender::bke::mesh_topology { Array<int> build_loop_to_poly_map(Span<MPoly> polys, int loops_num); @@ -348,5 +348,5 @@ inline int previous_poly_loop(const MPoly &poly, int loop_i) return loop_i - 1 + (loop_i == poly.loopstart) * poly.totloop; } -} // namespace blender::mesh_topology +} // namespace blender::bke::mesh_topology #endif diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h index dfefe125a51..27e04c1a4de 100644 --- a/source/blender/blenkernel/BKE_mesh_runtime.h +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -9,6 +9,7 @@ */ //#include "BKE_customdata.h" /* for eCustomDataMask */ +#include "BKE_mesh_types.h" #ifdef __cplusplus extern "C" { @@ -26,21 +27,10 @@ struct Object; struct Scene; /** - * \brief Initialize the runtime of the given mesh. - * - * Function expects that the runtime is already cleared. - */ -void BKE_mesh_runtime_init_data(struct Mesh *mesh); -/** * \brief Free all data (and mutexes) inside the runtime of the given mesh. */ void BKE_mesh_runtime_free_data(struct Mesh *mesh); -/** - * Clear all pointers which we don't want to be shared on copying the datablock. - * However, keep all the flags which defines what the mesh is (for example, that - * it's deformed only, or that its custom data layers are out of date.) - */ -void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, int flag); + int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh); void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh); /** @@ -66,6 +56,11 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri, const struct MLoopTri *looptri, int looptri_num); +/** \note Only used for access in C. */ +bool BKE_mesh_is_deformed_only(const struct Mesh *mesh); +/** \note Only used for access in C. */ +eMeshWrapperType BKE_mesh_wrapper_type(const struct Mesh *mesh); + /* NOTE: the functions below are defined in DerivedMesh.cc, and are intended to be moved * to a more suitable location when that file is removed. * They should also be renamed to use conventions from BKE, not old DerivedMesh.cc. diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h index 0b879c1dfe9..dacc2188abb 100644 --- a/source/blender/blenkernel/BKE_mesh_types.h +++ b/source/blender/blenkernel/BKE_mesh_types.h @@ -1,11 +1,35 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2020 Blender Foundation. All rights reserved. */ + #pragma once /** \file * \ingroup bke */ +#ifdef __cplusplus + +# include <mutex> + +# include "BLI_span.hh" + +# include "DNA_customdata_types.h" + +# include "MEM_guardedalloc.h" + +struct BVHCache; +struct EditMeshData; +struct MLoopTri; +struct ShrinkwrapBoundaryData; +struct SubdivCCG; +struct SubsurfRuntimeData; + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + typedef enum eMeshBatchDirtyMode { BKE_MESH_BATCH_DIRTY_ALL = 0, BKE_MESH_BATCH_DIRTY_SELECT, @@ -14,3 +38,125 @@ typedef enum eMeshBatchDirtyMode { BKE_MESH_BATCH_DIRTY_UVEDIT_ALL, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT, } eMeshBatchDirtyMode; + +/** #MeshRuntime.wrapper_type */ +typedef enum eMeshWrapperType { + /** Use mesh data (#Mesh.mvert, #Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */ + ME_WRAPPER_TYPE_MDATA = 0, + /** Use edit-mesh data (#Mesh.edit_mesh, #MeshRuntime.edit_data). */ + ME_WRAPPER_TYPE_BMESH = 1, + /** Use subdivision mesh data (#MeshRuntime.mesh_eval). */ + ME_WRAPPER_TYPE_SUBD = 2, +} eMeshWrapperType; + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +namespace blender::bke { + +/** + * \warning Typical access is done via #Mesh::looptris(). + */ +struct MLoopTri_Store { + /* WARNING! swapping between array (ready-to-be-used data) and array_wip + * (where data is actually computed) + * shall always be protected by same lock as one used for looptris computing. */ + MLoopTri *array = nullptr; + MLoopTri *array_wip = nullptr; + int len = 0; + int len_alloc = 0; +}; + +struct MeshRuntime { + /* Evaluated mesh for objects which do not have effective modifiers. + * This mesh is used as a result of modifier stack evaluation. + * Since modifier stack evaluation is threaded on object level we need some synchronization. */ + Mesh *mesh_eval = nullptr; + std::mutex eval_mutex; + + /* A separate mutex is needed for normal calculation, because sometimes + * the normals are needed while #eval_mutex is already locked. */ + std::mutex normals_mutex; + + /** Needed to ensure some thread-safety during render data pre-processing. */ + std::mutex render_mutex; + + /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */ + EditMeshData *edit_data = nullptr; + + /** + * Data used to efficiently draw the mesh in the viewport, especially useful when + * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`. + */ + void *batch_cache = nullptr; + + /** Cache for derived triangulation of the mesh. */ + MLoopTri_Store looptris; + + /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */ + BVHCache *bvh_cache = nullptr; + + /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */ + ShrinkwrapBoundaryData *shrinkwrap_data = nullptr; + + /** Needed in case we need to lazily initialize the mesh. */ + CustomData_MeshMasks cd_mask_extra = {}; + + SubdivCCG *subdiv_ccg = nullptr; + int subdiv_ccg_tot_level = 0; + + /** Set by modifier stack if only deformed from original. */ + bool deformed_only = false; + /** + * Copied from edit-mesh (hint, draw with edit-mesh data when true). + * + * Modifiers that edit the mesh data in-place must set this to false + * (most #eModifierTypeType_NonGeometrical modifiers). Otherwise the edit-mesh + * data will be used for drawing, missing changes from modifiers. See T79517. + */ + bool is_original_bmesh = false; + + /** #eMeshWrapperType and others. */ + eMeshWrapperType wrapper_type = ME_WRAPPER_TYPE_MDATA; + /** + * A type mask from wrapper_type, + * in case there are differences in finalizing logic between types. + */ + eMeshWrapperType wrapper_type_finalize = ME_WRAPPER_TYPE_MDATA; + + /** + * Settings for lazily evaluating the subdivision on the CPU if needed. These are + * set in the modifier when GPU subdivision can be performed, and owned by the by + * the modifier in the object. + */ + SubsurfRuntimeData *subsurf_runtime_data = nullptr; + + /** + * Caches for lazily computed vertex and polygon normals. These are stored here rather than in + * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a + * const mesh is not thread-safe. + */ + bool vert_normals_dirty = false; + bool poly_normals_dirty = false; + float (*vert_normals)[3] = nullptr; + float (*poly_normals)[3] = nullptr; + + /** + * A #BLI_bitmap containing tags for the center vertices of subdivided polygons, set by the + * subdivision surface modifier and used by drawing code instead of polygon center face dots. + */ + uint32_t *subsurf_face_dot_tags = nullptr; + + MeshRuntime() = default; + /** \warning This does not free all data currently. See #BKE_mesh_runtime_free_data. */ + ~MeshRuntime() = default; + + MEM_CXX_CLASS_ALLOC_FUNCS("MeshRuntime") +}; + +} // namespace blender::bke + +#endif diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 9d3000759ab..efadd5c11d6 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -246,6 +246,24 @@ float BKE_nlastrip_compute_frame_from_previous_strip(struct NlaStrip *strip); */ float BKE_nlastrip_compute_frame_to_next_strip(struct NlaStrip *strip); +/** + * Returns the next strip in this strip's NLA track, or a null pointer. + * + * \param strip The strip to find the next trip from. + * \param check_transitions Whether or not to skip transitions. + * \return The next strip in the track, or NULL if none are present. + */ +struct NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_transitions); + +/** + * Returns the previous strip in this strip's NLA track, or a null pointer. + * + * \param strip The strip to find the previous trip from. + * \param check_transitions Whether or not to skip transitions. + * \return The previous strip in the track, or NULL if none are present. + */ +struct NlaStrip *BKE_nlastrip_prev_in_track(struct NlaStrip *strip, bool skip_transitions); + /* ............ */ /** diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 6d103eab8a7..c3100dd2345 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -126,6 +126,8 @@ typedef enum { PBVH_UpdateColor = 1 << 14, PBVH_RebuildPixels = 1 << 15, PBVH_TexLeaf = 1 << 16, + PBVH_TopologyUpdated = 1 << 17, /* Used internally by pbvh_bmesh.c */ + } PBVHNodeFlags; typedef struct PBVHFrustumPlanes { @@ -266,7 +268,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden, - struct Mesh *me); + struct Mesh *me, + struct SubdivCCG *subdiv_ccg); /** * Build a PBVH from a BMesh. */ @@ -490,7 +493,10 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node); * * Skips triangles that are hidden. */ -void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node); +void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, + struct BMLog *log, + PBVHNode *node, + bool use_original); void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh); /* Update Bounding Box/Redraw and clear flags. */ @@ -669,7 +675,8 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot); void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, int (**r_orco_tris)[3], int *r_orco_tris_num, - float (**r_orco_coords)[3]); + float (**r_orco_coords)[3], + struct BMVert ***r_orco_verts); /** * \note doing a full search on all vertices here seems expensive, diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index b4cc46619a7..11ef2b08df4 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -35,6 +35,7 @@ #include "BKE_colorband.h" #include "BKE_deform.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_geometry_set.hh" #include "BKE_geometry_set_instances.hh" #include "BKE_key.h" @@ -537,7 +538,7 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, (final_datamask->lmask & CD_MASK_NORMAL) != 0); /* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */ - SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data; + SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data; if (subsurf_runtime_data) { subsurf_runtime_data->calc_loop_normals = calc_loop_normals; } @@ -585,11 +586,12 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval) void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval, const CustomData_MeshMasks *cd_mask_finalize) { - if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) { + if (me_eval->runtime->wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) { editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize); - me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH); + me_eval->runtime->wrapper_type_finalize = eMeshWrapperType( + me_eval->runtime->wrapper_type_finalize & ~(1 << ME_WRAPPER_TYPE_BMESH)); } - BLI_assert(me_eval->runtime.wrapper_type_finalize == 0); + BLI_assert(me_eval->runtime->wrapper_type_finalize == 0); } /** @@ -1052,7 +1054,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, append_mask.lmask |= CD_MASK_PREVIEW_MLOOPCOL; } - mesh_final->runtime.deformed_only = false; + mesh_final->runtime->deformed_only = false; } isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform); @@ -1119,10 +1121,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, mesh_calc_finalize(mesh_input, mesh_final); } else { - Mesh_Runtime *runtime = &mesh_input->runtime; + blender::bke::MeshRuntime *runtime = mesh_input->runtime; if (runtime->mesh_eval == nullptr) { - BLI_assert(runtime->eval_mutex != nullptr); - BLI_mutex_lock((ThreadMutex *)runtime->eval_mutex); + std::lock_guard lock{mesh_input->runtime->eval_mutex}; if (runtime->mesh_eval == nullptr) { /* Not yet finalized by any instance, do it now * Isolate since computing normals is multithreaded and we are holding a lock. */ @@ -1138,7 +1139,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Already finalized by another instance, reuse. */ mesh_final = runtime->mesh_eval; } - BLI_mutex_unlock((ThreadMutex *)runtime->eval_mutex); } else if (!mesh_has_modifier_final_normals(mesh_input, &final_datamask, runtime->mesh_eval)) { /* Modifier stack was (re-)evaluated with a request for additional normals @@ -1207,7 +1207,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 || (final_datamask->lmask & CD_MASK_NORMAL) != 0); - SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data; + SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data; if (subsurf_runtime_data) { subsurf_runtime_data->calc_loop_normals = calc_loop_normals; } @@ -1234,9 +1234,10 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, static void editbmesh_calc_modifier_final_normals_or_defer( Mesh *mesh_final, const CustomData_MeshMasks *final_datamask) { - if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) { + if (mesh_final->runtime->wrapper_type != ME_WRAPPER_TYPE_MDATA) { /* Generated at draw time. */ - mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type); + mesh_final->runtime->wrapper_type_finalize = eMeshWrapperType( + 1 << mesh_final->runtime->wrapper_type); return; } @@ -1450,7 +1451,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, deformed_verts = nullptr; } } - mesh_final->runtime.deformed_only = false; + mesh_final->runtime->deformed_only = false; } if (r_cage && i == cageIndex) { @@ -1469,7 +1470,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (!BKE_mesh_runtime_ensure_edit_data(me_orig)) { BKE_mesh_runtime_reset_edit_data(me_orig); } - me_orig->runtime.edit_data->vertexCos = (const float(*)[3])MEM_dupallocN(deformed_verts); + me_orig->runtime->edit_data->vertexCos = (const float(*)[3])MEM_dupallocN( + deformed_verts); } mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords( em_input, @@ -1583,7 +1585,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph, * object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns * the final result might be freed prior to object). */ Mesh *mesh = (Mesh *)ob->data; - const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval); + const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime->mesh_eval); BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned); /* Add the final mesh as a non-owning component to the geometry set. */ @@ -1643,7 +1645,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph, } } - const bool is_mesh_eval_owned = (me_final != mesh->runtime.mesh_eval); + const bool is_mesh_eval_owned = (me_final != mesh->runtime->mesh_eval); BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned); obedit->runtime.editmesh_eval_cage = me_cage; @@ -1899,7 +1901,7 @@ struct MappedUserData { static void make_vertexcos__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no[3])) + const float /*no*/[3]) { MappedUserData *mappedData = (MappedUserData *)userData; @@ -1914,7 +1916,7 @@ static void make_vertexcos__mapFunc(void *userData, void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int totcos) { - if (me_eval->runtime.deformed_only == false) { + if (me_eval->runtime->deformed_only == false) { MappedUserData userData; memset(r_cos, 0, sizeof(*r_cos) * totcos); userData.vertexcos = r_cos; diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index 58b377eecdb..afc3e525143 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -51,13 +51,13 @@ struct BVHCache { * When the `r_locked` is filled and the tree could not be found the caches mutex will be * locked. This mutex can be unlocked by calling `bvhcache_unlock`. * - * When `r_locked` is used the `mesh_eval_mutex` must contain the `Mesh_Runtime.eval_mutex`. + * When `r_locked` is used the `mesh_eval_mutex` must contain the `MeshRuntime.eval_mutex`. */ static bool bvhcache_find(BVHCache **bvh_cache_p, BVHCacheType type, BVHTree **r_tree, bool *r_locked, - ThreadMutex *mesh_eval_mutex) + std::mutex *mesh_eval_mutex) { bool do_lock = r_locked; if (r_locked) { @@ -69,11 +69,10 @@ static bool bvhcache_find(BVHCache **bvh_cache_p, return false; } /* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */ - BLI_mutex_lock(mesh_eval_mutex); + std::lock_guard lock{*mesh_eval_mutex}; if (*bvh_cache_p == nullptr) { *bvh_cache_p = bvhcache_init(); } - BLI_mutex_unlock(mesh_eval_mutex); } BVHCache *bvh_cache = *bvh_cache_p; @@ -1222,8 +1221,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const BVHCacheType bvh_cache_type, const int tree_type) { - BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache; - ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; + BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime->bvh_cache; const MLoopTri *looptri = nullptr; int looptri_len = 0; @@ -1248,7 +1246,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, bool lock_started = false; data->cached = bvhcache_find( - bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex); + bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, &mesh->runtime->eval_mutex); if (data->cached) { BLI_assert(lock_started == false); @@ -1352,7 +1350,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data, const int tree_type, const BVHCacheType bvh_cache_type, BVHCache **bvh_cache_p, - ThreadMutex *mesh_eval_mutex) + std::mutex *mesh_eval_mutex) { bool lock_started = false; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 56de583e2db..89983eb8f62 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -826,7 +826,7 @@ static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mes const MLoop *mloop = BKE_mesh_loops(mesh); const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh); const uint mvert_num = mesh->totvert; - const uint looptri_num = mesh->runtime.looptris.len; + const uint looptri_num = BKE_mesh_runtime_looptri_len(mesh); /* Allocate our vertices. */ clmd->clothObject->mvert_num = mvert_num; @@ -1167,7 +1167,7 @@ static Mesh *cloth_make_rest_mesh(ClothModifierData *clmd, Mesh *mesh) MVert *mvert = BKE_mesh_verts_for_write(mesh); /* vertex count is already ensured to match */ - for (unsigned i = 0; i < mesh->totvert; i++, verts++) { + for (uint i = 0; i < mesh->totvert; i++, verts++) { copy_v3_v3(mvert[i].co, verts->xrest); } BKE_mesh_tag_coords_changed(new_mesh); diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index be99a8ee87b..6f2390fc28f 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2382,16 +2382,21 @@ static bool attribute_stored_in_bmesh_flag(const StringRef name) "material_index"); } -static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src) +CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, + const eCustomDataMask mask) { Vector<CustomDataLayer> dst_layers; - for (const CustomDataLayer &layer : Span<CustomDataLayer>{src.layers, src.totlayer}) { - if (!attribute_stored_in_bmesh_flag(layer.name)) { - dst_layers.append(layer); + for (const CustomDataLayer &layer : Span<CustomDataLayer>{src->layers, src->totlayer}) { + if (attribute_stored_in_bmesh_flag(layer.name)) { + continue; + } + if (!(mask & CD_TYPE_AS_MASK(layer.type))) { + continue; } + dst_layers.append(layer); } - CustomData dst = src; + CustomData dst = *src; dst.layers = static_cast<CustomDataLayer *>( MEM_calloc_arrayN(dst_layers.size(), sizeof(CustomDataLayer), __func__)); dst.totlayer = dst_layers.size(); @@ -2402,18 +2407,6 @@ static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src return dst; } -bool CustomData_merge_mesh_to_bmesh(const CustomData *source, - CustomData *dest, - const eCustomDataMask mask, - const eCDAllocType alloctype, - const int totelem) -{ - CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source); - const bool result = CustomData_merge(&source_copy, dest, mask, alloctype, totelem); - MEM_SAFE_FREE(source_copy.layers); - return result; -} - void CustomData_realloc(CustomData *data, const int old_size, const int new_size) { BLI_assert(new_size >= 0); @@ -2463,17 +2456,6 @@ void CustomData_copy(const CustomData *source, CustomData_merge(source, dest, mask, alloctype, totelem); } -void CustomData_copy_mesh_to_bmesh(const CustomData *source, - CustomData *dest, - const eCustomDataMask mask, - const eCDAllocType alloctype, - const int totelem) -{ - CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source); - CustomData_copy(&source_copy, dest, mask, alloctype, totelem); - MEM_SAFE_FREE(source_copy.layers); -} - static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem) { const LayerTypeInfo *typeInfo; @@ -3697,7 +3679,7 @@ bool CustomData_bmesh_merge(const CustomData *source, destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers)); } - if (CustomData_merge_mesh_to_bmesh(source, dest, mask, alloctype, 0) == false) { + if (CustomData_merge(source, dest, mask, alloctype, 0) == false) { if (destold.layers) { MEM_freeN(destold.layers); } diff --git a/source/blender/blenkernel/intern/editmesh.cc b/source/blender/blenkernel/intern/editmesh.cc index 3a1dcd59f55..b586b4110f2 100644 --- a/source/blender/blenkernel/intern/editmesh.cc +++ b/source/blender/blenkernel/intern/editmesh.cc @@ -189,7 +189,7 @@ struct CageUserData { static void cage_mapped_verts_callback(void *userData, int index, const float co[3], - const float UNUSED(no[3])) + const float /*no*/[3]) { CageUserData *data = static_cast<CageUserData *>(userData); @@ -240,12 +240,12 @@ const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph, Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval); - if ((me->runtime.edit_data != nullptr) && (me->runtime.edit_data->vertexCos != nullptr)) { + if ((me->runtime->edit_data != nullptr) && (me->runtime->edit_data->vertexCos != nullptr)) { /* Deformed, and we have deformed coords already. */ - coords = me->runtime.edit_data->vertexCos; + coords = me->runtime->edit_data->vertexCos; } else if ((editmesh_eval_final != nullptr) && - (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) { + (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) { /* If this is an edit-mesh type, leave nullptr as we can use the vertex coords. */ } else { diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 228c27cedf7..d148d59a48b 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -13,6 +13,7 @@ #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" #include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" #include "FN_multi_function_builder.hh" @@ -213,11 +214,15 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, } /* Deselect loose vertices without corners that are still selected from the 'true' default. */ - for (const int vert_index : IndexRange(mesh.totvert)) { - if (loose_verts[vert_index]) { - r_values[vert_index] = false; + /* The record fact says that the value is true. + *Writing to the array from different threads is okay because each thread sets the same value. */ + threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) { + for (const int vert_index : range) { + if (loose_verts[vert_index]) { + r_values[vert_index] = false; + } } - } + }); } static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray) @@ -413,16 +418,16 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, const Span<MLoop> loops = mesh.loops(); r_values.fill(false); - for (const int poly_index : polys.index_range()) { - const MPoly &poly = polys[poly_index]; - if (old_values[poly_index]) { - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = loops[loop_index]; - const int vert_index = loop.v; - r_values[vert_index] = true; + threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) { + for (const int poly_index : range) { + if (old_values[poly_index]) { + const MPoly &poly = polys[poly_index]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + r_values[loop.v] = true; + } } } - } + }); } static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray) @@ -502,16 +507,16 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, const Span<MLoop> loops = mesh.loops(); r_values.fill(false); - for (const int poly_index : polys.index_range()) { - const MPoly &poly = polys[poly_index]; - if (old_values[poly_index]) { - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = loops[loop_index]; - const int edge_index = loop.e; - r_values[edge_index] = true; + threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) { + for (const int poly_index : range) { + if (old_values[poly_index]) { + const MPoly &poly = polys[poly_index]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + r_values[loop.e] = true; + } } } - } + }); } static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray) @@ -619,7 +624,7 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, /* For every corner, mix the values from the adjacent edges on the face. */ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop; + const int loop_index_prev = mesh_topology::previous_poly_loop(poly, loop_index); const MLoop &loop = loops[loop_index]; const MLoop &loop_prev = loops[loop_index_prev]; mixer.mix_in(loop_index, old_values[loop.e]); @@ -642,17 +647,19 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, r_values.fill(false); - for (const int poly_index : polys.index_range()) { - const MPoly &poly = polys[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop; - const MLoop &loop = loops[loop_index]; - const MLoop &loop_prev = loops[loop_index_prev]; - if (old_values[loop.e] && old_values[loop_prev.e]) { - r_values[loop_index] = true; + threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) { + for (const int poly_index : range) { + const MPoly &poly = polys[poly_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const int loop_index_prev = mesh_topology::previous_poly_loop(poly, loop_index); + const MLoop &loop = loops[loop_index]; + const MLoop &loop_prev = loops[loop_index_prev]; + if (old_values[loop.e] && old_values[loop_prev.e]) { + r_values[loop_index] = true; + } } } - } + }); } static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray) @@ -697,14 +704,18 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, BLI_assert(r_values.size() == mesh.totvert); const Span<MEdge> edges = mesh.edges(); + /* Multiple threads can write to the same index here, but they are only + * writing true, and writing to single bytes is expected to be threadsafe. */ r_values.fill(false); - for (const int edge_index : edges.index_range()) { - const MEdge &edge = edges[edge_index]; - if (old_values[edge_index]) { - r_values[edge.v1] = true; - r_values[edge.v2] = true; + threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) { + for (const int edge_index : range) { + if (old_values[edge_index]) { + const MEdge &edge = edges[edge_index]; + r_values[edge.v1] = true; + r_values[edge.v2] = true; + } } - } + }); } static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray) diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index 92b11ecaa61..52fcdef8a43 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -1856,6 +1856,10 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps) pt->strength = interpf(pt2->strength, pt1->strength, step); pt->flag = 0; interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step); + /* Set point as selected. */ + if (gps->flag & GP_STROKE_SELECT) { + pt->flag |= GP_SPOINT_SELECT; + } /* Set weights. */ if (gps->dvert != nullptr) { diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc index 5e8d2bc6d76..bb3713e770a 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.cc +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -1498,7 +1498,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) for (int i = 0; i < mesh->totvert; i++) { normalize_v3(process.no[i]); } - mesh->runtime.vert_normals = process.no; + mesh->runtime->vert_normals = process.no; BKE_mesh_vertex_normals_clear_dirty(mesh); mesh->totloop = loop_offset; diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 9e7821428d1..0018c217964 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -89,7 +89,7 @@ static void mesh_init_data(ID *id) CustomData_reset(&mesh->pdata); CustomData_reset(&mesh->ldata); - BKE_mesh_runtime_init_data(mesh); + mesh->runtime = new blender::bke::MeshRuntime(); /* A newly created mesh does not have normals, so tag them dirty. This will be cleared * by #BKE_mesh_vertex_normals_clear_dirty or #BKE_mesh_poly_normals_ensure. */ @@ -103,14 +103,19 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int Mesh *mesh_dst = (Mesh *)id_dst; const Mesh *mesh_src = (const Mesh *)id_src; - BKE_mesh_runtime_reset_on_copy(mesh_dst, flag); + mesh_dst->runtime = new blender::bke::MeshRuntime(); + mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only; + mesh_dst->runtime->wrapper_type = mesh_src->runtime->wrapper_type; + mesh_dst->runtime->wrapper_type_finalize = mesh_src->runtime->wrapper_type_finalize; + mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data; + mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra; /* Copy face dot tags, since meshes may be duplicated after a subsurf modifier * or node, but we still need to be able to draw face center vertices. */ - mesh_dst->runtime.subsurf_face_dot_tags = static_cast<uint32_t *>( - MEM_dupallocN(mesh_src->runtime.subsurf_face_dot_tags)); + mesh_dst->runtime->subsurf_face_dot_tags = static_cast<uint32_t *>( + MEM_dupallocN(mesh_src->runtime->subsurf_face_dot_tags)); if ((mesh_src->id.tag & LIB_TAG_NO_MAIN) == 0) { /* This is a direct copy of a main mesh, so for now it has the same topology. */ - mesh_dst->runtime.deformed_only = true; + mesh_dst->runtime->deformed_only = true; } /* This option is set for run-time meshes that have been copied from the current objects mode. * Currently this is used for edit-mesh although it could be used for sculpt or other @@ -121,7 +126,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int * * While this could be the callers responsibility, keep here since it's * highly unlikely we want to create a duplicate and not use it for drawing. */ - mesh_dst->runtime.is_original_bmesh = false; + mesh_dst->runtime->is_original_bmesh = false; /* Only do tessface if we have no polys. */ const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0)); @@ -194,6 +199,8 @@ static void mesh_free_data(ID *id) BKE_mesh_runtime_free_data(mesh); mesh_clear_geometry(mesh); MEM_SAFE_FREE(mesh->mat); + + delete mesh->runtime; } static void mesh_foreach_id(ID *id, LibraryForeachIDData *data) @@ -229,7 +236,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address mesh->mface = nullptr; mesh->totface = 0; memset(&mesh->fdata, 0, sizeof(mesh->fdata)); - mesh->runtime = blender::dna::shallow_zero_initialize(); + mesh->runtime = nullptr; /* Do not store actual geometry data in case this is a library override ID. */ if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { @@ -339,8 +346,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; mesh->edit_mesh = nullptr; - mesh->runtime = blender::dna::shallow_zero_initialize(); - BKE_mesh_runtime_init_data(mesh); + mesh->runtime = new blender::bke::MeshRuntime(); /* happens with old files */ if (mesh->mselect == nullptr) { @@ -1137,7 +1143,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size) void BKE_mesh_ensure_default_orig_index_customdata(Mesh *mesh) { - BLI_assert(mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA); + BLI_assert(mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA); BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh); } @@ -2106,8 +2112,8 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) } /* Update normals manually to avoid recalculation after this operation. */ - mesh->runtime.vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime.vert_normals, - sizeof(float[3]) * mesh->totvert); + mesh->runtime->vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime->vert_normals, + sizeof(float[3]) * mesh->totvert); /* Perform actual split of vertices and edges. */ split_faces_split_new_verts(mesh, new_verts, num_new_verts); @@ -2141,10 +2147,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) /* We are here because something did change in the mesh. This means we can not trust the existing * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the * evaluated mesh and let objects to re-create it with updated settings. */ - if (mesh->runtime.mesh_eval != nullptr) { - mesh->runtime.mesh_eval->edit_mesh = nullptr; - BKE_id_free(nullptr, mesh->runtime.mesh_eval); - mesh->runtime.mesh_eval = nullptr; + if (mesh->runtime->mesh_eval != nullptr) { + mesh->runtime->mesh_eval->edit_mesh = nullptr; + BKE_id_free(nullptr, mesh->runtime->mesh_eval); + mesh->runtime->mesh_eval = nullptr; } if (DEG_is_active(depsgraph)) { Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index b4f729ca507..027423f5774 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -903,7 +903,7 @@ static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh) { /* While we could copy this into the new mesh, * add the data to 'mesh' so future calls to this function don't need to re-convert the data. */ - if (mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { BKE_mesh_wrapper_ensure_mdata(mesh); } else { diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc index ba4f25c74ee..6cf237a7c8c 100644 --- a/source/blender/blenkernel/intern/mesh_debug.cc +++ b/source/blender/blenkernel/intern/mesh_debug.cc @@ -41,9 +41,9 @@ char *BKE_mesh_debug_info(const Mesh *me) BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me->totface); BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly); - BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only); + BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime->deformed_only); BLI_dynstr_appendf( - dynstr, " 'runtime.is_original_bmesh': %d,\n", me->runtime.is_original_bmesh); + dynstr, " 'runtime->is_original_bmesh': %d,\n", me->runtime->is_original_bmesh); BLI_dynstr_append(dynstr, " 'vert_layers': (\n"); CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr); diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc index 5369bc782b6..960e6c43103 100644 --- a/source/blender/blenkernel/intern/mesh_fair.cc +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -221,7 +221,7 @@ class MeshFairingContext : public FairingContext { } } - loop_to_poly_map_ = blender::mesh_topology::build_loop_to_poly_map(mpoly_, mloop_.size()); + loop_to_poly_map_ = blender::bke::mesh_topology::build_loop_to_poly_map(mpoly_, mloop_.size()); } ~MeshFairingContext() override diff --git a/source/blender/blenkernel/intern/mesh_iterators.cc b/source/blender/blenkernel/intern/mesh_iterators.cc index 46f9780f891..a99e9b2348d 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.cc +++ b/source/blender/blenkernel/intern/mesh_iterators.cc @@ -36,18 +36,18 @@ void BKE_mesh_foreach_mapped_vert( void *userData, MeshForeachFlag flag) { - if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) { + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMVert *eve; int i; - if (mesh->runtime.edit_data->vertexCos != nullptr) { - const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; + if (mesh->runtime->edit_data->vertexCos != nullptr) { + const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos; const float(*vertexNos)[3]; if (flag & MESH_FOREACH_USE_NORMAL) { - BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime.edit_data); - vertexNos = mesh->runtime.edit_data->vertexNos; + BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime->edit_data); + vertexNos = mesh->runtime->edit_data->vertexNos; } else { vertexNos = nullptr; @@ -96,14 +96,14 @@ void BKE_mesh_foreach_mapped_edge( void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), void *userData) { - if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) { + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMEdge *eed; int i; - if (mesh->runtime.edit_data->vertexCos != nullptr) { - const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; + if (mesh->runtime->edit_data->vertexCos != nullptr) { + const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos; BM_mesh_elem_index_ensure(bm, BM_VERT); BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { @@ -154,13 +154,13 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, /* We can't use `dm->getLoopDataLayout(dm)` here, * we want to always access `dm->loopData`, `EditDerivedBMesh` would * return loop data from BMesh itself. */ - if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) { + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMFace *efa; - const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; + const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos; /* XXX: investigate using EditMesh data. */ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? @@ -231,7 +231,7 @@ void BKE_mesh_foreach_mapped_face_center( void *userData, MeshForeachFlag flag) { - if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) { + if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; const float(*polyCos)[3]; @@ -240,12 +240,12 @@ void BKE_mesh_foreach_mapped_face_center( BMIter iter; int i; - BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime.edit_data); - polyCos = mesh->runtime.edit_data->polyCos; /* always set */ + BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime->edit_data); + polyCos = mesh->runtime->edit_data->polyCos; /* always set */ if (flag & MESH_FOREACH_USE_NORMAL) { - BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime.edit_data); - polyNos = mesh->runtime.edit_data->polyNos; /* maybe nullptr */ + BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime->edit_data); + polyNos = mesh->runtime->edit_data->polyNos; /* maybe nullptr */ } else { polyNos = nullptr; @@ -317,7 +317,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( BKE_mesh_vertex_normals_ensure(mesh) : nullptr; const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); - const BLI_bitmap *facedot_tags = mesh->runtime.subsurf_face_dot_tags; + const BLI_bitmap *facedot_tags = mesh->runtime->subsurf_face_dot_tags; BLI_assert(facedot_tags != nullptr); if (index) { @@ -364,7 +364,7 @@ struct MappedVCosData { static void get_vertexcos__mapFunc(void *user_data, int index, const float co[3], - const float UNUSED(no[3])) + const float /*no*/[3]) { MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data; diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc index 667802d5f48..ed4ae94da7f 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.cc +++ b/source/blender/blenkernel/intern/mesh_mapping.cc @@ -553,7 +553,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map, *r_mem = indices; } -namespace blender::mesh_topology { +namespace blender::bke::mesh_topology { Array<int> build_loop_to_poly_map(const Span<MPoly> polys, const int loops_num) { @@ -586,7 +586,7 @@ Array<Vector<int>> build_vert_to_loop_map(const Span<MLoop> loops, const int ver return map; } -} // namespace blender::mesh_topology +} // namespace blender::bke::mesh_topology /** \} */ diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index e589aff1c73..ebb5a72d137 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -95,72 +95,72 @@ static void add_v3_v3_atomic(float r[3], const float a[3]) void BKE_mesh_normals_tag_dirty(Mesh *mesh) { - mesh->runtime.vert_normals_dirty = true; - mesh->runtime.poly_normals_dirty = true; + mesh->runtime->vert_normals_dirty = true; + mesh->runtime->poly_normals_dirty = true; } float (*BKE_mesh_vertex_normals_for_write(Mesh *mesh))[3] { - if (mesh->runtime.vert_normals == nullptr) { - mesh->runtime.vert_normals = (float(*)[3])MEM_malloc_arrayN( + if (mesh->runtime->vert_normals == nullptr) { + mesh->runtime->vert_normals = (float(*)[3])MEM_malloc_arrayN( mesh->totvert, sizeof(float[3]), __func__); } - BLI_assert(MEM_allocN_len(mesh->runtime.vert_normals) >= sizeof(float[3]) * mesh->totvert); + BLI_assert(MEM_allocN_len(mesh->runtime->vert_normals) >= sizeof(float[3]) * mesh->totvert); - return mesh->runtime.vert_normals; + return mesh->runtime->vert_normals; } float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3] { - if (mesh->runtime.poly_normals == nullptr) { - mesh->runtime.poly_normals = (float(*)[3])MEM_malloc_arrayN( + if (mesh->runtime->poly_normals == nullptr) { + mesh->runtime->poly_normals = (float(*)[3])MEM_malloc_arrayN( mesh->totpoly, sizeof(float[3]), __func__); } - BLI_assert(MEM_allocN_len(mesh->runtime.poly_normals) >= sizeof(float[3]) * mesh->totpoly); + BLI_assert(MEM_allocN_len(mesh->runtime->poly_normals) >= sizeof(float[3]) * mesh->totpoly); - return mesh->runtime.poly_normals; + return mesh->runtime->poly_normals; } void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh) { - mesh->runtime.vert_normals_dirty = false; + mesh->runtime->vert_normals_dirty = false; BKE_mesh_assert_normals_dirty_or_calculated(mesh); } void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh) { - mesh->runtime.poly_normals_dirty = false; + mesh->runtime->poly_normals_dirty = false; BKE_mesh_assert_normals_dirty_or_calculated(mesh); } bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh) { - return mesh->runtime.vert_normals_dirty; + return mesh->runtime->vert_normals_dirty; } bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh) { - return mesh->runtime.poly_normals_dirty; + return mesh->runtime->poly_normals_dirty; } void BKE_mesh_clear_derived_normals(Mesh *mesh) { - MEM_SAFE_FREE(mesh->runtime.vert_normals); - MEM_SAFE_FREE(mesh->runtime.poly_normals); + MEM_SAFE_FREE(mesh->runtime->vert_normals); + MEM_SAFE_FREE(mesh->runtime->poly_normals); - mesh->runtime.vert_normals_dirty = true; - mesh->runtime.poly_normals_dirty = true; + mesh->runtime->vert_normals_dirty = true; + mesh->runtime->poly_normals_dirty = true; } void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh) { - if (!mesh->runtime.vert_normals_dirty) { - BLI_assert(mesh->runtime.vert_normals || mesh->totvert == 0); + if (!mesh->runtime->vert_normals_dirty) { + BLI_assert(mesh->runtime->vert_normals || mesh->totvert == 0); } - if (!mesh->runtime.poly_normals_dirty) { - BLI_assert(mesh->runtime.poly_normals || mesh->totpoly == 0); + if (!mesh->runtime->poly_normals_dirty) { + BLI_assert(mesh->runtime->poly_normals || mesh->totpoly == 0); } } @@ -348,20 +348,18 @@ void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert, const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] { if (!BKE_mesh_vertex_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0); - return mesh->runtime.vert_normals; + BLI_assert(mesh->runtime->vert_normals != nullptr || mesh->totvert == 0); + return mesh->runtime->vert_normals; } if (mesh->totvert == 0) { return nullptr; } - ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex; - BLI_mutex_lock(normals_mutex); + std::lock_guard lock{mesh->runtime->normals_mutex}; if (!BKE_mesh_vertex_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime.vert_normals != nullptr); - BLI_mutex_unlock(normals_mutex); - return mesh->runtime.vert_normals; + BLI_assert(mesh->runtime->vert_normals != nullptr); + return mesh->runtime->vert_normals; } float(*vert_normals)[3]; @@ -390,27 +388,24 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] BKE_mesh_poly_normals_clear_dirty(&mesh_mutable); }); - BLI_mutex_unlock(normals_mutex); return vert_normals; } const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3] { if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime.poly_normals != nullptr || mesh->totpoly == 0); - return mesh->runtime.poly_normals; + BLI_assert(mesh->runtime->poly_normals != nullptr || mesh->totpoly == 0); + return mesh->runtime->poly_normals; } if (mesh->totpoly == 0) { return nullptr; } - ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex; - BLI_mutex_lock(normals_mutex); + std::lock_guard lock{mesh->runtime->normals_mutex}; if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime.poly_normals != nullptr); - BLI_mutex_unlock(normals_mutex); - return mesh->runtime.poly_normals; + BLI_assert(mesh->runtime->poly_normals != nullptr); + return mesh->runtime->poly_normals; } float(*poly_normals)[3]; @@ -435,13 +430,12 @@ const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3] BKE_mesh_poly_normals_clear_dirty(&mesh_mutable); }); - BLI_mutex_unlock(normals_mutex); return poly_normals; } void BKE_mesh_ensure_normals_for_display(Mesh *mesh) { - switch ((eMeshWrapperType)mesh->runtime.wrapper_type) { + switch (mesh->runtime->wrapper_type) { case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: BKE_mesh_vertex_normals_ensure(mesh); @@ -449,7 +443,7 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) break; case ME_WRAPPER_TYPE_BMESH: { struct BMEditMesh *em = mesh->edit_mesh; - EditMeshData *emd = mesh->runtime.edit_data; + EditMeshData *emd = mesh->runtime->edit_data; if (emd->vertexCos) { BKE_editmesh_cache_ensure_vert_normals(em, emd); BKE_editmesh_cache_ensure_poly_normals(em, emd); @@ -470,7 +464,7 @@ void BKE_mesh_calc_normals(Mesh *mesh) #endif } -void BKE_mesh_calc_normals_looptri(MVert *mverts, +void BKE_mesh_calc_normals_looptri(const MVert *mverts, int numVerts, const MLoop *mloop, const MLoopTri *looptri, @@ -508,7 +502,7 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts, /* Following Mesh convention; we use vertex coordinate itself for normal in this case. */ for (int i = 0; i < numVerts; i++) { - MVert *mv = &mverts[i]; + const MVert *mv = &mverts[i]; float *no = tnorms[i]; if (UNLIKELY(normalize_v3(no) == 0.0f)) { diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index cb05d33bc2e..90798ea593d 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -1529,7 +1529,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, BLI_bitmap *looptri_active; looptri_src = BKE_mesh_runtime_looptri_ensure(me_src); - num_looptri_src = me_src->runtime.looptris.len; + num_looptri_src = BKE_mesh_runtime_looptri_len(me_src); looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__); for (tindex = 0; tindex < num_trees; tindex++) { diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc index bd9f8242274..e90a298ad8d 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.cc +++ b/source/blender/blenkernel/intern/mesh_runtime.cc @@ -17,6 +17,7 @@ #include "BLI_task.hh" #include "BKE_bvhutils.h" +#include "BKE_editmesh_cache.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" @@ -30,81 +31,17 @@ using blender::Span; /** \name Mesh Runtime Struct Utils * \{ */ -/** - * \brief Initialize the runtime mutexes of the given mesh. - * - * Any existing mutexes will be overridden. - */ -static void mesh_runtime_init_mutexes(Mesh *mesh) -{ - mesh->runtime.eval_mutex = MEM_new<ThreadMutex>("mesh runtime eval_mutex"); - BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex)); - mesh->runtime.normals_mutex = MEM_new<ThreadMutex>("mesh runtime normals_mutex"); - BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex)); - mesh->runtime.render_mutex = MEM_new<ThreadMutex>("mesh runtime render_mutex"); - BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.render_mutex)); -} - -/** - * \brief free the mutexes of the given mesh runtime. - */ -static void mesh_runtime_free_mutexes(Mesh *mesh) -{ - if (mesh->runtime.eval_mutex != nullptr) { - BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex)); - MEM_freeN(mesh->runtime.eval_mutex); - mesh->runtime.eval_mutex = nullptr; - } - if (mesh->runtime.normals_mutex != nullptr) { - BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex)); - MEM_freeN(mesh->runtime.normals_mutex); - mesh->runtime.normals_mutex = nullptr; - } - if (mesh->runtime.render_mutex != nullptr) { - BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.render_mutex)); - MEM_freeN(mesh->runtime.render_mutex); - mesh->runtime.render_mutex = nullptr; - } -} - -void BKE_mesh_runtime_init_data(Mesh *mesh) -{ - mesh_runtime_init_mutexes(mesh); -} - void BKE_mesh_runtime_free_data(Mesh *mesh) { BKE_mesh_runtime_clear_cache(mesh); - mesh_runtime_free_mutexes(mesh); -} - -void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int /*flag*/) -{ - Mesh_Runtime *runtime = &mesh->runtime; - - runtime->mesh_eval = nullptr; - runtime->edit_data = nullptr; - runtime->batch_cache = nullptr; - runtime->subdiv_ccg = nullptr; - runtime->looptris = blender::dna::shallow_zero_initialize(); - runtime->bvh_cache = nullptr; - runtime->shrinkwrap_data = nullptr; - runtime->subsurf_face_dot_tags = nullptr; - - runtime->vert_normals_dirty = true; - runtime->poly_normals_dirty = true; - runtime->vert_normals = nullptr; - runtime->poly_normals = nullptr; - - mesh_runtime_init_mutexes(mesh); } void BKE_mesh_runtime_clear_cache(Mesh *mesh) { - if (mesh->runtime.mesh_eval != nullptr) { - mesh->runtime.mesh_eval->edit_mesh = nullptr; - BKE_id_free(nullptr, mesh->runtime.mesh_eval); - mesh->runtime.mesh_eval = nullptr; + if (mesh->runtime->mesh_eval != nullptr) { + mesh->runtime->mesh_eval->edit_mesh = nullptr; + BKE_id_free(nullptr, mesh->runtime->mesh_eval); + mesh->runtime->mesh_eval = nullptr; } BKE_mesh_runtime_clear_geometry(mesh); BKE_mesh_batch_cache_free(mesh); @@ -131,32 +68,32 @@ static void mesh_ensure_looptri_data(Mesh *mesh) const uint totpoly = mesh->totpoly; const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop); - BLI_assert(mesh->runtime.looptris.array_wip == nullptr); + BLI_assert(mesh->runtime->looptris.array_wip == nullptr); - SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip); + SWAP(MLoopTri *, mesh->runtime->looptris.array, mesh->runtime->looptris.array_wip); - if ((looptris_len > mesh->runtime.looptris.len_alloc) || - (looptris_len < mesh->runtime.looptris.len_alloc * 2) || (totpoly == 0)) { - MEM_SAFE_FREE(mesh->runtime.looptris.array_wip); - mesh->runtime.looptris.len_alloc = 0; - mesh->runtime.looptris.len = 0; + if ((looptris_len > mesh->runtime->looptris.len_alloc) || + (looptris_len < mesh->runtime->looptris.len_alloc * 2) || (totpoly == 0)) { + MEM_SAFE_FREE(mesh->runtime->looptris.array_wip); + mesh->runtime->looptris.len_alloc = 0; + mesh->runtime->looptris.len = 0; } if (totpoly) { - if (mesh->runtime.looptris.array_wip == nullptr) { - mesh->runtime.looptris.array_wip = static_cast<MLoopTri *>( - MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__)); - mesh->runtime.looptris.len_alloc = looptris_len; + if (mesh->runtime->looptris.array_wip == nullptr) { + mesh->runtime->looptris.array_wip = static_cast<MLoopTri *>( + MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime->looptris.array_wip), __func__)); + mesh->runtime->looptris.len_alloc = looptris_len; } - mesh->runtime.looptris.len = looptris_len; + mesh->runtime->looptris.len = looptris_len; } } void BKE_mesh_runtime_looptri_recalc(Mesh *mesh) { mesh_ensure_looptri_data(mesh); - BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != nullptr); + BLI_assert(mesh->totpoly == 0 || mesh->runtime->looptris.array_wip != nullptr); const Span<MVert> verts = mesh->verts(); const Span<MPoly> polys = mesh->polys(); const Span<MLoop> loops = mesh->loops(); @@ -167,7 +104,7 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh) verts.data(), mesh->totloop, mesh->totpoly, - mesh->runtime.looptris.array_wip, + mesh->runtime->looptris.array_wip, BKE_mesh_poly_normals_ensure(mesh)); } else { @@ -176,43 +113,40 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh) verts.data(), mesh->totloop, mesh->totpoly, - mesh->runtime.looptris.array_wip); + mesh->runtime->looptris.array_wip); } - BLI_assert(mesh->runtime.looptris.array == nullptr); - atomic_cas_ptr((void **)&mesh->runtime.looptris.array, - mesh->runtime.looptris.array, - mesh->runtime.looptris.array_wip); - mesh->runtime.looptris.array_wip = nullptr; + BLI_assert(mesh->runtime->looptris.array == nullptr); + atomic_cas_ptr((void **)&mesh->runtime->looptris.array, + mesh->runtime->looptris.array, + mesh->runtime->looptris.array_wip); + mesh->runtime->looptris.array_wip = nullptr; } int BKE_mesh_runtime_looptri_len(const Mesh *mesh) { /* This is a ported copy of `dm_getNumLoopTri(dm)`. */ const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop); - BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len)); + BLI_assert(ELEM(mesh->runtime->looptris.len, 0, looptri_len)); return looptri_len; } const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh) { - ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; - BLI_mutex_lock(mesh_eval_mutex); + std::lock_guard lock{mesh->runtime->eval_mutex}; - MLoopTri *looptri = mesh->runtime.looptris.array; + MLoopTri *looptri = mesh->runtime->looptris.array; if (looptri != nullptr) { - BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len); + BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime->looptris.len); } else { /* Must isolate multithreaded tasks while holding a mutex lock. */ blender::threading::isolate_task( [&]() { BKE_mesh_runtime_looptri_recalc(const_cast<Mesh *>(mesh)); }); - looptri = mesh->runtime.looptris.array; + looptri = mesh->runtime->looptris.array; } - BLI_mutex_unlock(mesh_eval_mutex); - return looptri; } @@ -230,17 +164,17 @@ void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri, bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh) { - if (mesh->runtime.edit_data != nullptr) { + if (mesh->runtime->edit_data != nullptr) { return false; } - mesh->runtime.edit_data = MEM_cnew<EditMeshData>(__func__); + mesh->runtime->edit_data = MEM_cnew<EditMeshData>(__func__); return true; } bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh) { - EditMeshData *edit_data = mesh->runtime.edit_data; + EditMeshData *edit_data = mesh->runtime->edit_data; if (edit_data == nullptr) { return false; } @@ -255,13 +189,13 @@ bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh) bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh) { - if (mesh->runtime.edit_data == nullptr) { + if (mesh->runtime->edit_data == nullptr) { return false; } BKE_mesh_runtime_reset_edit_data(mesh); - MEM_freeN(mesh->runtime.edit_data); - mesh->runtime.edit_data = nullptr; + MEM_freeN(mesh->runtime->edit_data); + mesh->runtime->edit_data = nullptr; return true; } @@ -271,22 +205,22 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) BKE_mesh_tag_coords_changed(mesh); /* TODO(sergey): Does this really belong here? */ - if (mesh->runtime.subdiv_ccg != nullptr) { - BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg); - mesh->runtime.subdiv_ccg = nullptr; + if (mesh->runtime->subdiv_ccg != nullptr) { + BKE_subdiv_ccg_destroy(mesh->runtime->subdiv_ccg); + mesh->runtime->subdiv_ccg = nullptr; } BKE_shrinkwrap_discard_boundary_data(mesh); - MEM_SAFE_FREE(mesh->runtime.subsurf_face_dot_tags); + MEM_SAFE_FREE(mesh->runtime->subsurf_face_dot_tags); } void BKE_mesh_tag_coords_changed(Mesh *mesh) { BKE_mesh_normals_tag_dirty(mesh); - MEM_SAFE_FREE(mesh->runtime.looptris.array); - if (mesh->runtime.bvh_cache) { - bvhcache_free(mesh->runtime.bvh_cache); - mesh->runtime.bvh_cache = nullptr; + MEM_SAFE_FREE(mesh->runtime->looptris.array); + if (mesh->runtime->bvh_cache) { + bvhcache_free(mesh->runtime->bvh_cache); + mesh->runtime->bvh_cache = nullptr; } } @@ -305,6 +239,16 @@ void BKE_mesh_tag_coords_changed_uniformly(Mesh *mesh) } } +bool BKE_mesh_is_deformed_only(const Mesh *mesh) +{ + return mesh->runtime->deformed_only; +} + +eMeshWrapperType BKE_mesh_wrapper_type(const struct Mesh *mesh) +{ + return mesh->runtime->wrapper_type; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -317,13 +261,13 @@ void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = nullptr; void BKE_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) { - if (me->runtime.batch_cache) { + if (me->runtime->batch_cache) { BKE_mesh_batch_cache_dirty_tag_cb(me, mode); } } void BKE_mesh_batch_cache_free(Mesh *me) { - if (me->runtime.batch_cache) { + if (me->runtime->batch_cache) { BKE_mesh_batch_cache_free_cb(me); } } diff --git a/source/blender/blenkernel/intern/mesh_tangent.cc b/source/blender/blenkernel/intern/mesh_tangent.cc index 1162986aaf5..49ea23a1552 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.cc +++ b/source/blender/blenkernel/intern/mesh_tangent.cc @@ -570,8 +570,6 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval, const char (*tangent_names)[MAX_NAME], int tangent_names_len) { - BKE_mesh_runtime_looptri_ensure(me_eval); - /* TODO(@campbellbarton): store in Mesh.runtime to avoid recalculation. */ short tangent_mask = 0; BKE_mesh_calc_loop_tangent_ex( @@ -579,8 +577,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval, BKE_mesh_polys(me_eval), uint(me_eval->totpoly), BKE_mesh_loops(me_eval), - me_eval->runtime.looptris.array, - uint(me_eval->runtime.looptris.len), + BKE_mesh_runtime_looptri_ensure(me_eval), + uint(BKE_mesh_runtime_looptri_len(me_eval)), &me_eval->ldata, calc_active_tangent, tangent_names, diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index 101fad2fce8..61a95fb4d0e 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -57,13 +57,13 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, BKE_mesh_copy_parameters_for_eval(me, me_settings); BKE_mesh_runtime_ensure_edit_data(me); - me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH; + me->runtime->wrapper_type = ME_WRAPPER_TYPE_BMESH; if (cd_mask_extra) { - me->runtime.cd_mask_extra = *cd_mask_extra; + me->runtime->cd_mask_extra = *cd_mask_extra; } /* Use edit-mesh directly where possible. */ - me->runtime.is_original_bmesh = true; + me->runtime->is_original_bmesh = true; me->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(em)); me->edit_mesh->is_shallow_copy = true; @@ -81,7 +81,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, me->totloop = 0; #endif - EditMeshData *edit_data = me->runtime.edit_data; + EditMeshData *edit_data = me->runtime->edit_data; edit_data->vertexCos = vert_coords; return me; } @@ -95,17 +95,14 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em, void BKE_mesh_wrapper_ensure_mdata(Mesh *me) { - ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex; - BLI_mutex_lock(mesh_eval_mutex); - - if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { - BLI_mutex_unlock(mesh_eval_mutex); + std::lock_guard lock{me->runtime->eval_mutex}; + if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) { return; } /* Must isolate multithreaded tasks while holding a mutex lock. */ blender::threading::isolate_task([&]() { - switch (static_cast<eMeshWrapperType>(me->runtime.wrapper_type)) { + switch (static_cast<eMeshWrapperType>(me->runtime->wrapper_type)) { case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_SUBD: { break; /* Quiet warning. */ @@ -117,10 +114,10 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me) me->totloop = 0; BLI_assert(me->edit_mesh != nullptr); - BLI_assert(me->runtime.edit_data != nullptr); + BLI_assert(me->runtime->edit_data != nullptr); BMEditMesh *em = me->edit_mesh; - BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra); + BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime->cd_mask_extra); /* Adding original index layers assumes that all BMesh mesh wrappers are created from * original edit mode meshes (the only case where adding original indices makes sense). @@ -132,32 +129,30 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me) * harmful. */ BKE_mesh_ensure_default_orig_index_customdata_no_check(me); - EditMeshData *edit_data = me->runtime.edit_data; + EditMeshData *edit_data = me->runtime->edit_data; if (edit_data->vertexCos) { BKE_mesh_vert_coords_apply(me, edit_data->vertexCos); - me->runtime.is_original_bmesh = false; + me->runtime->is_original_bmesh = false; } break; } } - if (me->runtime.wrapper_type_finalize) { - BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime.cd_mask_extra); + if (me->runtime->wrapper_type_finalize) { + BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime->cd_mask_extra); } /* Keep type assignment last, so that read-only access only uses the mdata code paths after all * the underlying data has been initialized. */ - me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA; + me->runtime->wrapper_type = ME_WRAPPER_TYPE_MDATA; }); - - BLI_mutex_unlock(mesh_eval_mutex); } bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3]) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: - return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max); + return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime->edit_data, min, max); case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_SUBD: return BKE_mesh_minmax(me, min, max); @@ -174,11 +169,11 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me, float (*vert_coords)[3], int vert_coords_len) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: { BMesh *bm = me->edit_mesh->bm; BLI_assert(vert_coords_len <= bm->totvert); - EditMeshData *edit_data = me->runtime.edit_data; + EditMeshData *edit_data = me->runtime->edit_data; if (edit_data->vertexCos != nullptr) { for (int i = 0; i < vert_coords_len; i++) { copy_v3_v3(vert_coords[i], edit_data->vertexCos[i]); @@ -212,11 +207,11 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me, int vert_coords_len, const float mat[4][4]) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: { BMesh *bm = me->edit_mesh->bm; BLI_assert(vert_coords_len == bm->totvert); - EditMeshData *edit_data = me->runtime.edit_data; + EditMeshData *edit_data = me->runtime->edit_data; if (edit_data->vertexCos != nullptr) { for (int i = 0; i < vert_coords_len; i++) { mul_v3_m4v3(vert_coords[i], mat, edit_data->vertexCos[i]); @@ -253,7 +248,7 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me, int BKE_mesh_wrapper_vert_len(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totvert; case ME_WRAPPER_TYPE_MDATA: @@ -266,7 +261,7 @@ int BKE_mesh_wrapper_vert_len(const Mesh *me) int BKE_mesh_wrapper_edge_len(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totedge; case ME_WRAPPER_TYPE_MDATA: @@ -279,7 +274,7 @@ int BKE_mesh_wrapper_edge_len(const Mesh *me) int BKE_mesh_wrapper_loop_len(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totloop; case ME_WRAPPER_TYPE_MDATA: @@ -292,7 +287,7 @@ int BKE_mesh_wrapper_loop_len(const Mesh *me) int BKE_mesh_wrapper_poly_len(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totface; case ME_WRAPPER_TYPE_MDATA: @@ -311,7 +306,7 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me) static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me) { - SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)me->runtime.subsurf_runtime_data; + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)me->runtime->subsurf_runtime_data; if (runtime_data == nullptr || runtime_data->settings.level == 0) { return me; } @@ -359,24 +354,22 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me) } if (subdiv_mesh != me) { - if (me->runtime.mesh_eval != nullptr) { - BKE_id_free(nullptr, me->runtime.mesh_eval); + if (me->runtime->mesh_eval != nullptr) { + BKE_id_free(nullptr, me->runtime->mesh_eval); } - me->runtime.mesh_eval = subdiv_mesh; - me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD; + me->runtime->mesh_eval = subdiv_mesh; + me->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD; } - return me->runtime.mesh_eval; + return me->runtime->mesh_eval; } Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *me) { - ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex; - BLI_mutex_lock(mesh_eval_mutex); + std::lock_guard lock{me->runtime->eval_mutex}; - if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_SUBD) { - BLI_mutex_unlock(mesh_eval_mutex); - return me->runtime.mesh_eval; + if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) { + return me->runtime->mesh_eval; } Mesh *result; @@ -384,7 +377,6 @@ Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *me) /* Must isolate multithreaded tasks while holding a mutex lock. */ blender::threading::isolate_task([&]() { result = mesh_wrapper_ensure_subdivision(me); }); - BLI_mutex_unlock(mesh_eval_mutex); return result; } diff --git a/source/blender/blenkernel/intern/modifier.cc b/source/blender/blenkernel/intern/modifier.cc index 2eb8ef70a4d..fc1a0f47684 100644 --- a/source/blender/blenkernel/intern/modifier.cc +++ b/source/blender/blenkernel/intern/modifier.cc @@ -963,9 +963,9 @@ void BKE_modifier_path_init(char *path, int path_maxlen, const char *name) */ static void modwrap_dependsOnNormals(Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_BMESH: { - EditMeshData *edit_data = me->runtime.edit_data; + EditMeshData *edit_data = me->runtime->edit_data; if (edit_data->vertexCos) { /* Note that 'ensure' is acceptable here since these values aren't modified in-place. * If that changes we'll need to recalculate. */ @@ -993,7 +993,7 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md, { const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); - if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) { BKE_mesh_wrapper_ensure_mdata(me); } diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index 61cfe043927..5ff9602650e 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -397,7 +397,7 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod * In a longer term maybe special dependency graph tag can help sanitizing this a bit. */ Object *object_eval = DEG_get_evaluated_object(depsgraph, object); Mesh *mesh = static_cast<Mesh *>(object_eval->data); - SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg; + SubdivCCG *subdiv_ccg = mesh->runtime->subdiv_ccg; if (subdiv_ccg == nullptr) { return; } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index fd3580a7e88..ba63cdff917 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1272,6 +1272,34 @@ float BKE_nlastrip_compute_frame_to_next_strip(NlaStrip *strip) return limit_next; } +NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_transitions) +{ + NlaStrip *next = strip->next; + while (next != NULL) { + if (skip_transitions && (next->type & NLASTRIP_TYPE_TRANSITION)) { + next = next->next; + } + else { + return next; + } + } + return NULL; +} + +NlaStrip *BKE_nlastrip_prev_in_track(struct NlaStrip *strip, bool skip_transitions) +{ + NlaStrip *prev = strip->prev; + while (prev != NULL) { + if (skip_transitions && (prev->type & NLASTRIP_TYPE_TRANSITION)) { + prev = prev->prev; + } + else { + return prev; + } + } + return NULL; +} + NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt) { if (nlt == NULL) { diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 9417d1afc7e..2d949fb5c65 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1691,7 +1691,7 @@ static void object_update_from_subsurf_ccg(Object *object) if (mesh_eval == nullptr) { return; } - SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; + SubdivCCG *subdiv_ccg = mesh_eval->runtime->subdiv_ccg; if (subdiv_ccg == nullptr) { return; } @@ -1699,7 +1699,7 @@ static void object_update_from_subsurf_ccg(Object *object) if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) { return; } - const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level; + const int tot_level = mesh_eval->runtime->subdiv_ccg_tot_level; Object *object_orig = DEG_get_original_object(object); Mesh *mesh_orig = (Mesh *)object_orig->data; multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg); @@ -3218,7 +3218,7 @@ static void give_parvert(Object *par, int nr, float vec[3]) int count = 0; int numVerts = me_eval->totvert; - if (em && me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if (em && me_eval->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { numVerts = em->bm->totvert; if (em->bm->elem_table_dirty & BM_VERT) { #ifdef VPARENT_THREADING_HACK @@ -3233,8 +3233,8 @@ static void give_parvert(Object *par, int nr, float vec[3]) #endif } if (nr < numVerts) { - if (me_eval && me_eval->runtime.edit_data && me_eval->runtime.edit_data->vertexCos) { - add_v3_v3(vec, me_eval->runtime.edit_data->vertexCos[nr]); + if (me_eval && me_eval->runtime->edit_data && me_eval->runtime->edit_data->vertexCos) { + add_v3_v3(vec, me_eval->runtime->edit_data->vertexCos[nr]); } else { const BMVert *v = BM_vert_at_index(em->bm, nr); diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index a56176b7d9b..96da99af97e 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -57,10 +57,12 @@ #include "DEG_depsgraph_query.h" #include "BLI_hash.h" +#include "DNA_world_types.h" #include "NOD_geometry_nodes_log.hh" #include "RNA_access.h" #include "RNA_path.h" +#include "RNA_prototypes.h" #include "RNA_types.h" using blender::Array; @@ -421,8 +423,8 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob, /* Note that this will only show deformation if #eModifierMode_OnCage is enabled. * We could change this but it matches 2.7x behavior. */ me_eval = BKE_object_get_editmesh_eval_cage(ob); - if ((me_eval == nullptr) || (me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) { - EditMeshData *emd = me_eval ? me_eval->runtime.edit_data : nullptr; + if ((me_eval == nullptr) || (me_eval->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) { + EditMeshData *emd = me_eval ? me_eval->runtime->edit_data : nullptr; /* Only assign edit-mesh in the case we can't use `me_eval`. */ *r_em = em; @@ -1916,4 +1918,30 @@ bool BKE_object_dupli_find_rgba_attribute( return false; } +bool BKE_view_layer_find_rgba_attribute(struct Scene *scene, + struct ViewLayer *layer, + const char *name, + float r_value[4]) +{ + if (layer) { + PointerRNA layer_ptr; + RNA_pointer_create(&scene->id, &RNA_ViewLayer, layer, &layer_ptr); + + if (find_rna_property_rgba(&layer_ptr, name, r_value)) { + return true; + } + } + + if (find_rna_property_rgba(&scene->id, name, r_value)) { + return true; + } + + if (scene->world && find_rna_property_rgba(&scene->world->id, name, r_value)) { + return true; + } + + copy_v4_fl(r_value, 0.0f); + return false; +} + /** \} */ diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc index 5328d956cee..ceef6404bf0 100644 --- a/source/blender/blenkernel/intern/object_update.cc +++ b/source/blender/blenkernel/intern/object_update.cc @@ -373,10 +373,8 @@ void BKE_object_select_update(Depsgraph *depsgraph, Object *object) DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); if (object->type == OB_MESH && !object->runtime.is_data_eval_owned) { Mesh *mesh_input = (Mesh *)object->runtime.data_orig; - Mesh_Runtime *mesh_runtime = &mesh_input->runtime; - BLI_mutex_lock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex)); + std::lock_guard lock{mesh_input->runtime->eval_mutex}; BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data)); - BLI_mutex_unlock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex)); } else { BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data)); diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 00535ea5528..934cfb3cc46 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1743,7 +1743,7 @@ static void sculpt_update_object( ss->hide_poly = (bool *)CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".hide_poly"); - ss->subdiv_ccg = me_eval->runtime.subdiv_ccg; + ss->subdiv_ccg = me_eval->runtime->subdiv_ccg; PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob); BLI_assert(pbvh == ss->pbvh); @@ -2237,7 +2237,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect (void **)subdiv_ccg->grid_faces, subdiv_ccg->grid_flag_mats, subdiv_ccg->grid_hidden, - base_mesh); + base_mesh, + subdiv_ccg); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); return pbvh; @@ -2258,7 +2259,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); - SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; + SubdivCCG *subdiv_ccg = mesh_eval->runtime->subdiv_ccg; if (subdiv_ccg != nullptr) { BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg); } @@ -2277,8 +2278,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) else { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); - if (mesh_eval->runtime.subdiv_ccg != nullptr) { - pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide); + if (mesh_eval->runtime->subdiv_ccg != nullptr) { + pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg, respect_hide); } else if (ob->type == OB_MESH) { Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval; @@ -2287,9 +2288,9 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) } BKE_pbvh_pmap_set(pbvh, ob->sculpt->pmap); - sculpt_attribute_update_refs(ob); - ob->sculpt->pbvh = pbvh; + + sculpt_attribute_update_refs(ob); return pbvh; } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 6d42d344b86..d6dd3cf0dbb 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -60,6 +60,7 @@ #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mesh_legacy_convert.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -1933,7 +1934,7 @@ int psys_particle_dm_face_lookup(Mesh *mesh_final, index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX); } else { - BLI_assert(mesh_final->runtime.deformed_only); + BLI_assert(BKE_mesh_is_deformed_only(mesh_final)); index_mf_to_mpoly_deformed = index_mf_to_mpoly; } BLI_assert(index_mf_to_mpoly_deformed); @@ -2023,7 +2024,7 @@ static int psys_map_index_on_dm(Mesh *mesh, return 0; } - if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) { + if (BKE_mesh_is_deformed_only(mesh) || index_dmcache == DMCACHE_ISCHILD) { /* for meshes that are either only deformed or for child particles, the * index and fw do not require any mapping, so we can directly use it */ if (from == PART_FROM_VERT) { diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 4c56a8a9275..0301b83a043 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -29,6 +29,7 @@ #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_legacy_convert.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -899,7 +900,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, return 0; } - if (!final_mesh->runtime.deformed_only && + if (!BKE_mesh_is_deformed_only(final_mesh) && !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) { printf( "Can't create particles with the current modifier stack, disable destructive modifiers\n"); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index dec874caff4..c72bbe2fd08 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -48,6 +48,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_mesh_legacy_convert.h" +#include "BKE_mesh_runtime.h" #include "BKE_particle.h" #include "BKE_bvhutils.h" @@ -319,7 +320,7 @@ void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, Partic PARTICLE_P; /* CACHE LOCATIONS */ - if (!mesh_final->runtime.deformed_only) { + if (!BKE_mesh_is_deformed_only(mesh_final)) { /* Will use later to speed up subsurf/evaluated mesh. */ LinkNode *node, *nodedmelem, **nodearray; int totdmelem, totelem, i; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 075cfc5366f..2b989885ebc 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -39,8 +39,10 @@ #define LEAF_LIMIT 10000 -//#define PERFCNTRS +/* Uncomment to test that faces are only assigned to one PBVHNode */ +//#define VALIDATE_UNIQUE_NODE_FACES +//#define PERFCNTRS #define STACK_FIXED_DEPTH 100 typedef struct PBVHStack { @@ -422,6 +424,56 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) return false; } +static int adjust_partition_faces(PBVH *pbvh, int offset, int mid, int count) +{ + int poly = pbvh->looptri[pbvh->prim_indices[mid]].poly; + + /* Scan backwards. */ + while (mid > offset + 2) { /* First node should have at least 1 primitive */ + if (pbvh->looptri[pbvh->prim_indices[mid - 1]].poly != poly) { + return mid; + } + + mid--; + } + + /* If that didn't work try scanning forward. */ + while (mid < pbvh->totprim + count) { + if (pbvh->looptri[pbvh->prim_indices[mid]].poly != poly) { + break; + } + + mid++; + } + + return mid; +} + +static int adjust_partition_grids(PBVH *pbvh, int offset, int mid, int count) +{ + int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]); + + /* Scan backwards. */ + while (mid > offset + 2) { /* First node should have at least 1 primitive */ + if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid - 1]) != poly) { + return mid; + } + + mid--; + } + + /* If that didn't work try scanning forward. */ + while (mid < pbvh->totprim + count) { + if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]) != poly) { + break; + } + + mid++; + } + + return mid; +} + /* Recursively build a node in the tree * * vb is the voxel box around all of the primitives contained in @@ -478,6 +530,13 @@ static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int off end = partition_indices_material(pbvh, offset, offset + count - 1); } + if (pbvh->header.type == PBVH_FACES) { + end = adjust_partition_faces(pbvh, offset, end, count); + } + else { + end = adjust_partition_grids(pbvh, offset, end, count); + } + /* Build children */ build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset); build_sub(pbvh, @@ -587,6 +646,73 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node) } } +#ifdef VALIDATE_UNIQUE_NODE_FACES +static void pbvh_validate_node_prims(PBVH *pbvh) +{ + int totface = 0; + + if (pbvh->header.type == PBVH_BMESH) { + return; + } + + for (int i = 0; i < pbvh->totnode; i++) { + PBVHNode *node = pbvh->nodes + i; + + if (!(node->flag & PBVH_Leaf)) { + continue; + } + + for (int j = 0; j < node->totprim; j++) { + int poly; + + if (pbvh->header.type == PBVH_FACES) { + poly = pbvh->looptri[node->prim_indices[j]].poly; + } + else { + poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]); + } + + totface = max_ii(totface, poly + 1); + } + } + + int *facemap = (int *)MEM_malloc_arrayN(totface, sizeof(*facemap), __func__); + + for (int i = 0; i < totface; i++) { + facemap[i] = -1; + } + + for (int i = 0; i < pbvh->totnode; i++) { + PBVHNode *node = pbvh->nodes + i; + + if (!(node->flag & PBVH_Leaf)) { + continue; + } + + for (int j = 0; j < node->totprim; j++) { + int poly; + + if (pbvh->header.type == PBVH_FACES) { + poly = pbvh->looptri[node->prim_indices[j]].poly; + } + else { + poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]); + } + + if (facemap[poly] != -1 && facemap[poly] != i) { + printf("%s: error: face spanned multiple nodes (old: %d new: %d)\n", + __func__, + facemap[poly], + i); + } + + facemap[poly] = i; + } + } + MEM_SAFE_FREE(facemap); +} +#endif + void BKE_pbvh_build_mesh(PBVH *pbvh, Mesh *mesh, const MPoly *mpoly, @@ -645,6 +771,32 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, BB_expand(&cb, bbc->bcentroid); } + /* Ensure all primitives belonging to the same base face + * have the same bounds. This is needed to prevent them + * from being swapped away from each other inside the partition + * array. + */ + for (int i = 0; i < looptri_num; i++) { + const MLoopTri *lt = &looptri[i]; + int poly = lt->poly; + BBC *bbc = prim_bbc + i; + int j = i + 1; + + while (j < looptri_num && looptri[j].poly == poly) { + BBC *bbc2 = prim_bbc + j; + + BB_expand((BB *)bbc, bbc2->bmin); + BB_expand((BB *)bbc, bbc2->bmax); + j++; + } + + j = i + 1; + while (j < looptri_num && looptri[j].poly == poly) { + prim_bbc[j] = prim_bbc[i]; + j++; + } + } + if (looptri_num) { pbvh_build(pbvh, &cb, prim_bbc, looptri_num); } @@ -655,6 +807,10 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, memset(pbvh->vert_bitmap, 0, sizeof(bool) * totvert); BKE_pbvh_update_active_vcol(pbvh, mesh); + +#ifdef VALIDATE_UNIQUE_NODE_FACES + pbvh_validate_node_prims(pbvh); +#endif } void BKE_pbvh_build_grids(PBVH *pbvh, @@ -664,7 +820,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden, - Mesh *me) + Mesh *me, + SubdivCCG *subdiv_ccg) { const int gridsize = key->grid_size; @@ -675,6 +832,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh, pbvh->totgrid = totgrid; pbvh->gridkey = *key; pbvh->grid_hidden = grid_hidden; + pbvh->subdiv_ccg = subdiv_ccg; pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1); /* We need the base mesh attribute layout for PBVH draw. */ @@ -706,11 +864,40 @@ void BKE_pbvh_build_grids(PBVH *pbvh, BB_expand(&cb, bbc->bcentroid); } + /* Ensure all primitives belonging to the same base face + * have the same bounds. This is needed to prevent them + * from being swapped away from each other inside the partition + * array. + */ + for (int i = 0; i < totgrid; i++) { + int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i); + + BBC *bbc = prim_bbc + i; + int j = i + 1; + + while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) { + BBC *bbc2 = prim_bbc + j; + + BB_expand((BB *)bbc, bbc2->bmin); + BB_expand((BB *)bbc, bbc2->bmax); + j++; + } + + j = i + 1; + while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) { + prim_bbc[j] = prim_bbc[i]; + j++; + } + } + if (totgrid) { pbvh_build(pbvh, &cb, prim_bbc, totgrid); } MEM_freeN(prim_bbc); +#ifdef VALIDATE_UNIQUE_NODE_FACES + pbvh_validate_node_prims(pbvh); +#endif } PBVH *BKE_pbvh_new(PBVHType type) @@ -719,6 +906,11 @@ PBVH *BKE_pbvh_new(PBVHType type) pbvh->respect_hide = true; pbvh->draw_cache_invalid = true; pbvh->header.type = type; + + /* Initialize this to true, instead of waiting for a draw engine + * to set it. Prevents a crash in draw manager instancing code. + */ + pbvh->is_drawing = true; return pbvh; } @@ -2056,11 +2248,16 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, int (**r_orco_tris)[3], int *r_orco_tris_num, - float (**r_orco_coords)[3]) + float (**r_orco_coords)[3], + BMVert ***r_orco_verts) { *r_orco_tris = node->bm_ortri; *r_orco_tris_num = node->bm_tot_ortri; *r_orco_coords = node->bm_orco; + + if (r_orco_verts) { + *r_orco_verts = node->bm_orvert; + } } bool BKE_pbvh_node_has_vert_with_normal_update_tag(PBVH *pbvh, PBVHNode *node) diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 516e1fb4639..3b0f35263d3 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -493,7 +493,7 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh, BLI_gset_insert(node->bm_unique_verts, v); BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index); - node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; + node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated; /* Log the new vertex */ BM_log_vert_added(pbvh->bm_log, v, cd_vert_mask_offset); @@ -519,7 +519,7 @@ static BMFace *pbvh_bmesh_face_create( BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index); /* mark node for update */ - node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals; + node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_TopologyUpdated; node->flag &= ~PBVH_FullyHidden; /* Log the new face */ @@ -594,7 +594,7 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner, { PBVHNode *current_owner = pbvh_bmesh_node_from_vert(pbvh, v); /* mark node for update */ - current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; + current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated; BLI_assert(current_owner != new_owner); @@ -608,7 +608,7 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner, BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v)); /* mark node for update */ - new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; + new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated; } static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v) @@ -631,7 +631,7 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v) f_node_index_prev = f_node_index; PBVHNode *f_node = &pbvh->nodes[f_node_index]; - f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; + f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated; /* Remove current ownership */ BLI_gset_remove(f_node->bm_other_verts, v, NULL); @@ -680,7 +680,7 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f) BM_log_face_removed(pbvh->bm_log, f); /* mark node for update */ - f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals; + f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_TopologyUpdated; } static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e) @@ -701,14 +701,9 @@ static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e) static void pbvh_bmesh_node_drop_orig(PBVHNode *node) { - if (node->bm_orco) { - MEM_freeN(node->bm_orco); - } - if (node->bm_ortri) { - MEM_freeN(node->bm_ortri); - } - node->bm_orco = NULL; - node->bm_ortri = NULL; + MEM_SAFE_FREE(node->bm_orco); + MEM_SAFE_FREE(node->bm_ortri); + MEM_SAFE_FREE(node->bm_orvert); node->bm_tot_ortri = 0; } @@ -1507,29 +1502,51 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, bool hit = false; float nearest_vertex_co[3] = {0.0f}; + BLI_assert(!use_original || (BLI_gset_len(node->bm_faces) > 0 && node->bm_tot_ortri)); + + use_original = use_original && node->bm_tot_ortri; + + GSetIterator gs_iter; + if (use_original && node->bm_tot_ortri) { for (int i = 0; i < node->bm_tot_ortri; i++) { - const int *t = node->bm_ortri[i]; - hit |= ray_face_intersection_tri(ray_start, - isect_precalc, - node->bm_orco[t[0]], - node->bm_orco[t[1]], - node->bm_orco[t[2]], - depth); + float *cos[3]; + + cos[0] = node->bm_orco[node->bm_ortri[i][0]]; + cos[1] = node->bm_orco[node->bm_ortri[i][1]]; + cos[2] = node->bm_orco[node->bm_ortri[i][2]]; + + if (ray_face_intersection_tri(ray_start, isect_precalc, cos[0], cos[1], cos[2], depth)) { + hit = true; + + if (r_face_normal) { + normal_tri_v3(r_face_normal, cos[0], cos[1], cos[2]); + } + + if (r_active_vertex) { + float location[3] = {0.0f}; + madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); + for (int j = 0; j < 3; j++) { + if (len_squared_v3v3(location, cos[j]) < + len_squared_v3v3(location, nearest_vertex_co)) { + copy_v3_v3(nearest_vertex_co, cos[j]); + r_active_vertex->i = (intptr_t)node->bm_orvert[node->bm_ortri[i][j]]; + } + } + } + } } } else { - GSetIterator gs_iter; - GSET_ITER (gs_iter, node->bm_faces) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); BLI_assert(f->len == 3); + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { BMVert *v_tri[3]; BM_face_as_array_vert_tri(f, v_tri); - if (ray_face_intersection_tri( ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth)) { hit = true; @@ -2016,6 +2033,21 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, BLI_buffer_free(&edge_loops); BLI_buffer_free(&deleted_faces); + /* Go over all changed nodes and check if anything needs to be updated. */ + for (int n = 0; n < pbvh->totnode; n++) { + PBVHNode *node = &pbvh->nodes[n]; + + if (node->flag & PBVH_Leaf && node->flag & PBVH_TopologyUpdated) { + node->flag &= ~PBVH_TopologyUpdated; + + if (node->bm_ortri) { + /* Reallocate original triangle data. */ + pbvh_bmesh_node_drop_orig(node); + BKE_pbvh_bmesh_node_save_orig(pbvh->header.bm, pbvh->bm_log, node, true); + } + } + } + #ifdef USE_VERIFY pbvh_bmesh_verify(pbvh); #endif @@ -2023,7 +2055,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, return modified; } -void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node) +void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, PBVHNode *node, bool use_original) { /* Skip if original coords/triangles are already saved */ if (node->bm_orco) { @@ -2036,19 +2068,38 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node) node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__); node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__); + node->bm_orvert = MEM_mallocN(sizeof(*node->bm_orvert) * totvert, __func__); /* Copy out the vertices and assign a temporary index */ int i = 0; GSetIterator gs_iter; GSET_ITER (gs_iter, node->bm_unique_verts) { BMVert *v = BLI_gsetIterator_getKey(&gs_iter); - copy_v3_v3(node->bm_orco[i], v->co); + const float *origco = BM_log_original_vert_co(log, v); + + if (use_original && origco) { + copy_v3_v3(node->bm_orco[i], origco); + } + else { + copy_v3_v3(node->bm_orco[i], v->co); + } + + node->bm_orvert[i] = v; BM_elem_index_set(v, i); /* set_dirty! */ i++; } GSET_ITER (gs_iter, node->bm_other_verts) { BMVert *v = BLI_gsetIterator_getKey(&gs_iter); - copy_v3_v3(node->bm_orco[i], v->co); + const float *origco = BM_log_original_vert_co(log, v); + + if (use_original && origco) { + copy_v3_v3(node->bm_orco[i], BM_log_original_vert_co(log, v)); + } + else { + copy_v3_v3(node->bm_orco[i], v->co); + } + + node->bm_orvert[i] = v; BM_elem_index_set(v, i); /* set_dirty! */ i++; } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index c78bfc25cb2..34eb969adac 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -116,8 +116,11 @@ struct PBVHNode { GSet *bm_faces; GSet *bm_unique_verts; GSet *bm_other_verts; + + /* Deprecated. Stores original coordinates of triangles. */ float (*bm_orco)[3]; int (*bm_ortri)[3]; + BMVert **bm_orvert; int bm_tot_ortri; /* Used to store the brush color during a stroke and composite it over the original color */ diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index c73bbb91965..119daccce20 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -239,12 +239,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE)); pointcloud_init_data(&pointcloud->id); - CustomData_add_layer_named(&pointcloud->pdata, - CD_PROP_FLOAT, - CD_SET_DEFAULT, - nullptr, - pointcloud->totpoint, - POINTCLOUD_ATTR_RADIUS); CustomData_realloc(&pointcloud->pdata, 0, totpoint); pointcloud->totpoint = totpoint; diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 6b4cddb05f2..ffc6bc8d7a3 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -404,7 +404,7 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) const MVert *mvert = BKE_mesh_verts(mesh); totvert = mesh->totvert; looptri = BKE_mesh_runtime_looptri_ensure(mesh); - tottri = mesh->runtime.looptris.len; + tottri = BKE_mesh_runtime_looptri_len(mesh); const MLoop *mloop = BKE_mesh_loops(mesh); /* sanity checking - potential case when no data will be present */ @@ -679,7 +679,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) const MVert *mvert = BKE_mesh_verts(mesh); totvert = mesh->totvert; lt = BKE_mesh_runtime_looptri_ensure(mesh); - tottri = mesh->runtime.looptris.len; + tottri = BKE_mesh_runtime_looptri_len(mesh); const MLoop *mloop = BKE_mesh_loops(mesh); if (totvert > 0 && tottri > 0) { @@ -753,7 +753,7 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) const MVert *mvert = BKE_mesh_verts(mesh); totvert = mesh->totvert; looptri = BKE_mesh_runtime_looptri_ensure(mesh); - tottri = mesh->runtime.looptris.len; + tottri = BKE_mesh_runtime_looptri_len(mesh); const MLoop *mloop = BKE_mesh_loops(mesh); if (totvert > 0 && tottri > 0) { diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index d6183210186..fc47fb71bf3 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -244,7 +244,7 @@ static void scene_init_data(ID *id) /* Master Collection */ scene->master_collection = BKE_collection_master_add(scene); - BKE_view_layer_add(scene, "ViewLayer", nullptr, VIEWLAYER_ADD_NEW); + BKE_view_layer_add(scene, DATA_("ViewLayer"), nullptr, VIEWLAYER_ADD_NEW); } static void scene_copy_markers(Scene *scene_dst, const Scene *scene_src, const int flag) diff --git a/source/blender/blenkernel/intern/shrinkwrap.cc b/source/blender/blenkernel/intern/shrinkwrap.cc index 703b012d170..65226a5db9d 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.cc +++ b/source/blender/blenkernel/intern/shrinkwrap.cc @@ -140,7 +140,7 @@ bool BKE_shrinkwrap_init_tree( } if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { - data->boundary = mesh->runtime.shrinkwrap_data; + data->boundary = mesh->runtime->shrinkwrap_data; } return true; @@ -153,7 +153,7 @@ void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data) void BKE_shrinkwrap_discard_boundary_data(Mesh *mesh) { - ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data; + ShrinkwrapBoundaryData *data = mesh->runtime->shrinkwrap_data; if (data != nullptr) { MEM_freeN((void *)data->edge_is_boundary); @@ -164,7 +164,7 @@ void BKE_shrinkwrap_discard_boundary_data(Mesh *mesh) MEM_freeN(data); } - mesh->runtime.shrinkwrap_data = nullptr; + mesh->runtime->shrinkwrap_data = nullptr; } /* Accumulate edge for average boundary edge direction. */ @@ -327,7 +327,7 @@ void BKE_shrinkwrap_compute_boundary_data(Mesh *mesh) { BKE_shrinkwrap_discard_boundary_data(mesh); - mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh); + mesh->runtime->shrinkwrap_data = shrinkwrap_build_boundary_data(mesh); } /** diff --git a/source/blender/blenkernel/intern/subdiv_ccg.cc b/source/blender/blenkernel/intern/subdiv_ccg.cc index 6f583f760ef..bf09be444b1 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.cc +++ b/source/blender/blenkernel/intern/subdiv_ccg.cc @@ -128,7 +128,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv) subdiv_ccg->num_grids = num_grids; subdiv_ccg->grids = static_cast<CCGElem **>( MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids")); - subdiv_ccg->grids_storage = static_cast<unsigned char *>( + subdiv_ccg->grids_storage = static_cast<uchar *>( MEM_calloc_arrayN(num_grids, size_t(grid_area) * element_size, "subdiv ccg grids storage")); const size_t grid_size_in_bytes = size_t(grid_area) * element_size; for (int grid_index = 0; grid_index < num_grids; grid_index++) { @@ -286,7 +286,7 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const int face_ static void subdiv_ccg_eval_grids_task(void *__restrict userdata_v, const int face_index, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict /*tls*/) { CCGEvalGridsData *data = static_cast<CCGEvalGridsData *>(userdata_v); SubdivCCG *subdiv_ccg = data->subdiv_ccg; @@ -615,7 +615,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv, return nullptr; } Mesh *result = BKE_mesh_new_nomain_from_template(coarse_mesh, 0, 0, 0, 0, 0); - result->runtime.subdiv_ccg = subdiv_ccg; + result->runtime->subdiv_ccg = subdiv_ccg; return result; } @@ -779,7 +779,7 @@ static void subdiv_ccg_recalc_inner_normal_task(void *__restrict userdata_v, subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index); } -static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict UNUSED(userdata), +static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict /*userdata*/, void *__restrict tls_v) { RecalcInnerNormalsTLSData *tls = static_cast<RecalcInnerNormalsTLSData *>(tls_v); @@ -842,7 +842,7 @@ static void subdiv_ccg_recalc_modified_inner_normal_task(void *__restrict userda subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face); } -static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict UNUSED(userdata), +static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict /*userdata*/, void *__restrict tls_v) { RecalcInnerNormalsTLSData *tls = static_cast<RecalcInnerNormalsTLSData *>(tls_v); @@ -1016,7 +1016,7 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg, static void subdiv_ccg_average_inner_grids_task(void *__restrict userdata_v, const int face_index, - const TaskParallelTLS *__restrict UNUSED(tls_v)) + const TaskParallelTLS *__restrict /*tls_v*/) { AverageInnerGridsData *data = static_cast<AverageInnerGridsData *>(userdata_v); SubdivCCG *subdiv_ccg = data->subdiv_ccg; @@ -1095,7 +1095,7 @@ static void subdiv_ccg_average_grids_boundaries_task(void *__restrict userdata_v subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls); } -static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict UNUSED(userdata), +static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict /*userdata*/, void *__restrict tls_v) { AverageGridsBoundariesTLSData *tls = static_cast<AverageGridsBoundariesTLSData *>(tls_v); @@ -1137,7 +1137,7 @@ static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg, static void subdiv_ccg_average_grids_corners_task(void *__restrict userdata_v, const int n, - const TaskParallelTLS *__restrict UNUSED(tls_v)) + const TaskParallelTLS *__restrict /*tls_v*/) { AverageGridsCornerData *data = static_cast<AverageGridsCornerData *>(userdata_v); const int adjacent_vertex_index = data->adjacent_vert_index_map ? @@ -1323,10 +1323,9 @@ struct StitchFacesInnerGridsData { CCGFace **effected_ccg_faces; }; -static void subdiv_ccg_stitch_face_inner_grids_task( - void *__restrict userdata_v, - const int face_index, - const TaskParallelTLS *__restrict UNUSED(tls_v)) +static void subdiv_ccg_stitch_face_inner_grids_task(void *__restrict userdata_v, + const int face_index, + const TaskParallelTLS *__restrict /*tls_v*/) { StitchFacesInnerGridsData *data = static_cast<StitchFacesInnerGridsData *>(userdata_v); SubdivCCG *subdiv_ccg = data->subdiv_ccg; @@ -1447,7 +1446,7 @@ BLI_INLINE bool is_inner_edge_grid_coordinate(const SubdivCCG *subdiv_ccg, return false; } -BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG *UNUSED(subdiv_ccg), +BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG * /*subdiv_ccg*/, const SubdivCCGCoord *coord) { BLI_assert(coord->y > 0); @@ -1465,7 +1464,7 @@ BLI_INLINE SubdivCCGCoord coord_at_next_row(const SubdivCCG *subdiv_ccg, return result; } -BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG *UNUSED(subdiv_ccg), +BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG * /*subdiv_ccg*/, const SubdivCCGCoord *coord) { BLI_assert(coord->x > 0); diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index 00183ea90c2..3b97c1f5e68 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -528,9 +528,9 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask); subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context); subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices); - MEM_SAFE_FREE(subdiv_context->subdiv_mesh->runtime.subsurf_face_dot_tags); - subdiv_context->subdiv_mesh->runtime.subsurf_face_dot_tags = BLI_BITMAP_NEW(num_vertices, - __func__); + MEM_SAFE_FREE(subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags); + subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags = BLI_BITMAP_NEW(num_vertices, + __func__); return true; } @@ -595,7 +595,7 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext /* Evaluate undeformed texture coordinate. */ subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index); /* Remove face-dot flag. This can happen if there is more than one subsurf modifier. */ - BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index); + BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime->subsurf_face_dot_tags, subdiv_vertex_index); } static void evaluate_vertex_and_apply_displacement_interpolate( @@ -753,7 +753,7 @@ static void subdiv_mesh_tag_center_vertex(const MPoly *coarse_poly, Mesh *subdiv_mesh) { if (subdiv_mesh_is_center_vertex(coarse_poly, u, v)) { - BLI_BITMAP_ENABLE(subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index); + BLI_BITMAP_ENABLE(subdiv_mesh->runtime->subsurf_face_dot_tags, subdiv_vertex_index); } } diff --git a/source/blender/blenkernel/intern/subdiv_modifier.cc b/source/blender/blenkernel/intern/subdiv_modifier.cc index a5529e9b8fa..84b772db045 100644 --- a/source/blender/blenkernel/intern/subdiv_modifier.cc +++ b/source/blender/blenkernel/intern/subdiv_modifier.cc @@ -11,6 +11,7 @@ #include "DNA_scene_types.h" #include "DNA_userdef_types.h" +#include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_subdiv.h" @@ -143,7 +144,7 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene, bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh) { - SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data; + SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data; return runtime_data && runtime_data->has_gpu_subdiv; } diff --git a/source/blender/blenloader/intern/blend_validate.cc b/source/blender/blenloader/intern/blend_validate.cc index 0f43b20c391..7ac0a4fe1af 100644 --- a/source/blender/blenloader/intern/blend_validate.cc +++ b/source/blender/blenloader/intern/blend_validate.cc @@ -61,7 +61,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) for (Main *curmain = bmain->next; curmain != nullptr; curmain = curmain->next) { Library *curlib = curmain->curlib; if (curlib == nullptr) { - BKE_report(reports, RPT_ERROR, "Library database with nullptr library data-block!"); + BKE_report(reports, RPT_ERROR, "Library database with null library data-block pointer!"); continue; } @@ -103,7 +103,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) is_valid = false; BKE_reportf(reports, RPT_ERROR, - "ID %s has nullptr lib pointer while being in library %s!", + "ID %s has null lib pointer while being in library %s!", id->name, curlib->filepath); continue; diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 9e5ef41892a..3a39ed04d2a 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -2316,7 +2316,6 @@ static void lib_node_do_versions_group_indices(bNode *gnode) /* deprecated */ sock->own_index = link->fromsock->own_index; sock->to_index = 0; - sock->groupsock = NULL; } } } @@ -2329,7 +2328,6 @@ static void lib_node_do_versions_group_indices(bNode *gnode) /* deprecated */ sock->own_index = link->tosock->own_index; sock->to_index = 0; - sock->groupsock = NULL; } } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 061840aee7a..1a8fec49516 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3379,7 +3379,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) SpaceImage *sima = (SpaceImage *)sl; sima->flag &= ~(SI_FLAG_UNUSED_0 | SI_FLAG_UNUSED_1 | SI_FLAG_UNUSED_3 | SI_FLAG_UNUSED_6 | SI_FLAG_UNUSED_7 | SI_FLAG_UNUSED_8 | - SI_FLAG_UNUSED_17 | SI_CUSTOM_GRID | SI_FLAG_UNUSED_23 | + SI_FLAG_UNUSED_17 | SI_FLAG_UNUSED_18 | SI_FLAG_UNUSED_23 | SI_FLAG_UNUSED_24); break; } diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index 0584dd6b059..5328107e1f2 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -3604,6 +3604,13 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) v3d->overlay.flag |= V3D_OVERLAY_VIEWER_ATTRIBUTE; v3d->overlay.viewer_attribute_opacity = 1.0f; } + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + if (sima->flag & SI_FLAG_UNUSED_18) { /* Was #SI_CUSTOM_GRID. */ + sima->grid_shape_source = SI_GRID_SHAPE_FIXED; + sima->flag &= ~SI_FLAG_UNUSED_18; + } + } } } } diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 0efa5f73ae4..77223ecd1c7 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -207,6 +207,22 @@ if(WITH_GMP) ) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${TBB_LIBRARIES} + ) +endif() + blender_add_lib(bf_bmesh "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(MSVC AND NOT MSVC_CLANG) diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 3ee9fa7aee4..8125130490a 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -507,26 +507,32 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, for (int i = 0; i < me_src_array_len; i++) { const Mesh *me_src = me_src_array[i]; + CustomData mesh_vdata = CustomData_shallow_copy_remove_non_bmesh_attributes( + &me_src->vdata, CD_MASK_BMESH.vmask); + CustomData mesh_edata = CustomData_shallow_copy_remove_non_bmesh_attributes( + &me_src->edata, CD_MASK_BMESH.emask); + CustomData mesh_pdata = CustomData_shallow_copy_remove_non_bmesh_attributes( + &me_src->pdata, CD_MASK_BMESH.lmask); + CustomData mesh_ldata = CustomData_shallow_copy_remove_non_bmesh_attributes( + &me_src->ldata, CD_MASK_BMESH.pmask); + if (i == 0) { - CustomData_copy_mesh_to_bmesh( - &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh( - &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh( - &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh( - &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_merge_mesh_to_bmesh( - &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); - CustomData_merge_mesh_to_bmesh( - &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); - CustomData_merge_mesh_to_bmesh( - &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); - CustomData_merge_mesh_to_bmesh( - &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); + CustomData_merge(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); } + + MEM_SAFE_FREE(mesh_vdata.layers); + MEM_SAFE_FREE(mesh_edata.layers); + MEM_SAFE_FREE(mesh_pdata.layers); + MEM_SAFE_FREE(mesh_ldata.layers); } CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index dfbdd64ee7c..d65cac08db8 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -129,6 +129,10 @@ static BMFace *bm_face_create_from_mpoly(BMesh &bm, void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params) { + if (!me) { + /* Sanity check. */ + return; + } const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer)); KeyBlock *actkey; @@ -136,19 +140,35 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar CustomData_MeshMasks mask = CD_MASK_BMESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - if (!me || !me->totvert) { - if (me && is_new) { /* No verts? still copy custom-data layout. */ - CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); - CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); - CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); - CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); + CustomData mesh_vdata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->vdata, + mask.vmask); + CustomData mesh_edata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->edata, + mask.emask); + CustomData mesh_pdata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->pdata, + mask.pmask); + CustomData mesh_ldata = CustomData_shallow_copy_remove_non_bmesh_attributes(&me->ldata, + mask.lmask); + BLI_SCOPED_DEFER([&]() { + MEM_SAFE_FREE(mesh_vdata.layers); + MEM_SAFE_FREE(mesh_edata.layers); + MEM_SAFE_FREE(mesh_pdata.layers); + MEM_SAFE_FREE(mesh_ldata.layers); + }); + + if (me->totvert == 0) { + if (is_new) { + /* No verts? still copy custom-data layout. */ + CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); + CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); + CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); + CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE); } - return; /* Sanity check. */ + return; } const float(*vert_normals)[3] = nullptr; @@ -157,16 +177,16 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } if (is_new) { - CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); + CustomData_copy(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); } else { - CustomData_bmesh_merge(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); - CustomData_bmesh_merge(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); - CustomData_bmesh_merge(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); - CustomData_bmesh_merge(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); + CustomData_bmesh_merge(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); + CustomData_bmesh_merge(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); + CustomData_bmesh_merge(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); + CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); } /* -------------------------------------------------------------------- */ @@ -302,7 +322,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } /* Copy Custom Data */ - CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true); + CustomData_to_bmesh_block(&mesh_vdata, &bm->vdata, i, &v->head.data, true); /* Set shape key original index. */ if (cd_shape_keyindex_offset != -1) { @@ -338,7 +358,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } /* Copy Custom Data */ - CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true); + CustomData_to_bmesh_block(&mesh_edata, &bm->edata, i, &e->head.data, true); } if (is_new) { bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */ @@ -397,11 +417,11 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BM_elem_index_set(l_iter, totloops++); /* set_ok */ /* Save index of corresponding #MLoop. */ - CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true); + CustomData_to_bmesh_block(&mesh_ldata, &bm->ldata, j++, &l_iter->head.data, true); } while ((l_iter = l_iter->next) != l_first); /* Copy Custom Data */ - CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true); + CustomData_to_bmesh_block(&mesh_pdata, &bm->pdata, i, &f->head.data, true); if (params->calc_face_normal) { BM_face_normal_update(f); @@ -951,10 +971,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh { CustomData_MeshMasks mask = CD_MASK_MESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy_mesh_to_bmesh(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); - CustomData_copy_mesh_to_bmesh(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); - CustomData_copy_mesh_to_bmesh(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); - CustomData_copy_mesh_to_bmesh(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); + CustomData_copy(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_copy(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_copy(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } CustomData_add_layer(&me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, me->totvert); @@ -1238,7 +1258,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * * different than the BMesh's. */ BKE_mesh_clear_derived_normals(me); - me->runtime.deformed_only = true; + me->runtime->deformed_only = true; bke::MutableAttributeAccessor mesh_attributes = me->attributes_for_write(); diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index 04eaa43c899..0d321e1de8d 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -3,7 +3,7 @@ /** \file * \ingroup bmesh * - * normal recalculation. + * Functionality for flipping faces to make normals consistent. */ #include "MEM_guardedalloc.h" @@ -47,7 +47,7 @@ static bool bmo_recalc_normal_loop_filter_cb(const BMLoop *l, void *UNUSED(user_ * +------------+ * </pre> * - * In the example above, the a\ face can point towards the \a center + * In the example above, the \a face can point towards the \a center * which would end up flipping the normals inwards. * * To take these spikes into account, find the furthest face-loop-vertex. diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc index 751ac0003bf..ee31fce0ea8 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc @@ -10,6 +10,7 @@ #include "COM_MultilayerImageOperation.h" #include "COM_RenderLayersProg.h" #include "COM_SetAlphaMultiplyOperation.h" +#include "COM_SetAlphaReplaceOperation.h" #include "COM_SetColorOperation.h" namespace blender::compositor { @@ -48,7 +49,7 @@ void CryptomatteBaseNode::convert_to_operations(NodeConverter &converter, converter.map_output_socket(output_image_socket, apply_mask_operation->get_output_socket(0)); NodeOutput *output_pick_socket = this->get_output_socket(2); - SetAlphaMultiplyOperation *extract_pick_operation = new SetAlphaMultiplyOperation(); + SetAlphaReplaceOperation *extract_pick_operation = new SetAlphaReplaceOperation(); converter.add_operation(extract_pick_operation); converter.add_input_value(extract_pick_operation->get_input_socket(1), 1.0f); converter.add_link(cryptomatte_operation->get_output_socket(0), diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index 1f1333332f5..90cbe0988ad 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -2,6 +2,7 @@ set(INC . + ./algorithms ../../blenkernel ../../blenlib ../../gpu @@ -53,6 +54,10 @@ set(SRC COM_static_shader_manager.hh COM_texture_pool.hh COM_utilities.hh + + algorithms/intern/algorithm_parallel_reduction.cc + + algorithms/COM_algorithm_parallel_reduction.hh ) set(LIB diff --git a/source/blender/compositor/realtime_compositor/COM_domain.hh b/source/blender/compositor/realtime_compositor/COM_domain.hh index 54d712f7578..99b40ae61cf 100644 --- a/source/blender/compositor/realtime_compositor/COM_domain.hh +++ b/source/blender/compositor/realtime_compositor/COM_domain.hh @@ -28,7 +28,7 @@ struct RealizationOptions { * result involves projecting it on a different domain, which in turn, involves sampling the * result at arbitrary locations, the interpolation identifies the method used for computing the * value at those arbitrary locations. */ - Interpolation interpolation = Interpolation::Nearest; + Interpolation interpolation = Interpolation::Bilinear; /* If true, the result will be repeated infinitely along the horizontal axis when realizing the * result. If false, regions outside of bounds of the result along the horizontal axis will be * filled with zeros. */ diff --git a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh new file mode 100644 index 00000000000..9d0851eff84 --- /dev/null +++ b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "BLI_math_vec_types.hh" + +#include "GPU_texture.h" + +#include "COM_context.hh" + +namespace blender::realtime_compositor { + +/* -------------------------------------------------------------------- + * Sum Reductions. + */ + +/* Computes the sum of the red channel of all pixels in the given texture. */ +float sum_red(Context &context, GPUTexture *texture); + +/* Computes the sum of the green channel of all pixels in the given texture. */ +float sum_green(Context &context, GPUTexture *texture); + +/* Computes the sum of the blue channel of all pixels in the given texture. */ +float sum_blue(Context &context, GPUTexture *texture); + +/* Computes the sum of the luminance of all pixels in the given texture, using the given luminance + * coefficients to compute the luminance. */ +float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* -------------------------------------------------------------------- + * Sum Of Squared Difference Reductions. + */ + +/* Computes the sum of the squared difference between the red channel of all pixels in the given + * texture and the given subtrahend. This can be used to compute the standard deviation if the + * given subtrahend is the mean. */ +float sum_red_squared_difference(Context &context, GPUTexture *texture, float subtrahend); + +/* Computes the sum of the squared difference between the green channel of all pixels in the given + * texture and the given subtrahend. This can be used to compute the standard deviation if the + * given subtrahend is the mean. */ +float sum_green_squared_difference(Context &context, GPUTexture *texture, float subtrahend); + +/* Computes the sum of the squared difference between the blue channel of all pixels in the given + * texture and the given subtrahend. This can be used to compute the standard deviation if the + * given subtrahend is the mean. */ +float sum_blue_squared_difference(Context &context, GPUTexture *texture, float subtrahend); + +/* Computes the sum of the squared difference between the luminance of all pixels in the given + * texture and the given subtrahend, using the given luminance coefficients to compute the + * luminance. This can be used to compute the standard deviation if the given subtrahend is the + * mean. */ +float sum_luminance_squared_difference(Context &context, + GPUTexture *texture, + float3 luminance_coefficients, + float subtrahend); + +} // namespace blender::realtime_compositor diff --git a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc new file mode 100644 index 00000000000..3266ccd14eb --- /dev/null +++ b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_vec_types.hh" +#include "BLI_math_vector.hh" + +#include "MEM_guardedalloc.h" + +#include "GPU_compute.h" +#include "GPU_shader.h" +#include "GPU_texture.h" + +#include "COM_context.hh" +#include "COM_utilities.hh" + +#include "COM_algorithm_parallel_reduction.hh" + +namespace blender::realtime_compositor { + +/* Reduces the given texture into a single value and returns it. The return value should be freed + * by a call to MEM_freeN. The return value is either a pointer to a float, or a pointer to an + * array of floats that represents a vector. This depends on the given format, which should be + * compatible with the reduction shader. + * + * The given reduction shader should be bound when calling the function and the shader is expected + * to be derived from the compositor_parallel_reduction.glsl shader, see that file for more + * information. Also see the compositor_parallel_reduction_info.hh file for example shader + * definitions. */ +static float *parallel_reduction_dispatch(Context &context, + GPUTexture *texture, + GPUShader *shader, + eGPUTextureFormat format) +{ + GPU_shader_uniform_1b(shader, "is_initial_reduction", true); + + GPUTexture *texture_to_reduce = texture; + int2 size_to_reduce = int2(GPU_texture_width(texture), GPU_texture_height(texture)); + + /* Dispatch the reduction shader until the texture reduces to a single pixel. */ + while (size_to_reduce != int2(1)) { + const int2 reduced_size = math::divide_ceil(size_to_reduce, int2(16)); + GPUTexture *reduced_texture = context.texture_pool().acquire(reduced_size, format); + + GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH); + const int texture_image_unit = GPU_shader_get_texture_binding(shader, "input_tx"); + GPU_texture_bind(texture_to_reduce, texture_image_unit); + + const int image_unit = GPU_shader_get_texture_binding(shader, "output_img"); + GPU_texture_image_bind(reduced_texture, image_unit); + + GPU_compute_dispatch(shader, reduced_size.x, reduced_size.y, 1); + + GPU_texture_image_unbind(reduced_texture); + GPU_texture_unbind(texture_to_reduce); + + /* Release the input texture only if it is not the source texture, since the source texture is + * not acquired or owned by the function. */ + if (texture_to_reduce != texture) { + context.texture_pool().release(texture_to_reduce); + } + + texture_to_reduce = reduced_texture; + size_to_reduce = reduced_size; + + GPU_shader_uniform_1b(shader, "is_initial_reduction", false); + } + + GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); + float *pixel = static_cast<float *>(GPU_texture_read(texture_to_reduce, GPU_DATA_FLOAT, 0)); + + /* Release the final texture only if it is not the source texture, since the source texture is + * not acquired or owned by the function. */ + if (texture_to_reduce != texture) { + context.texture_pool().release(texture_to_reduce); + } + + return pixel; +} + +/* -------------------------------------------------------------------- + * Sum Reductions. + */ + +float sum_red(Context &context, GPUTexture *texture) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_red"); + GPU_shader_bind(shader); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float sum_green(Context &context, GPUTexture *texture) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_green"); + GPU_shader_bind(shader); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float sum_blue(Context &context, GPUTexture *texture) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_blue"); + GPU_shader_bind(shader); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +/* -------------------------------------------------------------------- + * Sum Of Squared Difference Reductions. + */ + +float sum_red_squared_difference(Context &context, GPUTexture *texture, float subtrahend) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_red_squared_difference"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "subtrahend", subtrahend); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float sum_green_squared_difference(Context &context, GPUTexture *texture, float subtrahend) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_green_squared_difference"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "subtrahend", subtrahend); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float sum_blue_squared_difference(Context &context, GPUTexture *texture, float subtrahend) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_blue_squared_difference"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "subtrahend", subtrahend); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float sum_luminance_squared_difference(Context &context, + GPUTexture *texture, + float3 luminance_coefficients, + float subtrahend) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_luminance_squared_difference"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + GPU_shader_uniform_1f(shader, "subtrahend", subtrahend); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +} // namespace blender::realtime_compositor diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index d82ae4cd32c..a645bd6b6af 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -77,7 +77,7 @@ set(SRC intern/draw_cache_impl_particles.c intern/draw_cache_impl_pointcloud.cc intern/draw_cache_impl_subdivision.cc - intern/draw_cache_impl_volume.c + intern/draw_cache_impl_volume.cc intern/draw_color_management.cc intern/draw_command.cc intern/draw_common.c @@ -731,6 +731,21 @@ if(WITH_GTESTS) endif() endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${TBB_LIBRARIES} + ) +endif() blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") @@ -756,3 +771,4 @@ if(WITH_GTESTS) blender_add_test_lib(bf_draw_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}") endif() endif() + diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 96f62d942d7..c454a58ffe9 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -813,6 +813,10 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && !DRW_state_is_image_render(); + if (ob->sculpt && ob->sculpt->pbvh) { + BKE_pbvh_is_drawing_set(ob->sculpt->pbvh, use_sculpt_pbvh); + } + /* First get materials for this mesh. */ if (ELEM(ob->type, OB_MESH, OB_SURF)) { const int materials_len = DRW_cache_object_material_count_get(ob); diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.hh b/source/blender/draw/engines/eevee_next/eevee_camera.hh index aaef0f5898d..c1d65dbf31e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_camera.hh +++ b/source/blender/draw/engines/eevee_next/eevee_camera.hh @@ -13,7 +13,7 @@ namespace blender::eevee { class Instance; -static const float cubeface_mat[6][4][4] = { +inline constexpr float cubeface_mat[6][4][4] = { /* Pos X */ {{0.0f, 0.0f, -1.0f, 0.0f}, {0.0f, -1.0f, 0.0f, 0.0f}, diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 8005b27c30e..a0bdf70e254 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -106,6 +106,8 @@ void Instance::begin_sync() gpencil_engine_enabled = false; + scene_sync(); + depth_of_field.sync(); motion_blur.sync(); hiz_buffer.sync(); @@ -115,6 +117,21 @@ void Instance::begin_sync() film.sync(); } +void Instance::scene_sync() +{ + SceneHandle &sc_handle = sync.sync_scene(scene); + + sc_handle.reset_recalc_flag(); + + /* This refers specifically to the Scene camera that can be accessed + * via View Layer Attribute nodes, rather than the actual render camera. */ + if (scene->camera != nullptr) { + ObjectHandle &ob_handle = sync.sync_object(scene->camera); + + ob_handle.reset_recalc_flag(); + } +} + void Instance::object_sync(Object *ob) { const bool is_renderable_type = ELEM(ob->type, OB_CURVES, OB_GPENCIL, OB_MESH, OB_LAMP); diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index c8eecbd812d..bc610cd0642 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -162,6 +162,7 @@ class Instance { void render_sample(); void render_read_result(RenderLayer *render_layer, const char *view_name); + void scene_sync(); void mesh_sync(Object *ob, ObjectHandle &ob_handle); void update_eval_members(); diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc index b63002df2e3..d190a1f17a3 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.cc +++ b/source/blender/draw/engines/eevee_next/eevee_material.cc @@ -187,6 +187,8 @@ MaterialPass MaterialModule::material_pass_get(Object *ob, /* Returned material should be ready to be drawn. */ BLI_assert(GPU_material_status(matpass.gpumat) == GPU_MAT_SUCCESS); + inst_.manager->register_layer_attributes(matpass.gpumat); + if (GPU_material_recalc_flag_get(matpass.gpumat)) { inst_.sampling.reset(); } @@ -217,6 +219,9 @@ MaterialPass MaterialModule::material_pass_get(Object *ob, matpass.sub_pass = &shader_sub->sub(GPU_material_get_name(matpass.gpumat)); matpass.sub_pass->material_set(*inst_.manager, matpass.gpumat); } + else { + matpass.sub_pass = nullptr; + } } return matpass; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index fd06cdc7f23..f6a96aaaff2 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -560,7 +560,7 @@ struct LightCullingData { uint local_lights_len; /** Items that are **NOT** processed by the 2.5D culling (i.e: Sun Lights). */ uint sun_lights_len; - /** Number of items that passes the first culling test. */ + /** Number of items that passes the first culling test. (local lights only) */ uint visible_count; /** Extent of one square tile in pixels. */ float tile_size; diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index f2daba48d7a..08cda6f47cf 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -68,6 +68,20 @@ WorldHandle &SyncModule::sync_world(::World *world) return eevee_dd; } +SceneHandle &SyncModule::sync_scene(::Scene *scene) +{ + DrawEngineType *owner = (DrawEngineType *)&DRW_engine_viewport_eevee_next_type; + struct DrawData *dd = DRW_drawdata_ensure( + (ID *)scene, owner, sizeof(eevee::SceneHandle), draw_data_init_cb, nullptr); + SceneHandle &eevee_dd = *reinterpret_cast<SceneHandle *>(dd); + + const int recalc_flags = ID_RECALC_ALL; + if ((eevee_dd.recalc & recalc_flags) != 0) { + inst_.sampling.reset(); + } + return eevee_dd; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.hh b/source/blender/draw/engines/eevee_next/eevee_sync.hh index ab883ce44c2..eda0342c4b6 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.hh +++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh @@ -139,6 +139,15 @@ struct WorldHandle : public DrawData { } }; +struct SceneHandle : public DrawData { + void reset_recalc_flag() + { + if (recalc != 0) { + recalc = 0; + } + } +}; + class SyncModule { private: Instance &inst_; @@ -149,6 +158,7 @@ class SyncModule { ObjectHandle &sync_object(Object *ob); WorldHandle &sync_world(::World *world); + SceneHandle &sync_scene(::Scene *scene); void sync_mesh(Object *ob, ObjectHandle &ob_handle, diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc index 313c0bda42e..37f90570028 100644 --- a/source/blender/draw/engines/eevee_next/eevee_world.cc +++ b/source/blender/draw/engines/eevee_next/eevee_world.cc @@ -87,6 +87,9 @@ void World::sync() default_tree.nodetree_get(bl_world); GPUMaterial *gpumat = inst_.shaders.world_shader_get(bl_world, ntree); + + inst_.manager->register_layer_attributes(gpumat); + inst_.pipelines.world.sync(gpumat); } diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index b632564a9ca..7883bf01aeb 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -114,11 +114,11 @@ GPU_SHADER_CREATE_INFO(eevee_surf_deferred) // .image_out(5, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_emission") /* Render-passes. */ // .image_out(6, Qualifier::READ_WRITE, GPU_RGBA16F, "rpass_volume_light") - /* TODO: AOVs maybe? */ .fragment_source("eevee_surf_deferred_frag.glsl") - // .additional_info("eevee_aov_out", "eevee_sampling_data", "eevee_camera", - // "eevee_utility_texture") - ; + .additional_info("eevee_camera", + "eevee_utility_texture", + "eevee_sampling_data", + "eevee_aov_out"); GPU_SHADER_CREATE_INFO(eevee_surf_forward) .vertex_out(eevee_surf_iface) diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh index 21dac8009f6..8913b7469ed 100644 --- a/source/blender/draw/engines/image/image_drawing_mode.hh +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -332,6 +332,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD offset++; } } + IMB_gpu_clamp_half_float(&extracted_buffer); GPU_texture_update_sub(texture, GPU_DATA_FLOAT, @@ -388,6 +389,7 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD } BKE_image_release_ibuf(image, tile_buffer, lock); } + IMB_gpu_clamp_half_float(&texture_buffer); GPU_texture_update(info.texture, GPU_DATA_FLOAT, texture_buffer.rect_float); imb_freerectImbuf_all(&texture_buffer); } diff --git a/source/blender/draw/engines/overlay/overlay_grid.cc b/source/blender/draw/engines/overlay/overlay_grid.cc index e31c40fff41..7c221e67691 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.cc +++ b/source/blender/draw/engines/overlay/overlay_grid.cc @@ -59,8 +59,10 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata) const bool draw_grid = is_uv_edit || !ED_space_image_has_buffer(sima); if (background_enabled && draw_grid) { grid_flag |= SHOW_GRID; - if (is_uv_edit && (sima->flag & SI_CUSTOM_GRID) != 0) { - grid_flag |= CUSTOM_GRID; + if (is_uv_edit) { + if (sima->grid_shape_source != SI_GRID_SHAPE_DYNAMIC) { + grid_flag |= CUSTOM_GRID; + } } } diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 36a980bd506..fecdad5802c 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -14,6 +14,7 @@ #include "BLI_alloca.h" #include "BKE_editmesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -231,7 +232,7 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, static const CustomData *workbench_mesh_get_loop_custom_data(const Mesh *mesh) { - if (mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if (BKE_mesh_wrapper_type(mesh) == ME_WRAPPER_TYPE_BMESH) { BLI_assert(mesh->edit_mesh != NULL); BLI_assert(mesh->edit_mesh->bm != NULL); return &mesh->edit_mesh->bm->ldata; @@ -241,7 +242,7 @@ static const CustomData *workbench_mesh_get_loop_custom_data(const Mesh *mesh) static const CustomData *workbench_mesh_get_vert_custom_data(const Mesh *mesh) { - if (mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if (BKE_mesh_wrapper_type(mesh) == ME_WRAPPER_TYPE_BMESH) { BLI_assert(mesh->edit_mesh != NULL); BLI_assert(mesh->edit_mesh->bm != NULL); return &mesh->edit_mesh->bm->vdata; diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index d53c5fbeaa5..3be50d471e2 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -924,6 +924,35 @@ class TextureFromPool : public Texture, NonMovable { GPUTexture *stencil_view() = delete; }; +class TextureRef : public Texture { + public: + TextureRef() = default; + + ~TextureRef() + { + this->tx_ = nullptr; + } + + void wrap(GPUTexture *tex) + { + this->tx_ = tex; + } + + /** Remove methods that are forbidden with this type of textures. */ + bool ensure_1d(int, int, eGPUTextureFormat, float *) = delete; + bool ensure_1d_array(int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_2d(int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_2d_array(int, int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_3d(int, int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_cube(int, int, eGPUTextureFormat, float *) = delete; + bool ensure_cube_array(int, int, int, eGPUTextureFormat, float *) = delete; + void filter_mode(bool) = delete; + void free() = delete; + GPUTexture *mip_view(int) = delete; + GPUTexture *layer_view(int) = delete; + GPUTexture *stencil_view() = delete; +}; + /** * Dummy type to bind texture as image. * It is just a GPUTexture in disguise. diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc index 011d72e9e8f..cc7c9959850 100644 --- a/source/blender/draw/intern/draw_attributes.cc +++ b/source/blender/draw/intern/draw_attributes.cc @@ -44,13 +44,10 @@ void drw_attributes_clear(DRW_Attributes *attributes) memset(attributes, 0, sizeof(DRW_Attributes)); } -void drw_attributes_merge(DRW_Attributes *dst, - const DRW_Attributes *src, - ThreadMutex *render_mutex) +void drw_attributes_merge(DRW_Attributes *dst, const DRW_Attributes *src, std::mutex &render_mutex) { - BLI_mutex_lock(render_mutex); + std::lock_guard lock{render_mutex}; drw_attributes_merge_requests(src, dst); - BLI_mutex_unlock(render_mutex); } bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b) diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h index 786301d0164..00621c711bf 100644 --- a/source/blender/draw/intern/draw_attributes.h +++ b/source/blender/draw/intern/draw_attributes.h @@ -9,6 +9,10 @@ #pragma once +#ifdef __cplusplus +# include <mutex> +#endif + #include "DNA_customdata_types.h" #include "DNA_meshdata_types.h" @@ -56,9 +60,11 @@ BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask ex void drw_attributes_clear(DRW_Attributes *attributes); +#ifdef __cplusplus void drw_attributes_merge(DRW_Attributes *dst, const DRW_Attributes *src, - ThreadMutex *render_mutex); + std::mutex &render_mutex); +#endif /* Return true if all requests in b are in a. */ bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index d3170f4c776..f533904f355 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -686,7 +686,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, MeshRenderData *mr = mesh_render_data_create( object, me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts); mr->use_hide = use_hide; - mr->use_subsurf_fdots = mr->me && mr->me->runtime.subsurf_face_dot_tags != nullptr; + mr->use_subsurf_fdots = mr->me && mr->me->runtime->subsurf_face_dot_tags != nullptr; mr->use_final_mesh = do_final; #ifdef DEBUG_TIME diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index f554e9e67c3..f606701ed09 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -463,7 +463,7 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->bm = me->edit_mesh->bm; mr->edit_bmesh = me->edit_mesh; mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage; - mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : nullptr; + mr->edit_data = is_mode_active ? mr->me->runtime->edit_data : nullptr; if (mr->edit_data) { EditMeshData *emd = mr->edit_data; @@ -499,8 +499,8 @@ MeshRenderData *mesh_render_data_create(Object *object, /* Use bmesh directly when the object is in edit mode unchanged by any modifiers. * For non-final UVs, always use original bmesh since the UV editor does not support * using the cage mesh with deformed coordinates. */ - if ((is_mode_active && mr->me->runtime.is_original_bmesh && - mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) || + if ((is_mode_active && mr->me->runtime->is_original_bmesh && + mr->me->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) || (do_uvedit && !do_final)) { mr->extract_type = MR_EXTRACT_BMESH; } diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 33b97388620..85dd9ca8695 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -14,9 +14,9 @@ #include "BLI_listbase.h" #include "BLI_math_base.h" #include "BLI_math_vec_types.hh" -#include "BLI_math_vector.h" #include "BLI_math_vector.hh" #include "BLI_span.hh" +#include "BLI_task.hh" #include "BLI_utildefines.h" #include "DNA_curves_types.h" @@ -60,7 +60,7 @@ struct CurvesBatchCache { * some locking would be necessary because multiple objects can use the same curves data with * different materials, etc. This is a placeholder to make multi-threading easier in the future. */ - ThreadMutex render_mutex; + std::mutex render_mutex; }; static bool curves_batch_cache_valid(const Curves &curves) @@ -74,15 +74,13 @@ static void curves_batch_cache_init(Curves &curves) CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache); if (!cache) { - cache = MEM_cnew<CurvesBatchCache>(__func__); + cache = MEM_new<CurvesBatchCache>(__func__); curves.batch_cache = cache; } else { - memset(cache, 0, sizeof(*cache)); + cache->curves_cache = {}; } - BLI_mutex_init(&cache->render_mutex); - cache->is_dirty = false; } @@ -172,9 +170,8 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode) void DRW_curves_batch_cache_free(Curves *curves) { curves_batch_cache_clear(*curves); - CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache); - BLI_mutex_end(&cache->render_mutex); - MEM_SAFE_FREE(curves->batch_cache); + MEM_delete(static_cast<CurvesBatchCache *>(curves->batch_cache)); + curves->batch_cache = nullptr; } void DRW_curves_batch_cache_free_old(Curves *curves, int ctime) @@ -226,38 +223,38 @@ static void curves_batch_cache_fill_segments_proc_pos( MutableSpan<PositionAndParameter> posTime_data, MutableSpan<float> hairLength_data) { + using namespace blender; /* TODO: use hair radius layer if available. */ - const int curve_num = curves_id.geometry.curve_num; - const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap( - curves_id.geometry); - Span<float3> positions = curves.positions(); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + const Span<float3> positions = curves.positions(); - for (const int i_curve : IndexRange(curve_num)) { - const IndexRange points = curves.points_for_curve(i_curve); + threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange range) { + for (const int i_curve : range) { + const IndexRange points = curves.points_for_curve(i_curve); - Span<float3> curve_positions = positions.slice(points); - MutableSpan<PositionAndParameter> curve_posTime_data = posTime_data.slice(points); - - float total_len = 0.0f; - for (const int i_point : curve_positions.index_range()) { - if (i_point > 0) { - total_len += blender::math::distance(curve_positions[i_point - 1], - curve_positions[i_point]); - } - curve_posTime_data[i_point].position = curve_positions[i_point]; - curve_posTime_data[i_point].parameter = total_len; - } - hairLength_data[i_curve] = total_len; + Span<float3> curve_positions = positions.slice(points); + MutableSpan<PositionAndParameter> curve_posTime_data = posTime_data.slice(points); - /* Assign length value. */ - if (total_len > 0.0f) { - const float factor = 1.0f / total_len; - /* Divide by total length to have a [0-1] number. */ + float total_len = 0.0f; for (const int i_point : curve_positions.index_range()) { - curve_posTime_data[i_point].parameter *= factor; + if (i_point > 0) { + total_len += math::distance(curve_positions[i_point - 1], curve_positions[i_point]); + } + curve_posTime_data[i_point].position = curve_positions[i_point]; + curve_posTime_data[i_point].parameter = total_len; + } + hairLength_data[i_curve] = total_len; + + /* Assign length value. */ + if (total_len > 0.0f) { + const float factor = 1.0f / total_len; + /* Divide by total length to have a [0-1] number. */ + for (const int i_point : curve_positions.index_range()) { + curve_posTime_data[i_point].parameter *= factor; + } } } - } + }); } static void curves_batch_cache_ensure_procedural_pos(const Curves &curves, @@ -275,7 +272,7 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves, GPU_vertbuf_data_alloc(cache.proc_point_buf, cache.point_len); MutableSpan posTime_data{ - reinterpret_cast<PositionAndParameter *>(GPU_vertbuf_get_data(cache.proc_point_buf)), + static_cast<PositionAndParameter *>(GPU_vertbuf_get_data(cache.proc_point_buf)), cache.point_len}; GPUVertFormat length_format = {0}; @@ -285,8 +282,8 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves, &length_format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); GPU_vertbuf_data_alloc(cache.proc_length_buf, cache.strands_len); - MutableSpan hairLength_data{ - reinterpret_cast<float *>(GPU_vertbuf_get_data(cache.proc_length_buf)), cache.strands_len}; + MutableSpan hairLength_data{static_cast<float *>(GPU_vertbuf_get_data(cache.proc_length_buf)), + cache.strands_len}; curves_batch_cache_fill_segments_proc_pos(curves, posTime_data, hairLength_data); @@ -310,15 +307,15 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves, static void curves_batch_cache_ensure_data_edit_points(const Curves &curves_id, CurvesEvalCache &cache) { - const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap( - curves_id.geometry); + using namespace blender; + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); static GPUVertFormat format_data = {0}; uint data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT); GPU_vertbuf_init_with_format(cache.data_edit_points, &format_data); GPU_vertbuf_data_alloc(cache.data_edit_points, curves.points_num()); - blender::VArray<float> selection; + VArray<float> selection; switch (curves_id.selection_domain) { case ATTR_DOMAIN_POINT: selection = curves.selection_point_float(); @@ -380,6 +377,7 @@ static void curves_batch_ensure_attribute(const Curves &curves, const int subdiv, const int index) { + using namespace blender; GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]); DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]); @@ -399,15 +397,15 @@ static void curves_batch_ensure_attribute(const Curves &curves, request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num : curves.geometry.curve_num); - const blender::bke::AttributeAccessor attributes = - blender::bke::CurvesGeometry::wrap(curves.geometry).attributes(); + const bke::AttributeAccessor attributes = + bke::CurvesGeometry::wrap(curves.geometry).attributes(); /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done * by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following * the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a * similar texture state swizzle to map the attribute correctly as for volume attributes, so we * can control the conversion ourselves. */ - blender::VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>( + VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>( request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f}); MutableSpan<ColorGeometry4f> vbo_span{ @@ -554,7 +552,6 @@ static bool curves_ensure_attributes(const Curves &curves, GPUMaterial *gpu_material, int subdiv) { - ThreadMutex *render_mutex = &cache.render_mutex; const CustomData *cd_curve = &curves.geometry.curve_data; const CustomData *cd_point = &curves.geometry.point_data; CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv]; @@ -588,9 +585,9 @@ static bool curves_ensure_attributes(const Curves &curves, GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]); DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]); } - drw_attributes_merge(&final_cache.attr_used, &attrs_needed, render_mutex); + drw_attributes_merge(&final_cache.attr_used, &attrs_needed, cache.render_mutex); } - drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, render_mutex); + drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, cache.render_mutex); } bool need_tf_update = false; @@ -689,7 +686,7 @@ static void request_attribute(Curves &curves, const char *name) drw_attributes_add_request( &attributes, name, type, CustomData_get_named_layer(&custom_data, type, name), domain); - drw_attributes_merge(&final_cache.attr_used, &attributes, &cache.render_mutex); + drw_attributes_merge(&final_cache.attr_used, &attributes, cache.render_mutex); } GPUTexture **DRW_curves_texture_for_evaluated_attribute(Curves *curves, diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index 5a041493a6a..5ce658abfe4 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -554,22 +554,13 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag static bool mesh_batch_cache_valid(Object *object, Mesh *me) { - MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache); if (cache == nullptr) { return false; } - if (object->sculpt && object->sculpt->pbvh) { - if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) { - return false; - } - - if (BKE_pbvh_is_drawing(object->sculpt->pbvh) && - BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) { - return false; - } - } + /* Note: PBVH draw data should not be checked here. */ if (cache->is_editmode != (me->edit_mesh != nullptr)) { return false; @@ -588,11 +579,11 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me) static void mesh_batch_cache_init(Object *object, Mesh *me) { - MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache); if (!cache) { - me->runtime.batch_cache = MEM_cnew<MeshBatchCache>(__func__); - cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); + me->runtime->batch_cache = MEM_cnew<MeshBatchCache>(__func__); + cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache); } else { memset(cache, 0, sizeof(*cache)); @@ -634,7 +625,7 @@ void DRW_mesh_batch_cache_validate(Object *object, Mesh *me) static MeshBatchCache *mesh_batch_cache_get(Mesh *me) { - return static_cast<MeshBatchCache *>(me->runtime.batch_cache); + return static_cast<MeshBatchCache *>(me->runtime->batch_cache); } static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, @@ -742,7 +733,7 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode) { - MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache); if (cache == nullptr) { return; } @@ -830,7 +821,7 @@ static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache) static void mesh_batch_cache_clear(Mesh *me) { - MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache); if (!cache) { return; } @@ -862,7 +853,7 @@ static void mesh_batch_cache_clear(Mesh *me) void DRW_mesh_batch_cache_free(Mesh *me) { mesh_batch_cache_clear(me); - MEM_SAFE_FREE(me->runtime.batch_cache); + MEM_SAFE_FREE(me->runtime->batch_cache); } /** \} */ @@ -1017,8 +1008,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object, BLI_assert(gpumat_array_len == cache->mat_len); mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); - ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; - drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex); + drw_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime->render_mutex); mesh_batch_cache_request_surface_batches(cache); return cache->surface_per_mat; } @@ -1046,8 +1036,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me) DRW_Attributes attrs_needed{}; request_active_and_default_color_attributes(*object, *me, attrs_needed); - ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; - drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex); + drw_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime->render_mutex); mesh_batch_cache_request_surface_batches(cache); return cache->batch.surface; @@ -1060,8 +1049,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Object *object, Mesh *me) DRW_Attributes attrs_needed{}; request_active_and_default_color_attributes(*object, *me, attrs_needed); - ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; - drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex); + drw_attributes_merge(&cache->attr_needed, &attrs_needed, me->runtime->render_mutex); mesh_batch_cache_request_surface_batches(cache); return cache->batch.surface; @@ -1300,7 +1288,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me) void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) { - MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache); + MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime->batch_cache); if (cache == nullptr) { return; @@ -1446,8 +1434,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, } } - ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex; - /* Verify that all surface batches have needed attribute layers. */ /* TODO(fclem): We could be a bit smarter here and only do it per @@ -1485,12 +1471,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, cache->batch_ready &= ~(MBC_SURFACE); mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed); - drw_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex); + drw_attributes_merge(&cache->attr_used, &cache->attr_needed, me->runtime->render_mutex); } mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed); mesh_cd_layers_type_clear(&cache->cd_needed); - drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex); + drw_attributes_merge( + &cache->attr_used_over_time, &cache->attr_needed, me->runtime->render_mutex); drw_attributes_clear(&cache->attr_needed); } @@ -1537,7 +1524,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh; if (do_update_sculpt_normals) { Mesh *mesh = static_cast<Mesh *>(ob->data); - BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg); + BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime->subdiv_ccg); } cache->batch_ready |= batch_requested; @@ -1548,8 +1535,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); do_cage = editmesh_eval_final != editmesh_eval_cage; - do_uvcage = !(editmesh_eval_final->runtime.is_original_bmesh && - editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH); + do_uvcage = !(editmesh_eval_final->runtime->is_original_bmesh && + editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH); } const bool do_subdivision = BKE_subsurf_modifier_has_gpu_subdiv(me); diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index 9f445be9750..6a9e6c126e9 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -2036,7 +2036,7 @@ static bool draw_subdiv_create_requested_buffers(Object *ob, const bool use_hide, OpenSubdiv_EvaluatorCache *evaluator_cache) { - SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data; + SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data; BLI_assert(runtime_data && runtime_data->has_gpu_subdiv); if (runtime_data->settings.level == 0) { diff --git a/source/blender/draw/intern/draw_cache_impl_volume.c b/source/blender/draw/intern/draw_cache_impl_volume.cc index 18a4c81514b..ac5e6fa05b9 100644 --- a/source/blender/draw/intern/draw_cache_impl_volume.c +++ b/source/blender/draw/intern/draw_cache_impl_volume.cc @@ -7,7 +7,7 @@ * \brief Volume API for render engines */ -#include <string.h> +#include <cstring> #include "MEM_guardedalloc.h" @@ -39,7 +39,7 @@ static void volume_batch_cache_clear(Volume *volume); /* ---------------------------------------------------------------------- */ /* Volume GPUBatch Cache */ -typedef struct VolumeBatchCache { +struct VolumeBatchCache { /* 3D textures */ ListBase grids; @@ -54,22 +54,22 @@ typedef struct VolumeBatchCache { /* settings to determine if cache is invalid */ bool is_dirty; -} VolumeBatchCache; +}; /* GPUBatch cache management. */ static bool volume_batch_cache_valid(Volume *volume) { - VolumeBatchCache *cache = volume->batch_cache; + VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache); return (cache && cache->is_dirty == false); } static void volume_batch_cache_init(Volume *volume) { - VolumeBatchCache *cache = volume->batch_cache; + VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache); if (!cache) { - cache = volume->batch_cache = MEM_callocN(sizeof(*cache), __func__); + volume->batch_cache = cache = MEM_cnew<VolumeBatchCache>(__func__); } else { memset(cache, 0, sizeof(*cache)); @@ -89,13 +89,13 @@ void DRW_volume_batch_cache_validate(Volume *volume) static VolumeBatchCache *volume_batch_cache_get(Volume *volume) { DRW_volume_batch_cache_validate(volume); - return volume->batch_cache; + return static_cast<VolumeBatchCache *>(volume->batch_cache); } void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode) { - VolumeBatchCache *cache = volume->batch_cache; - if (cache == NULL) { + VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache); + if (cache == nullptr) { return; } switch (mode) { @@ -109,7 +109,7 @@ void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode) static void volume_batch_cache_clear(Volume *volume) { - VolumeBatchCache *cache = volume->batch_cache; + VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache); if (!cache) { return; } @@ -130,18 +130,18 @@ void DRW_volume_batch_cache_free(Volume *volume) volume_batch_cache_clear(volume); MEM_SAFE_FREE(volume->batch_cache); } -typedef struct VolumeWireframeUserData { +struct VolumeWireframeUserData { Volume *volume; Scene *scene; -} VolumeWireframeUserData; +}; static void drw_volume_wireframe_cb( void *userdata, const float (*verts)[3], const int (*edges)[2], int totvert, int totedge) { - VolumeWireframeUserData *data = userdata; + VolumeWireframeUserData *data = static_cast<VolumeWireframeUserData *>(userdata); Scene *scene = data->scene; Volume *volume = data->volume; - VolumeBatchCache *cache = volume->batch_cache; + VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache); const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 || GPU_use_hq_normals_workaround(); @@ -181,7 +181,7 @@ static void drw_volume_wireframe_cb( if (volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS) { /* Create batch. */ cache->face_wire.batch = GPU_batch_create( - GPU_PRIM_POINTS, cache->face_wire.pos_nor_in_order, NULL); + GPU_PRIM_POINTS, cache->face_wire.pos_nor_in_order, nullptr); } else { /* Create edge index buffer. */ @@ -203,15 +203,15 @@ static void drw_volume_wireframe_cb( GPUBatch *DRW_volume_batch_cache_get_wireframes_face(Volume *volume) { if (volume->display.wireframe_type == VOLUME_WIREFRAME_NONE) { - return NULL; + return nullptr; } VolumeBatchCache *cache = volume_batch_cache_get(volume); - if (cache->face_wire.batch == NULL) { + if (cache->face_wire.batch == nullptr) { const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume); - if (volume_grid == NULL) { - return NULL; + if (volume_grid == nullptr) { + return nullptr; } /* Create wireframe from OpenVDB tree. */ @@ -228,8 +228,8 @@ GPUBatch *DRW_volume_batch_cache_get_wireframes_face(Volume *volume) static void drw_volume_selection_surface_cb( void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris) { - Volume *volume = userdata; - VolumeBatchCache *cache = volume->batch_cache; + Volume *volume = static_cast<Volume *>(userdata); + VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache); static GPUVertFormat format = {0}; static uint pos_id; @@ -257,10 +257,10 @@ static void drw_volume_selection_surface_cb( GPUBatch *DRW_volume_batch_cache_get_selection_surface(Volume *volume) { VolumeBatchCache *cache = volume_batch_cache_get(volume); - if (cache->selection_surface == NULL) { + if (cache->selection_surface == nullptr) { const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume); - if (volume_grid == NULL) { - return NULL; + if (volume_grid == nullptr) { + return nullptr; } BKE_volume_grid_selection_surface( volume, volume_grid, drw_volume_selection_surface_cb, volume); @@ -275,15 +275,14 @@ static DRWVolumeGrid *volume_grid_cache_get(const Volume *volume, const char *name = BKE_volume_grid_name(grid); /* Return cached grid. */ - DRWVolumeGrid *cache_grid; - for (cache_grid = cache->grids.first; cache_grid; cache_grid = cache_grid->next) { + LISTBASE_FOREACH (DRWVolumeGrid *, cache_grid, &cache->grids) { if (STREQ(cache_grid->name, name)) { return cache_grid; } } /* Allocate new grid. */ - cache_grid = MEM_callocN(sizeof(DRWVolumeGrid), __func__); + DRWVolumeGrid *cache_grid = MEM_cnew<DRWVolumeGrid>(__func__); cache_grid->name = BLI_strdup(name); BLI_addtail(&cache->grids, cache_grid); @@ -316,7 +315,7 @@ static DRWVolumeGrid *volume_grid_cache_get(const Volume *volume, dense_grid.voxels); /* The texture can be null if the resolution along one axis is larger than * GL_MAX_3D_TEXTURE_SIZE. */ - if (cache_grid->texture != NULL) { + if (cache_grid->texture != nullptr) { GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1"); GPU_texture_wrap_mode(cache_grid->texture, false, false); BKE_volume_dense_float_grid_clear(&dense_grid); @@ -339,7 +338,7 @@ DRWVolumeGrid *DRW_volume_batch_cache_get_grid(Volume *volume, const VolumeGrid { VolumeBatchCache *cache = volume_batch_cache_get(volume); DRWVolumeGrid *grid = volume_grid_cache_get(volume, volume_grid, cache); - return (grid->texture != NULL) ? grid : NULL; + return (grid->texture != nullptr) ? grid : nullptr; } int DRW_volume_material_count_get(Volume *volume) diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc index 9e0be3d96ae..55de779d85c 100644 --- a/source/blender/draw/intern/draw_debug.cc +++ b/source/blender/draw/intern/draw_debug.cc @@ -21,7 +21,7 @@ #include <iomanip> -#ifdef DEBUG +#if defined(DEBUG) || defined(WITH_DRAW_DEBUG) # define DRAW_DEBUG #else /* Uncomment to forcibly enable debug draw in release mode. */ @@ -558,7 +558,7 @@ void DebugDraw::display_prints() int slot = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT); float f_viewport[4]; GPU_viewport_size_get_f(f_viewport); - GPU_shader_uniform_4fv(shader, "viewport_size", f_viewport); + GPU_shader_uniform_2fv(shader, "viewport_size", f_viewport); if (gpu_print_buf_used) { GPU_debug_group_begin("GPU"); diff --git a/source/blender/draw/intern/draw_defines.h b/source/blender/draw/intern/draw_defines.h index f5976ddd34e..57035717bd7 100644 --- a/source/blender/draw/intern/draw_defines.h +++ b/source/blender/draw/intern/draw_defines.h @@ -15,6 +15,8 @@ #define DRW_VIEW_CULLING_UBO_SLOT 1 #define DRW_CLIPPING_UBO_SLOT 2 +#define DRW_LAYER_ATTR_UBO_SLOT 3 + #define DRW_RESOURCE_ID_SLOT 11 #define DRW_OBJ_MAT_SLOT 10 #define DRW_OBJ_INFOS_SLOT 9 diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index a56883ce304..b44c1364af9 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -622,6 +622,62 @@ void drw_uniform_attrs_pool_update(GHash *table, } } +GPUUniformBuf *drw_ensure_layer_attribute_buffer() +{ + DRWData *data = DST.vmempool; + + if (data->vlattrs_ubo_ready && data->vlattrs_ubo != NULL) { + return data->vlattrs_ubo; + } + + /* Allocate the buffer data. */ + const int buf_size = DRW_RESOURCE_CHUNK_LEN; + + if (data->vlattrs_buf == NULL) { + data->vlattrs_buf = MEM_calloc_arrayN( + buf_size, sizeof(LayerAttribute), "View Layer Attr Data"); + } + + /* Look up attributes. + * + * Mirrors code in draw_resource.cc and cycles/blender/shader.cpp. + */ + LayerAttribute *buffer = data->vlattrs_buf; + int count = 0; + + LISTBASE_FOREACH (GPULayerAttr *, attr, &data->vlattrs_name_list) { + float value[4]; + + if (BKE_view_layer_find_rgba_attribute( + DST.draw_ctx.scene, DST.draw_ctx.view_layer, attr->name, value)) { + LayerAttribute *item = &buffer[count++]; + + memcpy(item->data, value, sizeof(item->data)); + item->hash_code = attr->hash_code; + + /* Check if the buffer is full just in case. */ + if (count >= buf_size) { + break; + } + } + } + + buffer[0].buffer_length = count; + + /* Update or create the UBO object. */ + if (data->vlattrs_ubo != NULL) { + GPU_uniformbuf_update(data->vlattrs_ubo, buffer); + } + else { + data->vlattrs_ubo = GPU_uniformbuf_create_ex( + sizeof(*buffer) * buf_size, buffer, "View Layer Attributes"); + } + + data->vlattrs_ubo_ready = true; + + return data->vlattrs_ubo; +} + DRWSparseUniformBuf *DRW_uniform_attrs_pool_find_ubo(GHash *table, const struct GPUUniformAttrList *key) { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 6dfd434d5c7..da77845feb4 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -378,6 +378,8 @@ DRWData *DRW_viewport_data_create(void) drw_data->views = BLI_memblock_create(sizeof(DRWView)); drw_data->images = BLI_memblock_create(sizeof(GPUTexture *)); drw_data->obattrs_ubo_pool = DRW_uniform_attrs_pool_new(); + drw_data->vlattrs_name_cache = BLI_ghash_new( + BLI_ghashutil_inthash_p_simple, BLI_ghashutil_intcmp, "View Layer Attribute names"); { uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN; drw_data->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len); @@ -413,9 +415,24 @@ static void draw_texture_release(DRWData *drw_data) } } +static void draw_prune_vlattrs(DRWData *drw_data) +{ + drw_data->vlattrs_ubo_ready = false; + + /* Forget known attributes after they are unused for a few frames. */ + LISTBASE_FOREACH_MUTABLE (GPULayerAttr *, attr, &drw_data->vlattrs_name_list) { + if (++attr->users > 10) { + BLI_ghash_remove( + drw_data->vlattrs_name_cache, POINTER_FROM_UINT(attr->hash_code), NULL, NULL); + BLI_freelinkN(&drw_data->vlattrs_name_list, attr); + } + } +} + static void drw_viewport_data_reset(DRWData *drw_data) { draw_texture_release(drw_data); + draw_prune_vlattrs(drw_data); BLI_memblock_clear(drw_data->commands, NULL); BLI_memblock_clear(drw_data->commands_small, NULL); @@ -451,6 +468,12 @@ void DRW_viewport_data_free(DRWData *drw_data) BLI_memblock_destroy(drw_data->passes, NULL); BLI_memblock_destroy(drw_data->images, NULL); DRW_uniform_attrs_pool_free(drw_data->obattrs_ubo_pool); + BLI_ghash_free(drw_data->vlattrs_name_cache, NULL, NULL); + BLI_freelistN(&drw_data->vlattrs_name_list); + if (drw_data->vlattrs_ubo) { + GPU_uniformbuf_free(drw_data->vlattrs_ubo); + MEM_freeN(drw_data->vlattrs_buf); + } DRW_instance_data_list_free(drw_data->idatalist); DRW_texture_pool_free(drw_data->texture_pool); for (int i = 0; i < 2; i++) { @@ -811,6 +834,7 @@ static bool id_type_can_have_drawdata(const short id_type) /* has DrawData */ case ID_OB: case ID_WO: + case ID_SCE: return true; /* no DrawData */ diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc index 169d86b2ea1..c644cadd18c 100644 --- a/source/blender/draw/intern/draw_manager.cc +++ b/source/blender/draw/intern/draw_manager.cc @@ -35,6 +35,7 @@ void Manager::begin_sync() } acquired_textures.clear(); + layer_attributes.clear(); #ifdef DEBUG /* Detect uninitialized data. */ @@ -52,14 +53,46 @@ void Manager::begin_sync() resource_handle(float4x4::identity()); } +void Manager::sync_layer_attributes() +{ + /* Sort the attribute IDs - the shaders use binary search. */ + Vector<uint32_t> id_list; + + id_list.reserve(layer_attributes.size()); + + for (uint32_t id : layer_attributes.keys()) { + id_list.append(id); + } + + std::sort(id_list.begin(), id_list.end()); + + /* Look up the attributes. */ + int count = 0, size = layer_attributes_buf.end() - layer_attributes_buf.begin(); + + for (uint32_t id : id_list) { + if (layer_attributes_buf[count].sync( + DST.draw_ctx.scene, DST.draw_ctx.view_layer, layer_attributes.lookup(id))) { + /* Check if the buffer is full. */ + if (++count == size) { + break; + } + } + } + + layer_attributes_buf[0].buffer_length = count; +} + void Manager::end_sync() { GPU_debug_group_begin("Manager.end_sync"); + sync_layer_attributes(); + matrix_buf.push_update(); bounds_buf.push_update(); infos_buf.push_update(); attributes_buf.push_update(); + layer_attributes_buf.push_update(); attributes_buf_legacy.push_update(); /* Useful for debugging the following resource finalize. But will trigger the drawing of the GPU @@ -100,6 +133,7 @@ void Manager::resource_bind() GPU_storagebuf_bind(matrix_buf, DRW_OBJ_MAT_SLOT); GPU_storagebuf_bind(infos_buf, DRW_OBJ_INFOS_SLOT); GPU_storagebuf_bind(attributes_buf, DRW_OBJ_ATTR_SLOT); + GPU_uniformbuf_bind(layer_attributes_buf, DRW_LAYER_ATTR_UBO_SLOT); /* 2 is the hardcoded location of the uniform attr UBO. */ /* TODO(@fclem): Remove this workaround. */ GPU_uniformbuf_bind(attributes_buf_legacy, 2); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 6b5a2cc4f6f..52129049269 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -335,6 +335,7 @@ typedef enum { DRW_UNIFORM_BLOCK_OBMATS, DRW_UNIFORM_BLOCK_OBINFOS, DRW_UNIFORM_BLOCK_OBATTRS, + DRW_UNIFORM_BLOCK_VLATTRS, DRW_UNIFORM_RESOURCE_CHUNK, DRW_UNIFORM_RESOURCE_ID, /** Legacy / Fallback */ @@ -527,6 +528,11 @@ typedef struct DRWData { struct GPUUniformBuf **matrices_ubo; struct GPUUniformBuf **obinfos_ubo; struct GHash *obattrs_ubo_pool; + struct GHash *vlattrs_name_cache; + struct ListBase vlattrs_name_list; + struct LayerAttribute *vlattrs_buf; + struct GPUUniformBuf *vlattrs_ubo; + bool vlattrs_ubo_ready; uint ubo_len; /** Per draw-call volume object data. */ void *volume_grids_ubos; /* VolumeUniformBufPool */ @@ -691,6 +697,8 @@ void drw_uniform_attrs_pool_update(struct GHash *table, struct Object *dupli_parent, struct DupliObject *dupli_source); +GPUUniformBuf *drw_ensure_layer_attribute_buffer(void); + double *drw_engine_data_cache_time_get(GPUViewport *viewport); void *drw_engine_data_engine_data_create(GPUViewport *viewport, void *engine_type); void *drw_engine_data_engine_data_get(GPUViewport *viewport, void *engine_handle); diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh index fbd3d28d3f4..0a865179cee 100644 --- a/source/blender/draw/intern/draw_manager.hh +++ b/source/blender/draw/intern/draw_manager.hh @@ -44,6 +44,7 @@ class Manager { using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>; using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>; using ObjectAttributeBuf = StorageArrayBuffer<ObjectAttribute, 128>; + using LayerAttributeBuf = UniformArrayBuffer<LayerAttribute, 512>; /** * TODO(@fclem): Remove once we get rid of old EEVEE code-base. * `DRW_RESOURCE_CHUNK_LEN = 512`. @@ -87,6 +88,16 @@ class Manager { ObjectAttributeLegacyBuf attributes_buf_legacy; /** + * Table of all View Layer attributes required by shaders, used to populate the buffer below. + */ + Map<uint32_t, GPULayerAttr> layer_attributes; + + /** + * Buffer of layer attribute values, indexed and sorted by the hash. + */ + LayerAttributeBuf layer_attributes_buf; + + /** * List of textures coming from Image data-blocks. * They need to be reference-counted in order to avoid being freed in another thread. */ @@ -131,6 +142,11 @@ class Manager { Span<GPUMaterial *> materials); /** + * Collect necessary View Layer attributes. + */ + void register_layer_attributes(GPUMaterial *material); + + /** * Submit a pass for drawing. All resource reference will be dereferenced and commands will be * sent to GPU. */ @@ -169,6 +185,9 @@ class Manager { void debug_bind(); void resource_bind(); + + private: + void sync_layer_attributes(); }; inline ResourceHandle Manager::resource_handle(const ObjectRef ref) @@ -229,6 +248,19 @@ inline void Manager::extract_object_attributes(ResourceHandle handle, } } +inline void Manager::register_layer_attributes(GPUMaterial *material) +{ + const ListBase *attr_list = GPU_material_layer_attributes(material); + + if (attr_list != nullptr) { + LISTBASE_FOREACH (const GPULayerAttr *, attr, attr_list) { + /** Since layer attributes are global to the whole render pass, + * this only collects a table of their names. */ + layer_attributes.add(attr->hash_code, *attr); + } + } +} + } // namespace blender::draw /* TODO(@fclem): This is for testing. The manager should be passed to the engine through the diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc index 2d0ea58b6e5..0312eecc7b7 100644 --- a/source/blender/draw/intern/draw_manager_data.cc +++ b/source/blender/draw/intern/draw_manager_data.cc @@ -695,7 +695,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob) drw_call_calc_orco(ob, ob_infos->orcotexfac); /* Random float value. */ uint random = (DST.dupli_source) ? - DST.dupli_source->random_id : + DST.dupli_source->random_id : /* TODO(fclem): this is rather costly to do at runtime. Maybe we can * put it in ob->runtime and make depsgraph ensure it is up to date. */ BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0); @@ -1348,7 +1348,7 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) } Mesh *mesh = static_cast<Mesh *>(scd->ob->data); - BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg); + BKE_pbvh_update_normals(pbvh, mesh->runtime->subdiv_ccg); BKE_pbvh_draw_cb(pbvh, update_only_visible, @@ -1841,6 +1841,13 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, GPUMaterial *mater grp, loc, DRW_UNIFORM_BLOCK_OBATTRS, uattrs, GPU_SAMPLER_DEFAULT, 0, 1); grp->uniform_attrs = uattrs; } + + if (GPU_material_layer_attributes(material) != NULL) { + int loc = GPU_shader_get_uniform_block_binding(grp->shader, + GPU_LAYER_ATTRIBUTE_UBO_BLOCK_NAME); + drw_shgroup_uniform_create_ex( + grp, loc, DRW_UNIFORM_BLOCK_VLATTRS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); + } } GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat attrs[], diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 3627b0fbf10..8b1b35b5f03 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -44,6 +44,7 @@ typedef struct DRWCommandsState { int obmats_loc; int obinfos_loc; int obattrs_loc; + int vlattrs_loc; int baseinst_loc; int chunkid_loc; int resourceid_loc; @@ -682,6 +683,10 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, uni->uniform_attrs); DRW_sparse_uniform_buffer_bind(state->obattrs_ubo, 0, uni->location); break; + case DRW_UNIFORM_BLOCK_VLATTRS: + state->vlattrs_loc = uni->location; + GPU_uniformbuf_bind(drw_ensure_layer_attribute_buffer(), uni->location); + break; case DRW_UNIFORM_RESOURCE_CHUNK: state->chunkid_loc = uni->location; GPU_shader_uniform_int(shgroup->shader, uni->location, 0); @@ -960,6 +965,9 @@ static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState if (state->obattrs_loc != -1) { DRW_sparse_uniform_buffer_unbind(state->obattrs_ubo, state->resource_chunk); } + if (state->vlattrs_loc != -1) { + GPU_uniformbuf_unbind(DST.vmempool->vlattrs_ubo); + } } static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) @@ -970,6 +978,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) .obmats_loc = -1, .obinfos_loc = -1, .obattrs_loc = -1, + .vlattrs_loc = -1, .baseinst_loc = -1, .chunkid_loc = -1, .resourceid_loc = -1, diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 04a9f3fdd2d..40b05dff51f 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -237,6 +237,42 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) WM_jobs_start(wm, wm_job); } +static void drw_register_shader_vlattrs(GPUMaterial *mat) +{ + const ListBase *attrs = GPU_material_layer_attributes(mat); + + if (!attrs) { + return; + } + + GHash *hash = DST.vmempool->vlattrs_name_cache; + ListBase *list = &DST.vmempool->vlattrs_name_list; + + LISTBASE_FOREACH (GPULayerAttr *, attr, attrs) { + GPULayerAttr **p_val; + + /* Add to the table and list if newly seen. */ + if (!BLI_ghash_ensure_p(hash, POINTER_FROM_UINT(attr->hash_code), (void ***)&p_val)) { + DST.vmempool->vlattrs_ubo_ready = false; + + GPULayerAttr *new_link = *p_val = MEM_dupallocN(attr); + + /* Insert into the list ensuring sorted order. */ + GPULayerAttr *link = list->first; + + while (link && link->hash_code <= attr->hash_code) { + link = link->next; + } + + new_link->prev = new_link->next = NULL; + BLI_insertlinkbefore(list, link, new_link); + } + + /* Reset the unused frames counter. */ + (*p_val)->users = 0; + } +} + void DRW_deferred_shader_remove(GPUMaterial *mat) { LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) { @@ -382,6 +418,9 @@ GPUMaterial *DRW_shader_from_world(World *wo, false, callback, thunk); + + drw_register_shader_vlattrs(mat); + if (DRW_state_is_image_render()) { /* Do not deferred if doing render. */ deferred = false; @@ -411,6 +450,8 @@ GPUMaterial *DRW_shader_from_material(Material *ma, callback, thunk); + drw_register_shader_vlattrs(mat); + if (DRW_state_is_image_render()) { /* Do not deferred if doing render. */ deferred = false; diff --git a/source/blender/draw/intern/draw_manager_text.cc b/source/blender/draw/intern/draw_manager_text.cc index d41127c3641..100ef528bc8 100644 --- a/source/blender/draw/intern/draw_manager_text.cc +++ b/source/blender/draw/intern/draw_manager_text.cc @@ -15,6 +15,7 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" #include "BKE_global.h" +#include "BKE_mesh.h" #include "BKE_unit.h" #include "DNA_mesh_types.h" @@ -233,8 +234,8 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, float clip_planes[4][4]; /* allow for displaying shape keys and deform mods */ BMIter iter; - const float(*vert_coords)[3] = (me->runtime.edit_data ? me->runtime.edit_data->vertexCos : - nullptr); + const float(*vert_coords)[3] = (me->runtime->edit_data ? me->runtime->edit_data->vertexCos : + nullptr); const bool use_coords = (vert_coords != nullptr); /* when 2 or more edge-info options are enabled, space apart */ @@ -339,8 +340,8 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, const float(*poly_normals)[3] = nullptr; if (use_coords) { BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); - BKE_editmesh_cache_ensure_poly_normals(em, me->runtime.edit_data); - poly_normals = me->runtime.edit_data->polyNos; + BKE_editmesh_cache_ensure_poly_normals(em, me->runtime->edit_data); + poly_normals = me->runtime->edit_data->polyNos; } BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh index ee2180712d1..24dfdd1b97b 100644 --- a/source/blender/draw/intern/draw_pass.hh +++ b/source/blender/draw/intern/draw_pass.hh @@ -174,9 +174,15 @@ class PassBase { /** * Reminders: - * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) + * - `compare_mask & reference` is what is tested against `compare_mask & stencil_value` * stencil_value being the value stored in the stencil buffer. - * - (write-mask & reference) is what gets written if the test condition is fulfilled. + * - `write-mask & reference` is what gets written if the test condition is fulfilled. + * + * This will modify the stencil state until another call to this function. + * If not specified before any draw-call, these states will be undefined. + * + * For more information see: + * https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkStencilOpState.html */ void state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask); @@ -728,7 +734,7 @@ template<class T> inline void PassBase<T>::state_set(DRWState state) template<class T> inline void PassBase<T>::state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask) { - create_command(Type::StencilSet).stencil_set = {write_mask, reference, compare_mask}; + create_command(Type::StencilSet).stencil_set = {write_mask, compare_mask, reference}; } template<class T> inline void PassBase<T>::shader_set(GPUShader *shader) diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc index cab260f87ac..60a0d4e6bb2 100644 --- a/source/blender/draw/intern/draw_pbvh.cc +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -389,12 +389,19 @@ struct PBVHBatches { break; case CD_PBVH_MASK_TYPE: - foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { - float *mask = CCG_elem_mask(&args->ccg_key, elems[i]); + if (args->ccg_key.has_mask) { + foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { + float *mask = CCG_elem_mask(&args->ccg_key, elems[i]); - *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = mask ? uchar(*mask * 255.0f) : - 255; - }); + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = uchar(*mask * 255.0f); + }); + } + else { + foreach_grids( + [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int i) { + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = 0; + }); + } break; case CD_PBVH_FSET_TYPE: { @@ -1158,8 +1165,17 @@ struct PBVHBatches { } for (PBVHBatch &batch : batches.values()) { - GPU_batch_elembuf_set(batch.tris, tri_index, false); - GPU_batch_elembuf_set(batch.lines, lines_index, false); + if (tri_index) { + GPU_batch_elembuf_set(batch.tris, tri_index, false); + } + else { + /* Still flag the batch as dirty even if we're using the default index layout. */ + batch.tris->flag |= GPU_BATCH_DIRTY; + } + + if (lines_index) { + GPU_batch_elembuf_set(batch.lines, lines_index, false); + } } } diff --git a/source/blender/draw/intern/draw_resource.cc b/source/blender/draw/intern/draw_resource.cc index f57058190fb..c1f83c3a5ae 100644 --- a/source/blender/draw/intern/draw_resource.cc +++ b/source/blender/draw/intern/draw_resource.cc @@ -38,3 +38,16 @@ bool ObjectAttribute::sync(const blender::draw::ObjectRef &ref, const GPUUniform } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name LayerAttributes + * \{ */ + +bool LayerAttribute::sync(Scene *scene, ViewLayer *layer, const GPULayerAttr &attr) +{ + hash_code = attr.hash_code; + + return BKE_view_layer_find_rgba_attribute(scene, layer, attr.name, &data.x); +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 37899e36d8a..75a7e28fa75 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -15,6 +15,7 @@ typedef struct ObjectBounds ObjectBounds; typedef struct VolumeInfos VolumeInfos; typedef struct CurvesInfos CurvesInfos; typedef struct ObjectAttribute ObjectAttribute; +typedef struct LayerAttribute LayerAttribute; typedef struct DrawCommand DrawCommand; typedef struct DispatchCommand DispatchCommand; typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer; @@ -24,8 +25,10 @@ typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer; # ifdef __cplusplus /* C++ only forward declarations. */ struct Object; +struct ViewLayer; struct ID; struct GPUUniformAttr; +struct GPULayerAttr; namespace blender::draw { @@ -192,6 +195,20 @@ struct ObjectAttribute { * C++ compiler gives us the same size. */ BLI_STATIC_ASSERT_ALIGN(ObjectAttribute, 20) +#pragma pack(push, 4) +struct LayerAttribute { + float4 data; + uint hash_code; + uint buffer_length; /* Only in the first record. */ + uint _pad1, _pad2; + +#if !defined(GPU_SHADER) && defined(__cplusplus) + bool sync(Scene *scene, ViewLayer *layer, const GPULayerAttr &attr); +#endif +}; +#pragma pack(pop) +BLI_STATIC_ASSERT_ALIGN(LayerAttribute, 32) + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/intern/draw_view.hh b/source/blender/draw/intern/draw_view.hh index 4fc74e3e890..94fb62508bb 100644 --- a/source/blender/draw/intern/draw_view.hh +++ b/source/blender/draw/intern/draw_view.hh @@ -79,6 +79,26 @@ class View { return -(data_.winmat[3][2] + 1.0f) / data_.winmat[2][2]; } + const float4x4 &viewmat() const + { + return data_.viewmat; + } + + const float4x4 &viewinv() const + { + return data_.viewinv; + } + + const float4x4 &winmat() const + { + return data_.winmat; + } + + const float4x4 &wininv() const + { + return data_.wininv; + } + private: /** Called from draw manager. */ void bind(); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index d9bb8d1d2b4..c6230e2695e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -16,6 +16,8 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" +#include "BKE_mesh.h" #include "draw_cache_extract.hh" @@ -116,7 +118,7 @@ BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh * BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->ldata; @@ -132,7 +134,7 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->pdata; @@ -148,7 +150,7 @@ BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me) BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->edata; @@ -164,7 +166,7 @@ BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me) BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me) { - switch ((eMeshWrapperType)me->runtime.wrapper_type) { + switch (me->runtime->wrapper_type) { case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->vdata; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index be919b1af67..e40503a9707 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -557,7 +557,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false; if (mr->use_subsurf_fdots) { - const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags; + const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags; const MLoop *mloop = mr->mloop; const int ml_index_end = mp->loopstart + mp->totloop; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc index d964f608e52..1b552b01d6b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc @@ -46,7 +46,7 @@ static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr, GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata); if (mr->use_subsurf_fdots) { - const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags; + const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags; const MLoop *mloop = mr->mloop; const int ml_index_end = mp->loopstart + mp->totloop; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc index 6d93a482623..d43eb6117df 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc @@ -77,7 +77,7 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, const MVert *mvert = mr->mvert; const MLoop *mloop = mr->mloop; - const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags; + const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags; const int ml_index_end = mp->loopstart + mp->totloop; for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc index 96240af2ee6..802f000cb43 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc @@ -74,7 +74,7 @@ static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, void *_data) { MeshExtract_FdotUV_Data *data = static_cast<MeshExtract_FdotUV_Data *>(_data); - const BLI_bitmap *facedot_tags = mr->me->runtime.subsurf_face_dot_tags; + const BLI_bitmap *facedot_tags = mr->me->runtime->subsurf_face_dot_tags; const MLoop *mloop = mr->mloop; const int ml_index_end = mp->loopstart + mp->totloop; diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh index ad0426e6d3f..33634fb5fcb 100644 --- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh +++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh @@ -19,6 +19,14 @@ GPU_SHADER_CREATE_INFO(draw_curves_infos) .typedef_source("draw_shader_shared.h") .uniform_buf(3, "CurvesInfos", "drw_curves", Frequency::BATCH); +GPU_SHADER_CREATE_INFO(draw_layer_attributes) + .typedef_source("draw_shader_shared.h") + .define("VLATTR_LIB") + .uniform_buf(DRW_LAYER_ATTR_UBO_SLOT, + "LayerAttribute", + "drw_layer_attrs[DRW_RESOURCE_CHUNK_LEN]", + Frequency::BATCH); + GPU_SHADER_CREATE_INFO(draw_object_infos_new) .typedef_source("draw_shader_shared.h") .define("OBINFO_LIB") diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index cb6652507ed..61e92f0a1c3 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1707,6 +1707,10 @@ static void ed_surf_delete_selected(Object *obedit) bp++; } if (a == 0) { + if (cu->actnu == BLI_findindex(editnurb, nu)) { + cu->actnu = CU_ACT_NONE; + } + BLI_remlink(editnurb, nu); keyIndex_delNurb(cu->editnurb, nu); BKE_nurb_free(nu); @@ -6483,6 +6487,7 @@ static int curve_delete_exec(bContext *C, wmOperator *op) } else if (type == CURVE_SEGMENT) { changed = curve_delete_segments(obedit, v3d, false); + cu->actnu = CU_ACT_NONE; } else { BLI_assert(0); @@ -6490,7 +6495,7 @@ static int curve_delete_exec(bContext *C, wmOperator *op) if (changed) { changed_multi = true; - cu->actnu = cu->actvert = CU_ACT_NONE; + cu->actvert = CU_ACT_NONE; if (ED_curve_updateAnimPaths(bmain, obedit->data)) { WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 340288b2d74..c6d7eb294fb 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -623,6 +623,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) true, "Only Active", "Copy only active Layer, uncheck to append all layers"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } @@ -3686,6 +3687,7 @@ void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot) true, "Only Active", "Append only active material, uncheck to append all materials"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index c30b8c5ec6a..24e14fdce72 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -87,17 +87,6 @@ void ED_node_tag_update_id(struct ID *id); float ED_node_grid_size(void); -/* node_relationships.cc */ - -/** - * Test == 0, clear all intersect flags. - */ -void ED_node_link_intersect_test(struct ScrArea *area, int test); -/** - * Assumes link with #NODE_LINKFLAG_HILITE set. - */ -void ED_node_link_insert(struct Main *bmain, struct ScrArea *area); - /* node_edit.cc */ void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo); @@ -186,3 +175,20 @@ bool ED_space_node_color_sample(struct Main *bmain, #ifdef __cplusplus } #endif + +#ifdef __cplusplus + +/* node_relationships.cc */ + +namespace blender::ed::space_node { + +void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion); +/** + * Assumes link with #NODE_LINKFLAG_HILITE set. + */ +void node_insert_on_link_flags(Main &bmain, SpaceNode &snode); +void node_insert_on_link_flags_clear(bNodeTree &node_tree); + +} // namespace blender::ed::space_node + +#endif
\ No newline at end of file diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index b499ae0ce59..c8ffbb9acb1 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -339,12 +339,20 @@ bool ED_uvedit_udim_params_from_image_space(const struct SpaceImage *sima, bool use_active, struct UVMapUDIM_Params *udim_params); +typedef enum { + ED_UVPACK_MARGIN_SCALED = 0, /* Use scale of existing UVs to multiply margin. */ + ED_UVPACK_MARGIN_ADD, /* Just add the margin, ignoring any UV scale. */ + ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */ +} eUVPackIsland_MarginMethod; + struct UVPackIsland_Params { uint rotate : 1; uint only_selected_uvs : 1; uint only_selected_faces : 1; uint use_seams : 1; uint correct_aspect : 1; + eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */ + float margin; /* Additional space to add around each island. */ }; /** @@ -353,9 +361,24 @@ struct UVPackIsland_Params { bool uv_coords_isect_udim(const struct Image *image, const int udim_grid[2], const float coords[2]); + +/** + * Pack UV islands from multiple objects. + * + * \param scene: Scene containing the objects to be packed. + * \param objects: Array of Objects to pack. + * \param objects_len: Length of `objects` array. + * \param bmesh_override: BMesh array aligned with `objects`. + * Optional, when non-null this overrides object's BMesh. + * This is needed to perform UV packing on objects that aren't in edit-mode. + * \param udim_params: Parameters to specify UDIM target and UDIM source image. + * \param params: Parameters and options to pass to the packing engine. + * + */ void ED_uvedit_pack_islands_multi(const struct Scene *scene, Object **objects, uint objects_len, + struct BMesh **bmesh_override, const struct UVMapUDIM_Params *udim_params, const struct UVPackIsland_Params *params); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index c357b67722d..f0bf04ed408 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -103,7 +103,7 @@ enum eView2D_CommonViewTypes { /** \} */ /* -------------------------------------------------------------------- */ -/** \name Foeard Declarations +/** \name Forward Declarations * \{ */ struct View2D; diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc index ebfde05f516..60e1c0abfa1 100644 --- a/source/blender/editors/interface/interface_dropboxes.cc +++ b/source/blender/editors/interface/interface_dropboxes.cc @@ -89,7 +89,7 @@ static void ui_drop_material_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *dro static char *ui_drop_material_tooltip(bContext *C, wmDrag *drag, - const int UNUSED(xy[2]), + const int /*xy*/[2], struct wmDropBox * /*drop*/) { PointerRNA rna_ptr = CTX_data_pointer_get_type(C, "object", &RNA_Object); diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc index 9dd6f95e190..f443dd43a3a 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.cc +++ b/source/blender/editors/interface/interface_region_menu_pie.cc @@ -222,7 +222,7 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } - pie = UI_pie_menu_begin(C, IFACE_(mt->label), ICON_NONE, event); + pie = UI_pie_menu_begin(C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE, event); layout = UI_pie_menu_layout(pie); UI_menutype_draw(C, mt, layout); diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc index f88cabb2b70..569f657a544 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.cc +++ b/source/blender/editors/interface/interface_region_menu_popup.cc @@ -175,11 +175,7 @@ struct uiPopupMenu { static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup) { - uiBlock *block; uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup); - int minwidth, width, height; - char direction; - bool flip; if (pup->menu_func) { pup->block->handle = handle; @@ -188,6 +184,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi } /* Find block minimum width. */ + int minwidth; if (uiLayoutGetUnitsX(pup->layout) != 0.0f) { /* Use the minimum width from the layout if it's set. */ minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X; @@ -207,6 +204,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi } /* Find block direction. */ + char direction; if (pup->but) { if (pup->block->direction != 0) { /* allow overriding the direction from menu_func */ @@ -220,9 +218,9 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi direction = UI_DIR_DOWN; } - flip = (direction == UI_DIR_DOWN); + bool flip = (direction == UI_DIR_DOWN); - block = pup->block; + uiBlock *block = pup->block; /* in some cases we create the block before the region, * so we set it delayed here if necessary */ @@ -232,6 +230,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi block->direction = direction; + int width, height; UI_block_layout_resolve(block, &width, &height); UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT); @@ -318,7 +317,6 @@ uiPopupBlockHandle *ui_popup_menu_create( { wmWindow *window = CTX_wm_window(C); const uiStyle *style = UI_style_get_dpi(); - uiPopupBlockHandle *handle; uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__); pup->block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS_PULLDOWN); @@ -357,7 +355,8 @@ uiPopupBlockHandle *ui_popup_menu_create( pup->menu_func = menu_func; pup->menu_arg = arg; - handle = ui_popup_block_create(C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr); + uiPopupBlockHandle *handle = ui_popup_block_create( + C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr); if (!but) { handle->popup = true; @@ -384,7 +383,6 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, { const uiStyle *style = UI_style_get_dpi(); uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__); - uiBut *but; pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN); pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP; @@ -423,7 +421,7 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, ""); } else { - but = uiDefBut( + uiBut *but = uiDefBut( pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, ""); but->drawflag = UI_BUT_TEXT_LEFT; } @@ -448,20 +446,20 @@ void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *b void UI_popup_menu_end(bContext *C, uiPopupMenu *pup) { wmWindow *window = CTX_wm_window(C); - uiPopupBlockHandle *menu; - uiBut *but = nullptr; - ARegion *butregion = nullptr; pup->popup = true; pup->mx = window->eventstate->xy[0]; pup->my = window->eventstate->xy[1]; + uiBut *but = nullptr; + ARegion *butregion = nullptr; if (pup->but) { but = pup->but; butregion = pup->butregion; } - menu = ui_popup_block_create(C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr); + uiPopupBlockHandle *menu = ui_popup_block_create( + C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr); menu->popup = true; UI_popup_handlers_add(C, &window->modalhandlers, menu, 0); @@ -545,8 +543,6 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports) int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) { - uiPopupMenu *pup; - uiLayout *layout; MenuType *mt = WM_menutype_find(idname, true); if (mt == nullptr) { @@ -559,8 +555,9 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } - pup = UI_popup_menu_begin(C, IFACE_(mt->label), ICON_NONE); - layout = UI_popup_menu_layout(pup); + uiPopupMenu *pup = UI_popup_menu_begin( + C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); UI_menutype_draw(C, mt, layout); @@ -579,9 +576,9 @@ void UI_popup_block_invoke_ex( bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free, bool can_refresh) { wmWindow *window = CTX_wm_window(C); - uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, nullptr, nullptr, func, nullptr, arg, arg_free); + uiPopupBlockHandle *handle = ui_popup_block_create( + C, nullptr, nullptr, func, nullptr, arg, arg_free); handle->popup = true; /* It can be useful to disable refresh (even though it will work) @@ -607,9 +604,9 @@ void UI_popup_block_ex(bContext *C, wmOperator *op) { wmWindow *window = CTX_wm_window(C); - uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, nullptr, nullptr, func, nullptr, arg, nullptr); + uiPopupBlockHandle *handle = ui_popup_block_create( + C, nullptr, nullptr, func, nullptr, arg, nullptr); handle->popup = true; handle->retvalue = 1; handle->can_refresh = true; diff --git a/source/blender/editors/interface/interface_region_popup.cc b/source/blender/editors/interface/interface_region_popup.cc index e93bc4c4bfe..e574cb30b23 100644 --- a/source/blender/editors/interface/interface_region_popup.cc +++ b/source/blender/editors/interface/interface_region_popup.cc @@ -69,7 +69,6 @@ static void ui_popup_block_position(wmWindow *window, /* Compute button position in window coordinates using the source * button region/block, to position the popup attached to it. */ rctf butrct; - if (!handle->refresh) { ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect); @@ -417,14 +416,13 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block) { const float xmin_orig = block->rect.xmin; const int margin = UI_SCREEN_MARGIN; - int winx, winy; if (block->flag & UI_BLOCK_NO_WIN_CLIP) { return; } - winx = WM_window_pixels_x(window); - winy = WM_window_pixels_y(window); + const int winx = WM_window_pixels_x(window); + const int winy = WM_window_pixels_y(window); /* shift to left if outside of view */ if (block->rect.xmax > winx - margin) { @@ -549,7 +547,6 @@ uiBlock *ui_popup_block_refresh(bContext *C, void *arg = handle->popup_create_vars.arg; uiBlock *block_old = static_cast<uiBlock *>(region->uiblocks.first); - uiBlock *block; handle->refresh = (block_old != nullptr); @@ -561,6 +558,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, #endif /* create ui block */ + uiBlock *block; if (create_func) { block = create_func(C, region, arg); } @@ -618,16 +616,14 @@ uiBlock *ui_popup_block_refresh(bContext *C, if (block->flag & UI_BLOCK_RADIAL) { const int win_width = UI_SCREEN_MARGIN; - int winx, winy; - - int x_offset = 0, y_offset = 0; - winx = WM_window_pixels_x(window); - winy = WM_window_pixels_y(window); + const int winx = WM_window_pixels_x(window); + const int winy = WM_window_pixels_y(window); copy_v2_v2(block->pie_data.pie_center_init, block->pie_data.pie_center_spawned); /* only try translation if area is large enough */ + int x_offset = 0; if (BLI_rctf_size_x(&block->rect) < winx - (2.0f * win_width)) { if (block->rect.xmin < win_width) { x_offset += win_width - block->rect.xmin; @@ -637,6 +633,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, } } + int y_offset = 0; if (BLI_rctf_size_y(&block->rect) < winy - (2.0f * win_width)) { if (block->rect.ymin < win_width) { y_offset += win_width - block->rect.ymin; @@ -756,9 +753,6 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, { wmWindow *window = CTX_wm_window(C); uiBut *activebut = UI_context_active_but_get(C); - static ARegionType type; - ARegion *region; - uiBlock *block; /* disable tooltips from buttons below */ if (activebut) { @@ -787,9 +781,10 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, handle->can_refresh = false; /* create area region */ - region = ui_region_temp_add(CTX_wm_screen(C)); + ARegion *region = ui_region_temp_add(CTX_wm_screen(C)); handle->region = region; + static ARegionType type; memset(&type, 0, sizeof(ARegionType)); type.draw = ui_block_region_draw; type.layout = ui_block_region_refresh; @@ -798,7 +793,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, UI_region_handlers_add(®ion->handlers); - block = ui_popup_block_refresh(C, handle, butregion, but); + uiBlock *block = ui_popup_block_refresh(C, handle, butregion, but); handle = block->handle; /* keep centered on window resizing */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index d21f969e431..a3259831c9f 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3269,7 +3269,7 @@ void uiTemplatePreview(uiLayout *layout, uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, - IFACE_("World"), + CTX_IFACE_(BLT_I18NCONTEXT_ID_WORLD, "World"), 0, 0, UI_UNIT_X * 10, diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index d4855f470ff..100d56a6b0d 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -658,7 +658,7 @@ void WM_OT_alembic_import(wmOperatorType *ot) ot->name = "Import Alembic"; ot->description = "Load an Alembic archive"; ot->idname = "WM_OT_alembic_import"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET; ot->invoke = wm_alembic_import_invoke; ot->exec = wm_alembic_import_exec; diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 1048d0eca32..a630f150e0e 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -770,14 +770,12 @@ void WM_OT_collada_import(wmOperatorType *ot) ot->name = "Import COLLADA"; ot->description = "Load a Collada file"; ot->idname = "WM_OT_collada_import"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET; ot->invoke = WM_operator_filesel; ot->exec = wm_collada_import_exec; ot->poll = WM_operator_winactive; - // ot->flag = OPTYPE_PRESET; - ot->ui = wm_collada_import_draw; WM_operator_properties_filesel(ot, diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index cb8eafeb52d..7559cd47b27 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -81,7 +81,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op) export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); export_params.up_axis = RNA_enum_get(op->ptr, "up_axis"); - export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor"); + export_params.global_scale = RNA_float_get(op->ptr, "global_scale"); export_params.apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers"); export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode"); @@ -122,7 +122,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) col = uiLayoutColumn(box, false); sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to")); uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE); - uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE); + uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE); row = uiLayoutRow(box, false); uiItemR(row, imfptr, "forward_axis", UI_ITEM_R_EXPAND, IFACE_("Forward Axis"), ICON_NONE); @@ -301,15 +301,16 @@ void WM_OT_obj_export(struct wmOperatorType *ot) RNA_def_property_update_runtime(prop, (void *)forward_axis_update); prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", ""); RNA_def_property_update_runtime(prop, (void *)up_axis_update); - RNA_def_float(ot->srna, - "scaling_factor", - 1.0f, - 0.001f, - 10000.0f, - "Scale", - "Upscale the object by this factor", - 0.01, - 1000.0f); + RNA_def_float( + ot->srna, + "global_scale", + 1.0f, + 0.0001f, + 10000.0f, + "Scale", + "Value by which to enlarge or shrink the objects with respect to the world's origin", + 0.0001f, + 10000.0f); /* File Writer options. */ RNA_def_boolean( ot->srna, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes"); @@ -405,6 +406,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op) { struct OBJImportParams import_params; RNA_string_get(op->ptr, "filepath", import_params.filepath); + import_params.global_scale = RNA_float_get(op->ptr, "global_scale"); import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size"); import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); import_params.up_axis = RNA_enum_get(op->ptr, "up_axis"); @@ -459,6 +461,7 @@ static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr) uiItemL(box, IFACE_("Transform"), ICON_OBJECT_DATA); uiLayout *col = uiLayoutColumn(box, false); uiLayout *sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE); uiItemR(sub, imfptr, "clamp_size", 0, NULL, ICON_NONE); sub = uiLayoutColumn(col, false); @@ -489,7 +492,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot) ot->name = "Import Wavefront OBJ"; ot->description = "Load a Wavefront OBJ scene"; ot->idname = "WM_OT_obj_import"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET; ot->invoke = wm_obj_import_invoke; ot->exec = wm_obj_import_exec; @@ -506,6 +509,16 @@ void WM_OT_obj_import(struct wmOperatorType *ot) FILE_SORT_DEFAULT); RNA_def_float( ot->srna, + "global_scale", + 1.0f, + 0.0001f, + 10000.0f, + "Scale", + "Value by which to enlarge or shrink the objects with respect to the world's origin", + 0.0001f, + 10000.0f); + RNA_def_float( + ot->srna, "clamp_size", 0.0f, 0.0f, diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c index c98e5beaf3b..c27d42a07c0 100644 --- a/source/blender/editors/io/io_stl_ops.c +++ b/source/blender/editors/io/io_stl_ops.c @@ -95,7 +95,7 @@ void WM_OT_stl_import(struct wmOperatorType *ot) ot->exec = wm_stl_import_execute; ot->poll = WM_operator_winactive; ot->check = wm_stl_import_check; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index eb80cabcd7f..c776fbf0dd7 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -500,7 +500,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot) ot->poll = WM_operator_winactive; ot->ui = wm_usd_import_draw; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_USD, diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index e9897021b4a..a147594b25b 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -100,7 +100,7 @@ typedef struct KnifeColors { /* Knife-tool Operator. */ typedef struct KnifeVert { Object *ob; - uint base_index; + uint ob_index; BMVert *v; /* Non-NULL if this is an original vert. */ ListBase edges; ListBase faces; @@ -142,7 +142,7 @@ typedef struct KnifeLineHit { KnifeVert *v; BMFace *f; Object *ob; - uint base_index; + uint ob_index; } KnifeLineHit; typedef struct KnifePosData { @@ -156,7 +156,7 @@ typedef struct KnifePosData { KnifeEdge *edge; BMFace *bmface; Object *ob; /* Object of the vert, edge or bmface. */ - uint base_index; + uint ob_index; /* When true, the cursor isn't over a face. */ bool is_space; @@ -182,7 +182,7 @@ typedef struct KnifeBVH { BVHTree *tree; /* Knife Custom BVH Tree. */ BMLoop *(*looptris)[3]; /* Used by #knife_bvh_raycast_cb to store the intersecting looptri. */ float uv[2]; /* Used by #knife_bvh_raycast_cb to store the intersecting uv. */ - uint base_index; + uint ob_index; /* Use #bm_ray_cast_cb_elem_not_in_face_check. */ bool (*filter_cb)(BMFace *f, void *userdata); @@ -218,6 +218,7 @@ typedef struct KnifeTool_OpData { /* Used for swapping current object when in multi-object edit mode. */ Object **objects; uint objects_len; + bool objects_free; /** Array `objects_len` length of additional per-object data. */ KnifeObjectInfo *objects_info; @@ -1158,11 +1159,11 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k * \{ */ static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd, - int base_index, + int ob_index, int tri_index, int tri_index_buf[3]) { - const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index]; + const KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index]; if (obinfo->tri_indices) { return obinfo->tri_indices[tri_index]; } @@ -1173,25 +1174,25 @@ static const int *knife_bm_tri_index_get(const KnifeTool_OpData *kcd, } static void knife_bm_tri_cagecos_get(const KnifeTool_OpData *kcd, - int base_index, + int ob_index, int tri_index, float cos[3][3]) { - const KnifeObjectInfo *obinfo = &kcd->objects_info[base_index]; + const KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index]; int tri_ind_buf[3]; - const int *tri_ind = knife_bm_tri_index_get(kcd, base_index, tri_index, tri_ind_buf); + const int *tri_ind = knife_bm_tri_index_get(kcd, ob_index, tri_index, tri_ind_buf); for (int i = 0; i < 3; i++) { copy_v3_v3(cos[i], obinfo->cagecos[tri_ind[i]]); } } static void knife_bm_tri_cagecos_get_worldspace(const KnifeTool_OpData *kcd, - int base_index, + int ob_index, int tri_index, float cos[3][3]) { - knife_bm_tri_cagecos_get(kcd, base_index, tri_index, cos); - const Object *ob = kcd->objects[base_index]; + knife_bm_tri_cagecos_get(kcd, ob_index, tri_index, cos); + const Object *ob = kcd->objects[ob_index]; for (int i = 0; i < 3; i++) { mul_m4_v3(ob->obmat, cos[i]); } @@ -1236,9 +1237,9 @@ static void knife_bvh_init(KnifeTool_OpData *kcd) bool test_fn_ret = false; /* Calculate tottri. */ - for (uint b = 0; b < kcd->objects_len; b++) { + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { ob_tottri = 0; - ob = kcd->objects[b]; + ob = kcd->objects[ob_index]; em = BKE_editmesh_from_object(ob); for (int i = 0; i < em->tottri; i++) { @@ -1268,8 +1269,8 @@ static void knife_bvh_init(KnifeTool_OpData *kcd) * Don't forget to update #knife_bvh_intersect_plane! */ tottri = 0; - for (uint b = 0; b < kcd->objects_len; b++) { - ob = kcd->objects[b]; + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + ob = kcd->objects[ob_index]; em = BKE_editmesh_from_object(ob); looptris = em->looptris; @@ -1286,7 +1287,7 @@ static void knife_bvh_init(KnifeTool_OpData *kcd) } float tri_cos[3][3]; - knife_bm_tri_cagecos_get_worldspace(kcd, b, i, tri_cos); + knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, i, tri_cos); BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, &tri_cos[0][0], 3); } @@ -1324,10 +1325,10 @@ static void knife_bvh_raycast_cb(void *userdata, int tottri; tottri = 0; - uint b = 0; - for (; b < kcd->objects_len; b++) { + uint ob_index = 0; + for (; ob_index < kcd->objects_len; ob_index++) { index -= tottri; - ob = kcd->objects[b]; + ob = kcd->objects[ob_index]; em = BKE_editmesh_from_object(ob); tottri = em->tottri; if (index < tottri) { @@ -1343,7 +1344,7 @@ static void knife_bvh_raycast_cb(void *userdata, } float tri_cos[3][3]; - knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos); + knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, index, tri_cos); isect = (ray->radius > 0.0f ? isect_ray_tri_epsilon_v3( ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv, ray->radius) : @@ -1370,7 +1371,7 @@ static void knife_bvh_raycast_cb(void *userdata, kcd->bvh.looptris = em->looptris; copy_v2_v2(kcd->bvh.uv, uv); - kcd->bvh.base_index = b; + kcd->bvh.ob_index = ob_index; } } @@ -1382,7 +1383,7 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd, float *r_dist, float r_hitout[3], float r_cagehit[3], - uint *r_base_index) + uint *r_ob_index) { BMFace *face; BVHTreeRayHit hit; @@ -1399,7 +1400,7 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd, /* Hits returned in world space. */ if (r_hitout) { float tri_cos[3][3]; - knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos); + knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.ob_index, hit.index, tri_cos); interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv); if (r_cagehit) { @@ -1411,8 +1412,8 @@ static BMFace *knife_bvh_raycast(KnifeTool_OpData *kcd, *r_dist = hit.dist; } - if (r_base_index) { - *r_base_index = kcd->bvh.base_index; + if (r_ob_index) { + *r_ob_index = kcd->bvh.ob_index; } return face; @@ -1428,7 +1429,7 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd, float *r_dist, float r_hitout[3], float r_cagehit[3], - uint *r_base_index, + uint *r_ob_index, bool (*filter_cb)(BMFace *f, void *userdata), void *filter_userdata) { @@ -1453,7 +1454,7 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd, /* Hits returned in world space. */ if (r_hitout) { float tri_cos[3][3]; - knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.base_index, hit.index, tri_cos); + knife_bm_tri_cagecos_get_worldspace(kcd, kcd->bvh.ob_index, hit.index, tri_cos); interp_v3_v3v3v3_uv(r_hitout, UNPACK3(tri_cos), kcd->bvh.uv); if (r_cagehit) { @@ -1465,8 +1466,8 @@ static BMFace *knife_bvh_raycast_filter(KnifeTool_OpData *kcd, *r_dist = hit.dist; } - if (r_base_index) { - *r_base_index = kcd->bvh.base_index; + if (r_ob_index) { + *r_ob_index = kcd->bvh.ob_index; } return face; @@ -1726,7 +1727,7 @@ static KnifeEdge *new_knife_edge(KnifeTool_OpData *kcd) } /* Get a KnifeVert wrapper for an existing BMVert. */ -static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob, uint base_index) +static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob, uint ob_index) { KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v); const float *cageco; @@ -1736,7 +1737,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob BMFace *f; if (BM_elem_index_get(v) >= 0) { - cageco = kcd->objects_info[base_index].cagecos[BM_elem_index_get(v)]; + cageco = kcd->objects_info[ob_index].cagecos[BM_elem_index_get(v)]; } else { cageco = v->co; @@ -1748,7 +1749,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob kfv = new_knife_vert(kcd, v->co, cageco_ws); kfv->v = v; kfv->ob = ob; - kfv->base_index = base_index; + kfv->ob_index = ob_index; BLI_ghash_insert(kcd->origvertmap, v, kfv); BM_ITER_ELEM (f, &bmiter, v, BM_FACES_OF_VERT) { @@ -1760,7 +1761,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob } /* Get a KnifeEdge wrapper for an existing BMEdge. */ -static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob, uint base_index) +static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob, uint ob_index) { KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e); if (!kfe) { @@ -1769,8 +1770,8 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob kfe = new_knife_edge(kcd); kfe->e = e; - kfe->v1 = get_bm_knife_vert(kcd, e->v1, ob, base_index); - kfe->v2 = get_bm_knife_vert(kcd, e->v2, ob, base_index); + kfe->v1 = get_bm_knife_vert(kcd, e->v1, ob, ob_index); + kfe->v2 = get_bm_knife_vert(kcd, e->v2, ob, ob_index); knife_add_to_vert_edges(kcd, kfe); @@ -1784,10 +1785,7 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e, Object *ob return kfe; } -static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, - Object *ob, - uint base_index, - BMFace *f) +static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, Object *ob, uint ob_index, BMFace *f) { ListBase *list = BLI_ghash_lookup(kcd->kedgefacemap, f); @@ -1798,7 +1796,7 @@ static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, list = knife_empty_list(kcd); BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) { - knife_append_list(kcd, list, get_bm_knife_edge(kcd, e, ob, base_index)); + knife_append_list(kcd, list, get_bm_knife_edge(kcd, e, ob, ob_index)); } BLI_ghash_insert(kcd->kedgefacemap, f, list); @@ -1809,7 +1807,7 @@ static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace *f) { - knife_append_list(kcd, knife_get_face_kedges(kcd, kfe->v1->ob, kfe->v1->base_index, f), kfe); + knife_append_list(kcd, knife_get_face_kedges(kcd, kfe->v1->ob, kfe->v1->ob_index, f), kfe); knife_append_list(kcd, &kfe->faces, f); } @@ -1826,7 +1824,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, newkfe->v1 = kfe->v1; newkfe->v2 = new_knife_vert(kcd, co, cageco); newkfe->v2->ob = kfe->v1->ob; - newkfe->v2->base_index = kfe->v1->base_index; + newkfe->v2->ob_index = kfe->v1->ob_index; newkfe->v2->is_cut = true; if (kfe->e) { knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e); @@ -2123,7 +2121,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, BLI_assert(lh1->f); kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit); kfe->v1->ob = lh1->ob; - kfe->v1->base_index = lh1->base_index; + kfe->v1->ob_index = lh1->ob_index; kfe->v1->is_cut = true; kfe->v1->is_face = true; knife_append_list(kcd, &kfe->v1->faces, lh1->f); @@ -2141,7 +2139,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, BLI_assert(lh2->f); kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit); kfe->v2->ob = lh2->ob; - kfe->v2->base_index = lh2->base_index; + kfe->v2->ob_index = lh2->ob_index; kfe->v2->is_cut = true; kfe->v2->is_face = true; knife_append_list(kcd, &kfe->v2->faces, lh2->f); @@ -2567,7 +2565,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, const float v1[3], const float v2[3], Object *ob, - uint base_index, + uint ob_index, BMFace *f, const float face_tol_sq, float hit_co[3], @@ -2600,7 +2598,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, break; } - knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, tri_cos); + knife_bm_tri_cagecos_get_worldspace(kcd, ob_index, tri_i, tri_cos); /* Using epsilon test in case ray is directly through an internal * tessellation edge and might not hit either tessellation tri with @@ -2617,7 +2615,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, } interp_v3_v3v3v3_uv(hit_cageco, UNPACK3(tri_cos), ray_tri_uv); /* Now check that far enough away from verts and edges. */ - list = knife_get_face_kedges(kcd, ob, base_index, f); + list = knife_get_face_kedges(kcd, ob, ob_index, f); for (ref = list->first; ref; ref = ref->next) { kfe = ref->ref; if (kfe->is_invalid) { @@ -2651,11 +2649,11 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) float ws[3]; INIT_MINMAX(min, max); - for (uint b = 0; b < kcd->objects_len; b++) { - ob = kcd->objects[b]; + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + ob = kcd->objects[ob_index]; em = BKE_editmesh_from_object(ob); - const float(*cagecos)[3] = kcd->objects_info[b].cagecos; + const float(*cagecos)[3] = kcd->objects_info[ob_index].cagecos; if (cagecos) { for (int i = 0; i < em->bm->totvert; i++) { copy_v3_v3(ws, cagecos[i]); @@ -2930,11 +2928,11 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) Object *ob; BMEditMesh *em; - uint b = 0; for (i = 0, result = results; i < tot; i++, result++) { - for (b = 0; b < kcd->objects_len; b++) { - ob = kcd->objects[b]; + uint ob_index = 0; + for (ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + ob = kcd->objects[ob_index]; em = BKE_editmesh_from_object(ob); if (*result >= 0 && *result < em->tottri) { ls = (BMLoop **)em->looptris[*result]; @@ -2956,9 +2954,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } /* Don't care what the value is except that it is non-NULL, for iterator. */ BLI_smallhash_insert(&faces, (uintptr_t)f, f); - BLI_smallhash_insert(&fobs, (uintptr_t)f, (void *)(uintptr_t)b); + BLI_smallhash_insert(&fobs, (uintptr_t)f, (void *)(uintptr_t)ob_index); - list = knife_get_face_kedges(kcd, ob, b, f); + list = knife_get_face_kedges(kcd, ob, ob_index, f); for (ref = list->first; ref; ref = ref->next) { kfe = ref->ref; if (kfe->is_invalid) { @@ -3033,7 +3031,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } hit.ob = v->ob; - hit.base_index = v->base_index; + hit.ob_index = v->ob_index; copy_v3_v3(hit.hit, v->co); copy_v3_v3(hit.cagehit, v->cageco); copy_v2_v2(hit.schit, s); @@ -3109,7 +3107,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) transform_point_by_seg_v3( hit.hit, p_cage, kfe->v1->co, kfe->v2->co, kfe->v1->cageco, kfe->v2->cageco); hit.ob = kfe->v1->ob; - hit.base_index = kfe->v1->base_index; + hit.ob_index = kfe->v1->ob_index; copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, sint); hit.perc = lambda; @@ -3129,16 +3127,16 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) { float p[3], p_cage[3]; - uint base_index = (uint)(uintptr_t)BLI_smallhash_lookup(&fobs, (uintptr_t)f); - ob = kcd->objects[base_index]; + uint ob_index = (uint)(uintptr_t)BLI_smallhash_lookup(&fobs, (uintptr_t)f); + ob = kcd->objects[ob_index]; if (use_hit_prev && - knife_ray_intersect_face(kcd, s1, v1, v3, ob, base_index, f, face_tol_sq, p, p_cage)) { + knife_ray_intersect_face(kcd, s1, v1, v3, ob, ob_index, f, face_tol_sq, p, p_cage)) { if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) { memset(&hit, 0, sizeof(hit)); hit.f = f; hit.ob = ob; - hit.base_index = base_index; + hit.ob_index = ob_index; copy_v3_v3(hit.hit, p); copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, s1); @@ -3148,12 +3146,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } if (use_hit_curr && - knife_ray_intersect_face(kcd, s2, v2, v4, ob, base_index, f, face_tol_sq, p, p_cage)) { + knife_ray_intersect_face(kcd, s2, v2, v4, ob, ob_index, f, face_tol_sq, p, p_cage)) { if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) { memset(&hit, 0, sizeof(hit)); hit.f = f; hit.ob = ob; - hit.base_index = base_index; + hit.ob_index = ob_index; copy_v3_v3(hit.hit, p); copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, s2); @@ -3205,7 +3203,7 @@ static void knife_pos_data_clear(KnifePosData *kpd) static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, Object **r_ob, - uint *r_base_index, + uint *r_ob_index, bool *is_space, float r_co[3], float r_cageco[3]) @@ -3221,7 +3219,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, sub_v3_v3v3(ray, origin_ofs, origin); normalize_v3_v3(ray_normal, ray); - f = knife_bvh_raycast(kcd, origin, ray_normal, 0.0f, NULL, r_co, r_cageco, r_base_index); + f = knife_bvh_raycast(kcd, origin, ray_normal, 0.0f, NULL, r_co, r_cageco, r_ob_index); if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) { f = NULL; @@ -3232,7 +3230,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, } if (f) { - *r_ob = kcd->objects[*r_base_index]; + *r_ob = kcd->objects[*r_ob_index]; } else { if (kcd->is_interactive) { @@ -3267,7 +3265,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd, const float radius, Object *ob, - uint base_index, + uint ob_index, BMFace *f, const float cageco[3]) { @@ -3280,7 +3278,7 @@ static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd, knife_project_v2(kcd, cageco, sco); - list = knife_get_face_kedges(kcd, ob, base_index, f); + list = knife_get_face_kedges(kcd, ob, ob_index, f); for (ref = list->first; ref; ref = ref->next) { KnifeEdge *kfe = ref->ref; int i; @@ -3329,7 +3327,7 @@ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize) if (!kcd->curr.is_space) { density = (float)knife_sample_screen_density_from_closest_face( - kcd, maxsize * 2.0f, kcd->curr.ob, kcd->curr.base_index, kcd->curr.bmface, kcd->curr.cage); + kcd, maxsize * 2.0f, kcd->curr.ob, kcd->curr.ob_index, kcd->curr.bmface, kcd->curr.cage); } return density ? min_ff(maxsize / ((float)density * 0.5f), maxsize) : maxsize; @@ -3388,7 +3386,7 @@ static void knife_interp_v3_v3v3(const KnifeTool_OpData *kcd, /* p is closest point on edge to the mouse cursor. */ static KnifeEdge *knife_find_closest_edge_of_face( - KnifeTool_OpData *kcd, Object *ob, uint base_index, BMFace *f, float p[3], float cagep[3]) + KnifeTool_OpData *kcd, Object *ob, uint ob_index, BMFace *f, float p[3], float cagep[3]) { float sco[2]; float maxdist; @@ -3414,7 +3412,7 @@ static KnifeEdge *knife_find_closest_edge_of_face( knife_project_v2(kcd, cagep, sco); /* Look through all edges associated with this face. */ - list = knife_get_face_kedges(kcd, ob, base_index, f); + list = knife_get_face_kedges(kcd, ob, ob_index, f); for (ref = list->first; ref; ref = ref->next) { KnifeEdge *kfe = ref->ref; float kfv1_sco[2], kfv2_sco[2], test_cagep[3]; @@ -3479,7 +3477,7 @@ static KnifeEdge *knife_find_closest_edge_of_face( * this is important for angle snap, which uses the previous mouse position. */ edgesnap = new_knife_vert(kcd, p, cagep); edgesnap->ob = ob; - edgesnap->base_index = base_index; + edgesnap->ob_index = ob_index; knife_project_v2(kcd, edgesnap->cageco, kcd->curr.mval); } @@ -3906,14 +3904,14 @@ static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[ kcd->curr.ob = kcd->vc.obedit; kcd->curr.bmface = knife_find_closest_face(kcd, &kcd->curr.ob, - &kcd->curr.base_index, + &kcd->curr.ob_index, &kcd->curr.is_space, kcd->curr.co, kcd->curr.cage); if (kcd->curr.bmface) { kcd->curr.edge = knife_find_closest_edge_of_face( - kcd, kcd->curr.ob, kcd->curr.base_index, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage); + kcd, kcd->curr.ob, kcd->curr.ob_index, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage); } if (kcd->curr.edge) { @@ -4017,7 +4015,7 @@ static void knifetool_undo(KnifeTool_OpData *kcd) static void knifetool_init_obinfo(KnifeTool_OpData *kcd, Object *ob, - uint base_index, + uint ob_index, bool use_tri_indices) { @@ -4027,7 +4025,7 @@ static void knifetool_init_obinfo(KnifeTool_OpData *kcd, BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT); - KnifeObjectInfo *obinfo = &kcd->objects_info[base_index]; + KnifeObjectInfo *obinfo = &kcd->objects_info[ob_index]; obinfo->em = em_eval; obinfo->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc( kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL); @@ -4045,10 +4043,10 @@ static void knifetool_init_obinfo(KnifeTool_OpData *kcd, } } -static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint base_index) +static void knifetool_free_obinfo(KnifeTool_OpData *kcd, uint ob_index) { - MEM_SAFE_FREE(kcd->objects_info[base_index].cagecos); - MEM_SAFE_FREE(kcd->objects_info[base_index].tri_indices); + MEM_SAFE_FREE(kcd->objects_info[ob_index].cagecos); + MEM_SAFE_FREE(kcd->objects_info[ob_index].tri_indices); } /** \} */ @@ -4081,6 +4079,8 @@ static void knife_init_colors(KnifeColors *colors) /* called when modal loop selection gets set up... */ static void knifetool_init(ViewContext *vc, KnifeTool_OpData *kcd, + Object **objects, + const int objects_len, const bool only_select, const bool cut_through, const bool xray, @@ -4101,16 +4101,24 @@ static void knifetool_init(ViewContext *vc, kcd->scene = scene; kcd->region = vc->region; - kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( - vc->scene, vc->view_layer, vc->v3d, &kcd->objects_len); + if (objects) { + kcd->objects = objects; + kcd->objects_len = objects_len; + kcd->objects_free = false; + } + else { + kcd->objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + vc->scene, vc->view_layer, vc->v3d, &kcd->objects_len); + kcd->objects_free = true; + } Object *ob; BMEditMesh *em; kcd->objects_info = MEM_callocN(sizeof(*kcd->objects_info) * kcd->objects_len, "knife cagecos"); - for (uint b = 0; b < kcd->objects_len; b++) { - ob = kcd->objects[b]; + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + ob = kcd->objects[ob_index]; em = BKE_editmesh_from_object(ob); - knifetool_init_obinfo(kcd, ob, b, use_tri_indices); + knifetool_init_obinfo(kcd, ob, ob_index, use_tri_indices); /* Can't usefully select resulting edges in face mode. */ kcd->select_result = (em->selectmode != SCE_SELECT_FACE); @@ -4225,7 +4233,9 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd) } /* Free object bases. */ - MEM_freeN(kcd->objects); + if (kcd->objects_free) { + MEM_freeN(kcd->objects); + } /* Destroy kcd itself. */ MEM_freeN(kcd); @@ -4318,9 +4328,15 @@ static void knifetool_finish_single_post(KnifeTool_OpData *UNUSED(kcd), Object * /* Called on tool confirmation. */ static void knifetool_finish_ex(KnifeTool_OpData *kcd) { - for (uint b = 0; b < kcd->objects_len; b++) { - Object *ob = kcd->objects[b]; + /* Separate pre/post passes are needed because `em->looptris` recalculation from the 'post' pass + * causes causes triangle indices in #KnifeTool_OpData.bvh to get out of sync. + * So perform all the cuts before doing any mesh recalculation, see: T101721. */ + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + Object *ob = kcd->objects[ob_index]; knifetool_finish_single_pre(kcd, ob); + } + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + Object *ob = kcd->objects[ob_index]; knifetool_finish_single_post(kcd, ob); } } @@ -4789,6 +4805,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) knifetool_init(&vc, kcd, + NULL, + 0, only_select, cut_through, xray, @@ -4802,8 +4820,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) BMEditMesh *em; bool faces_selected = false; - for (uint b = 0; b < kcd->objects_len; b++) { - obedit = kcd->objects[b]; + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + obedit = kcd->objects[ob_index]; em = BKE_editmesh_from_object(obedit); if (em->bm->totfacesel != 0) { faces_selected = true; @@ -4942,7 +4960,12 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2]) return false; } -void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through) +void EDBM_mesh_knife(ViewContext *vc, + Object **objects, + const int objects_len, + LinkNode *polys, + bool use_tag, + bool cut_through) { KnifeTool_OpData *kcd; @@ -4959,6 +4982,8 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th knifetool_init(vc, kcd, + objects, + objects_len, only_select, cut_through, xray, @@ -5000,18 +5025,21 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th /* Finish. */ { - Object *ob; - BMEditMesh *em; - for (uint b = 0; b < kcd->objects_len; b++) { - - ob = kcd->objects[b]; - em = BKE_editmesh_from_object(ob); + /* See #knifetool_finish_ex for why multiple passes are needed. */ + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + Object *ob = kcd->objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); if (use_tag) { BM_mesh_elem_hflag_enable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false); } knifetool_finish_single_pre(kcd, ob); + } + + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { + Object *ob = kcd->objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(ob); /* Tag faces inside! */ if (use_tag) { @@ -5104,9 +5132,12 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th #undef F_ISECT_SET_UNKNOWN #undef F_ISECT_SET_OUTSIDE } + } + for (uint ob_index = 0; ob_index < kcd->objects_len; ob_index++) { /* Defer freeing data until the BVH tree is finished with, see: #point_is_visible and * the doc-string for #knifetool_finish_single_post. */ + Object *ob = kcd->objects[ob_index]; knifetool_finish_single_post(kcd, ob); } diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index e27d19ab000..6004a2943a2 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -132,22 +132,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op) ViewContext vc; em_setup_viewcontext(C, &vc); - /* TODO: Ideally meshes would occlude each other, currently they don't - * since each knife-project runs as a separate operation. */ uint objects_len; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( vc.scene, vc.view_layer, vc.v3d, &objects_len); + + EDBM_mesh_knife(&vc, objects, objects_len, polys, true, cut_through); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; ED_view3d_viewcontext_init_object(&vc, obedit); BMEditMesh *em = BKE_editmesh_from_object(obedit); - EDBM_mesh_knife(&vc, polys, true, cut_through); - /* select only tagged faces */ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - EDBM_selectmode_disable_multi(C, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); + EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc index 0d1e3c08d84..76d0bab8a52 100644 --- a/source/blender/editors/mesh/editmesh_select.cc +++ b/source/blender/editors/mesh/editmesh_select.cc @@ -22,7 +22,9 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_layer.h" +#include "BKE_mesh.h" #include "BKE_report.h" #include "WM_api.h" @@ -1065,8 +1067,8 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, { Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, static_cast<ID *>(obedit->data)); - if (me_eval->runtime.edit_data) { - coords = me_eval->runtime.edit_data->vertexCos; + if (me_eval->runtime->edit_data) { + coords = me_eval->runtime->edit_data->vertexCos; } } diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc index f5056021f7d..5c837e61a79 100644 --- a/source/blender/editors/mesh/editmesh_undo.cc +++ b/source/blender/editors/mesh/editmesh_undo.cc @@ -101,7 +101,7 @@ struct UndoMesh { int shapenr; #ifdef USE_ARRAY_STORE - /* N`ull arrays are considered empty */ + /* Null arrays are considered empty. */ struct { /* most data is stored as 'custom' data */ BArrayCustomData *vdata, *edata, *ldata, *pdata; BArrayState **keyblocks; @@ -231,7 +231,7 @@ static void um_arraystore_cd_compact(CustomData *cdata, } bcd->states[i] = BLI_array_store_state_add( - bs, layer->data, (size_t)data_len * stride, state_reference); + bs, layer->data, size_t(data_len) * stride, state_reference); } else { bcd->states[i] = nullptr; @@ -334,7 +334,7 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool um_ref->store.keyblocks[i] : nullptr; um->store.keyblocks[i] = BLI_array_store_state_add( - bs, keyblock->data, (size_t)keyblock->totelem * stride, state_reference); + bs, keyblock->data, size_t(keyblock->totelem) * stride, state_reference); } if (keyblock->data) { @@ -352,7 +352,7 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool BArrayStore *bs = BLI_array_store_at_size_ensure( &um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); um->store.mselect = BLI_array_store_state_add( - bs, me->mselect, (size_t)me->totselect * stride, state_reference); + bs, me->mselect, size_t(me->totselect) * stride, state_reference); } /* keep me->totselect for validation */ @@ -597,6 +597,11 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key, Undo * on it. Necessary to use the attribute API. */ strcpy(um->me.id.name, "MEundomesh_from_editmesh"); + /* Runtime data is necessary for some asserts in other code, and the overhead of creating it for + * undo meshes should be low. */ + BLI_assert(um->me.runtime == nullptr); + um->me.runtime = new blender::bke::MeshRuntime(); + CustomData_MeshMasks cd_mask_extra{}; cd_mask_extra.vmask = CD_MASK_SHAPE_KEYINDEX; BMeshToMeshParams params{}; diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index e6505715324..0e20bb18595 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -18,6 +18,7 @@ struct BMElem; struct BMOperator; struct EnumPropertyItem; struct LinkNode; +struct Object; struct bContext; struct wmKeyConfig; struct wmKeyMap; @@ -177,6 +178,8 @@ void MESH_OT_knife_project(struct wmOperatorType *ot); * \param use_tag: When set, tag all faces inside the polylines. */ void EDBM_mesh_knife(struct ViewContext *vc, + struct Object **objects, + int objects_len, struct LinkNode *polys, bool use_tag, bool cut_through); diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index 2210cc67bff..4d75ab7f041 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -1335,7 +1335,7 @@ struct VertPickData { static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no[3])) + const float /*no*/[3]) { VertPickData *data = static_cast<VertPickData *>(userData); if (data->hide_vert && data->hide_vert[index]) { diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index 872d2367332..c7995809438 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -21,6 +21,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_force_types.h" +#include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" @@ -788,7 +789,9 @@ static bool modifier_apply_obdata( if (ELEM(mti->type, eModifierTypeType_Constructive, eModifierTypeType_Nonconstructive)) { BKE_report( - reports, RPT_ERROR, "Transform curve to mesh in order to apply constructive modifiers"); + reports, + RPT_ERROR, + "Cannot apply constructive modifiers on curve. Convert curve to mesh in order to apply"); return false; } @@ -855,8 +858,38 @@ static bool modifier_apply_obdata( Main *bmain = DEG_get_bmain(depsgraph); BKE_object_material_from_eval_data(bmain, ob, &curves_eval.id); } + else if (ob->type == OB_POINTCLOUD) { + PointCloud &points = *static_cast<PointCloud *>(ob->data); + if (mti->modifyGeometrySet == nullptr) { + BLI_assert_unreachable(); + return false; + } + + /* Create a temporary geometry set and component. */ + GeometrySet geometry_set; + geometry_set.get_component_for_write<PointCloudComponent>().replace( + &points, GeometryOwnershipType::ReadOnly); + + ModifierEvalContext mectx = {depsgraph, ob, (ModifierApplyFlag)0}; + mti->modifyGeometrySet(md_eval, &mectx, &geometry_set); + if (!geometry_set.has_pointcloud()) { + BKE_report( + reports, RPT_ERROR, "Evaluated geometry from modifier does not contain a point cloud"); + return false; + } + PointCloud *pointcloud_eval = + geometry_set.get_component_for_write<PointCloudComponent>().release(); + + /* Anonymous attributes shouldn't be available on the applied geometry. */ + pointcloud_eval->attributes_for_write().remove_anonymous(); + + /* Copy the relevant information to the original. */ + Main *bmain = DEG_get_bmain(depsgraph); + BKE_object_material_from_eval_data(bmain, ob, &pointcloud_eval->id); + BKE_pointcloud_nomain_to_pointcloud(pointcloud_eval, &points, true); + } else { - /* TODO: implement for point clouds and volumes. */ + /* TODO: implement for volumes. */ BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); return false; } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 2f18922f4ee..5da19d76259 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2318,26 +2318,39 @@ static int make_override_library_exec(bContext *C, wmOperator *op) id_root = &collection->id; user_overrides_from_selected_objects = true; } - /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ + /* Else, poll func ensures us that ID_IS_LINKED(obact) is true, or that it is already an existing + * liboverride. */ else { + BLI_assert(ID_IS_LINKED(obact) || ID_IS_OVERRIDE_LIBRARY_REAL(obact)); id_root = &obact->id; user_overrides_from_selected_objects = true; } - const bool do_fully_editable = !user_overrides_from_selected_objects; - - GSet *user_overrides_objects_uids = do_fully_editable ? NULL : - BLI_gset_new(BLI_ghashutil_inthash_p, - BLI_ghashutil_intcmp, - __func__); - /* Make already existing selected liboverrides editable. */ + bool is_active_override = false; FOREACH_SELECTED_OBJECT_BEGIN (view_layer, CTX_wm_view3d(C), ob_iter) { if (ID_IS_OVERRIDE_LIBRARY_REAL(ob_iter) && !ID_IS_LINKED(ob_iter)) { ob_iter->id.override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED; + is_active_override = is_active_override || (&ob_iter->id == id_root); + DEG_id_tag_update(&ob_iter->id, ID_RECALC_COPY_ON_WRITE); } } FOREACH_SELECTED_OBJECT_END; + /* If the active object is a liboverride, there is no point going further, since in the weird + * case where some other selected objects would be linked ones, there is no way to properly + * create overrides for them currently. + * + * Could be added later if really needed, but would rather avoid that extra complexity here. */ + if (is_active_override) { + return OPERATOR_FINISHED; + } + + const bool do_fully_editable = !user_overrides_from_selected_objects; + + GSet *user_overrides_objects_uids = do_fully_editable ? NULL : + BLI_gset_new(BLI_ghashutil_inthash_p, + BLI_ghashutil_intcmp, + __func__); if (do_fully_editable) { /* Pass. */ diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc index 02a247dd15e..d874226f04e 100644 --- a/source/blender/editors/object/object_vgroup.cc +++ b/source/blender/editors/object/object_vgroup.cc @@ -2376,22 +2376,6 @@ void ED_vgroup_mirror(Object *ob, /* TODO: vgroup locking. * TODO: face masking. */ -#define VGROUP_MIRR_OP \ - dvert_mirror_op(dvert, \ - dvert_mirr, \ - sel, \ - sel_mirr, \ - flip_map, \ - flip_map_len, \ - mirror_weights, \ - flip_vgroups, \ - all_vgroups, \ - def_nr) - - BMVert *eve, *eve_mirr; - MDeformVert *dvert_mirr; - char sel, sel_mirr; - int *flip_map = nullptr, flip_map_len; const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; int totmirr = 0, totfail = 0; @@ -2404,6 +2388,8 @@ void ED_vgroup_mirror(Object *ob, return; } + int *flip_map = nullptr; + int flip_map_len; if (flip_vgroups) { flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, false, &flip_map_len) : BKE_object_defgroup_flip_map_single(ob, false, def_nr, &flip_map_len); @@ -2438,21 +2424,27 @@ void ED_vgroup_mirror(Object *ob, BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); /* Go through the list of edit-vertices and assign them. */ + BMVert *eve, *eve_mirr; BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_TAG)) { if ((eve_mirr = EDBM_verts_mirror_get(em, eve))) { if (eve_mirr != eve) { if (!BM_elem_flag_test(eve_mirr, BM_ELEM_TAG)) { - sel = BM_elem_flag_test(eve, BM_ELEM_SELECT); - sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); + const bool sel = BM_elem_flag_test(eve, BM_ELEM_SELECT); + const bool sel_mirr = BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); if ((sel || sel_mirr) && (eve != eve_mirr)) { - MDeformVert *dvert = static_cast<MDeformVert *>( - BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); - dvert_mirr = static_cast<MDeformVert *>( - BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)); - - VGROUP_MIRR_OP; + dvert_mirror_op( + static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)), + static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve_mirr, cd_dvert_offset)), + sel, + sel_mirr, + flip_map, + flip_map_len, + mirror_weights, + flip_vgroups, + all_vgroups, + def_nr); totmirr++; } @@ -2471,39 +2463,38 @@ void ED_vgroup_mirror(Object *ob, } else { /* object mode / weight paint */ - int vidx, vidx_mirr; const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; if (me->deform_verts().is_empty()) { goto cleanup; } - if (!use_vert_sel) { - sel = sel_mirr = true; - } - BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__); MutableSpan<MDeformVert> dverts = me->deform_verts_for_write(); const bke::AttributeAccessor attributes = me->attributes(); const VArray<bool> select_vert = attributes.lookup_or_default<bool>( ".select_vert", ATTR_DOMAIN_POINT, false); - for (vidx = 0; vidx < me->totvert; vidx++) { + for (int vidx = 0; vidx < me->totvert; vidx++) { if (!BLI_BITMAP_TEST(vert_tag, vidx)) { + int vidx_mirr; if ((vidx_mirr = mesh_get_x_mirror_vert(ob, nullptr, vidx, use_topology)) != -1) { if (vidx != vidx_mirr) { if (!BLI_BITMAP_TEST(vert_tag, vidx_mirr)) { - - if (use_vert_sel) { - sel = select_vert[vidx]; - sel_mirr = select_vert[vidx_mirr]; - } + const bool sel = use_vert_sel ? select_vert[vidx] : true; + const bool sel_mirr = use_vert_sel ? select_vert[vidx_mirr] : true; if (sel || sel_mirr) { - MDeformVert *dvert = &dverts[vidx]; - dvert_mirr = &dvert[vidx_mirr]; - - VGROUP_MIRR_OP; + dvert_mirror_op(&dverts[vidx], + &dverts[vidx_mirr], + sel, + sel_mirr, + flip_map, + flip_map_len, + mirror_weights, + flip_vgroups, + all_vgroups, + def_nr); totmirr++; } @@ -2523,9 +2514,6 @@ void ED_vgroup_mirror(Object *ob, } else if (ob->type == OB_LATTICE) { Lattice *lt = vgroup_edit_lattice(ob); - int i1, i2; - int u, v, w; - int pntsu_half; /* half but found up odd value */ if (lt->pntsu == 1 || lt->dvert == nullptr) { @@ -2535,29 +2523,33 @@ void ED_vgroup_mirror(Object *ob, /* unlike editmesh we know that by only looping over the first half of * the 'u' indices it will cover all points except the middle which is * ok in this case */ - pntsu_half = lt->pntsu / 2; + int pntsu_half = lt->pntsu / 2; - for (w = 0; w < lt->pntsw; w++) { - for (v = 0; v < lt->pntsv; v++) { - for (u = 0; u < pntsu_half; u++) { + for (int w = 0; w < lt->pntsw; w++) { + for (int v = 0; v < lt->pntsv; v++) { + for (int u = 0; u < pntsu_half; u++) { int u_inv = (lt->pntsu - 1) - u; if (u != u_inv) { - BPoint *bp, *bp_mirr; - - i1 = BKE_lattice_index_from_uvw(lt, u, v, w); - i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w); + const int i1 = BKE_lattice_index_from_uvw(lt, u, v, w); + const int i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w); - bp = <->def[i1]; - bp_mirr = <->def[i2]; + const BPoint *bp = <->def[i1]; + const BPoint *bp_mirr = <->def[i2]; - sel = bp->f1 & SELECT; - sel_mirr = bp_mirr->f1 & SELECT; + const bool sel = bp->f1 & SELECT; + const bool sel_mirr = bp_mirr->f1 & SELECT; if (sel || sel_mirr) { - MDeformVert *dvert = <->dvert[i1]; - dvert_mirr = <->dvert[i2]; - - VGROUP_MIRR_OP; + dvert_mirror_op(<->dvert[i1], + <->dvert[i2], + sel, + sel_mirr, + flip_map, + flip_map_len, + mirror_weights, + flip_vgroups, + all_vgroups, + def_nr); totmirr++; } } @@ -2850,8 +2842,9 @@ static bool vertex_group_vert_select_unlocked_poll(bContext *C) if (def_nr != 0) { const ListBase *defbase = BKE_object_defgroup_list(ob); const bDeformGroup *dg = static_cast<const bDeformGroup *>(BLI_findlink(defbase, def_nr - 1)); - if (dg) { - return !(dg->flag & DG_LOCK_WEIGHT); + if (dg && (dg->flag & DG_LOCK_WEIGHT)) { + CTX_wm_operator_poll_msg_set(C, "The active vertex group is locked"); + return false; } } return true; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 761a6702c6f..e6d0aca7902 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3533,7 +3533,7 @@ static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagg } const bool use_dm_final_indices = (psys->part->use_modifier_stack && - !psmd_eval->mesh_final->runtime.deformed_only); + !BKE_mesh_is_deformed_only(psmd_eval->mesh_final)); /* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */ BKE_mesh_tessface_ensure(me); @@ -4353,7 +4353,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v, 0, 0, 0)) { - if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) { + if (psys->part->use_modifier_stack && !BKE_mesh_is_deformed_only(psmd_eval->mesh_final)) { add_pars[iter].num = add_pars[iter].num_dmcache; add_pars[iter].num_dmcache = DMCACHE_ISCHILD; } @@ -4430,7 +4430,7 @@ static int brush_add(const bContext *C, PEData *data, short number) timestep = psys_get_timestep(&sim); - if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) { + if (psys->part->use_modifier_stack || BKE_mesh_is_deformed_only(psmd_eval->mesh_final)) { mesh = psmd_eval->mesh_final; } else { diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 08db03db0e9..71ed32caede 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -732,7 +732,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, invert_m4_m4(to_imat, to_mat); const bool use_dm_final_indices = (target_psys->part->use_modifier_stack && - !target_psmd->mesh_final->runtime.deformed_only); + !BKE_mesh_is_deformed_only(target_psmd->mesh_final)); if (use_dm_final_indices || !target_psmd->mesh_original) { mesh = target_psmd->mesh_final; diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 25d5ceb8216..83ce447e8cf 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -879,7 +879,7 @@ static int new_world_exec(bContext *C, wmOperator * /*op*/) wo = new_wo; } else { - wo = BKE_world_add(bmain, DATA_("World")); + wo = BKE_world_add(bmain, CTX_DATA_(BLT_I18NCONTEXT_ID_WORLD, "World")); ED_node_shader_default(C, &wo->id); wo->use_nodes = true; } diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index f19017cb723..01877deb716 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -286,6 +286,7 @@ static void SCENE_OT_new(wmOperatorType *ot) /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", scene_new_items, SCE_COPY_NEW, "Type", ""); + RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_SCENE); } /** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc index ced7949c69f..d5c5aa5cebd 100644 --- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc +++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc @@ -74,11 +74,8 @@ class AbstractPaintMode { class ImagePaintMode : public AbstractPaintMode { public: - void *paint_new_stroke(bContext *C, - wmOperator *op, - Object * /*ob*/, - const float UNUSED(mouse[2]), - int mode) override + void *paint_new_stroke( + bContext *C, wmOperator *op, Object * /*ob*/, const float /*mouse*/[2], int mode) override { return paint_2d_new_stroke(C, op, mode); } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 8ffa78cd457..41d5090b38c 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -4074,7 +4074,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p ps->totloop_eval = ps->me_eval->totloop; ps->mlooptri_eval = BKE_mesh_runtime_looptri_ensure(ps->me_eval); - ps->totlooptri_eval = ps->me_eval->runtime.looptris.len; + ps->totlooptri_eval = BKE_mesh_runtime_looptri_len(ps->me_eval); ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces"); diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index cb981a3bfb1..ce4a5151a20 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -286,7 +286,7 @@ static void imapaint_pick_uv( const ePaintCanvasSource mode = scene->toolsettings->imapaint.mode; const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval); - const int tottri = me_eval->runtime.looptris.len; + const int tottri = BKE_mesh_runtime_looptri_len(me_eval); const MVert *mvert = BKE_mesh_verts(me_eval); const MLoop *mloop = BKE_mesh_loops(me_eval); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 87112616f93..37a630b8065 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1981,7 +1981,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, int(*orco_tris)[3]; int orco_tris_num; - BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords); + BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords, NULL); for (int i = 0; i < orco_tris_num; i++) { const float *co_tri[3] = { @@ -3289,7 +3289,7 @@ static void sculpt_topology_update(Sculpt *sd, if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { BKE_pbvh_node_mark_topology_update(nodes[n]); - BKE_pbvh_bmesh_node_save_orig(ss->bm, nodes[n]); + BKE_pbvh_bmesh_node_save_orig(ss->bm, ss->bm_log, nodes[n], false); } } @@ -4310,7 +4310,8 @@ static void sculpt_update_cache_invariants( bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2]) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); - UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + ToolSettings *tool_settings = CTX_data_tool_settings(C); + UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings; Brush *brush = BKE_paint_brush(&sd->paint); ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); @@ -4445,6 +4446,13 @@ static void sculpt_update_cache_invariants( } } + /* Original coordinates require the sculpt undo system, which isn't used + * for image brushes. It's also not necessary, just disable it. */ + if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT && + SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) { + cache->original = false; + } + cache->first_time = true; #define PIXEL_INPUT_THRESHHOLD 5 @@ -5787,15 +5795,14 @@ static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent if (!started && ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { /* Did the stroke never start? If so push a blank sculpt undo * step to prevent a global undo step (which is triggered by the - * OPTYPE_UNDO flag in SCULPT_OT_brush_stroke). + * #OPTYPE_UNDO flag in #SCULPT_OT_brush_stroke). * * Having blank global undo steps interleaved with sculpt steps * corrupts the DynTopo undo stack. * See T101430. * - * Note: simply returning OPERATOR_CANCELLED was not - * sufficient to prevent this. - */ + * NOTE: simply returning #OPERATOR_CANCELLED was not + * sufficient to prevent this. */ Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index 5a0fcd8bc27..505440c9272 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -503,7 +503,7 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking, PBVHVertRef vert, AutomaskingNodeData *automask_data) { - if (!automasking) { + if (!automasking || vert.i == PBVH_REF_NONE) { return 1.0f; } diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c index 041efbb357c..92541d10a59 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -2149,6 +2149,8 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float final_disp[3]; switch (brush->elastic_deform_type) { case BRUSH_ELASTIC_DEFORM_GRAB: diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index 15a91e4eaab..ee1238e0f24 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -198,8 +198,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0); /* This operations needs a strength tweak as the relax deformation is too weak by default. */ - if (relax_face_sets) { - bstrength *= 2.0f; + if (relax_face_sets && data->iteration < 2) { + bstrength *= 1.5f; } const int thread_id = BLI_task_parallel_thread_id(tls); @@ -261,6 +261,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in if (ss->cache->alt_smooth) { SCULPT_boundary_info_ensure(ob); for (int i = 0; i < 4; i++) { + data.iteration = i; BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); } } @@ -827,9 +828,6 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) const int mode = RNA_enum_get(op->ptr, "mode"); const int tot_vert = SCULPT_vertex_count_get(ss); - const int active_face_set = SCULPT_active_face_set_get(ss); - - SCULPT_undo_push_begin(ob, op); PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; @@ -842,62 +840,86 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); - - if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) { - bool hidden_vertex = false; + const int active_face_set = SCULPT_active_face_set_get(ss); - /* This can fail with regular meshes with non-manifold geometry as the visibility state can't - * be synced from face sets to non-manifold vertices. */ - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - for (int i = 0; i < tot_vert; i++) { - PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + SCULPT_undo_push_begin(ob, op); + for (int i = 0; i < totnode; i++) { + SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_HIDDEN); + } - if (!SCULPT_vertex_visible_get(ss, vertex)) { - hidden_vertex = true; - break; + switch (mode) { + case SCULPT_FACE_SET_VISIBILITY_TOGGLE: { + bool hidden_vertex = false; + + /* This can fail with regular meshes with non-manifold geometry as the visibility state can't + * be synced from face sets to non-manifold vertices. */ + if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + for (int i = 0; i < tot_vert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_visible_get(ss, vertex)) { + hidden_vertex = true; + break; + } } } - } - if (ss->hide_poly) { - for (int i = 0; i < ss->totfaces; i++) { - if (ss->hide_poly[i]) { - hidden_vertex = true; - break; + if (ss->hide_poly) { + for (int i = 0; i < ss->totfaces; i++) { + if (ss->hide_poly[i]) { + hidden_vertex = true; + break; + } } } - } - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); + ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - if (hidden_vertex) { - SCULPT_face_visibility_all_set(ss, true); - } - else { - SCULPT_face_visibility_all_set(ss, false); - SCULPT_face_set_visibility_set(ss, active_face_set, true); + if (hidden_vertex) { + SCULPT_face_visibility_all_set(ss, true); + } + else { + if (ss->face_sets) { + SCULPT_face_visibility_all_set(ss, false); + SCULPT_face_set_visibility_set(ss, active_face_set, true); + } + else { + SCULPT_face_visibility_all_set(ss, true); + } + } + break; } - } + case SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE: + ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) { - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - SCULPT_face_visibility_all_set(ss, false); - SCULPT_face_set_visibility_set(ss, active_face_set, true); - } + if (ss->face_sets) { + SCULPT_face_visibility_all_set(ss, false); + SCULPT_face_set_visibility_set(ss, active_face_set, true); + } + else { + SCULPT_face_set_visibility_set(ss, active_face_set, true); + } + break; + case SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE: + ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) { - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - SCULPT_face_set_visibility_set(ss, active_face_set, false); - } + if (ss->face_sets) { + SCULPT_face_set_visibility_set(ss, active_face_set, false); + } + else { + SCULPT_face_visibility_all_set(ss, false); + } - if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) { - ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); - SCULPT_face_visibility_all_invert(ss); + break; + case SCULPT_FACE_SET_VISIBILITY_INVERT: + ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh); + SCULPT_face_visibility_all_invert(ss); + break; } /* For modes that use the cursor active vertex, update the rotation origin for viewport - * navigation. */ + * navigation. + */ if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) { UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; float location[3]; @@ -912,7 +934,6 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) SCULPT_visibility_sync_all_from_faces(ob); SCULPT_undo_push_end(ob); - for (int i = 0; i < totnode; i++) { BKE_pbvh_node_mark_update_visibility(nodes[i]); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 44ff0da9347..59b0f7f5925 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -332,7 +332,7 @@ typedef struct SculptThreadedTaskData { int mask_init_seed; ThreadMutex mutex; - + int iteration; } SculptThreadedTaskData; /*************** Brush testing declarations ****************/ diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 1042356489b..56a35ee1774 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -1116,10 +1116,7 @@ static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op) SCULPT_undo_push_end(ob); SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); - - /* Unlike other operators we do not tag the ID for update here; - * it triggers a PBVH rebuild which is too slow and ruins - * the interactivity of the tool. */ + SCULPT_tag_update_overlays(C); return OPERATOR_FINISHED; } @@ -1294,11 +1291,10 @@ static int sculpt_reveal_all_exec(bContext *C, wmOperator *op) SCULPT_visibility_sync_all_from_faces(ob); - /* Note: SCULPT_visibility_sync_all_from_faces may have deleted - * pbvh->hide_vert if hide_poly did not exist, which is why - * we call BKE_pbvh_update_hide_attributes_from_mesh here instead of - * after CustomData_free_layer_named above. - */ + /* NOTE: #SCULPT_visibility_sync_all_from_faces may have deleted + * `pbvh->hide_vert` if hide_poly did not exist, which is why + * we call #BKE_pbvh_update_hide_attributes_from_mesh here instead of + * after #CustomData_free_layer_named above. */ if (!with_bmesh) { BKE_pbvh_update_hide_attributes_from_mesh(ss->pbvh); } diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index f276c2acd1a..a625c124dd3 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1611,7 +1611,9 @@ void CLIP_OT_mode_set(wmOperatorType *ot) ot->poll = ED_space_clip_poll; /* properties */ - RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", ""); + ot->prop = RNA_def_enum( + ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", ""); + RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_MOVIECLIP); } /** \} */ @@ -1639,14 +1641,14 @@ static int clip_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv float pan_vec[3]; const wmNDOFMotionData *ndof = event->customdata; - const float speed = NDOF_PIXELS_PER_SECOND; + const float pan_speed = NDOF_PIXELS_PER_SECOND; WM_event_ndof_pan_get(ndof, pan_vec, true); - mul_v2_fl(pan_vec, (speed * ndof->dt) / sc->zoom); - pan_vec[2] *= -ndof->dt; + mul_v3_fl(pan_vec, ndof->dt); + mul_v2_fl(pan_vec, pan_speed / sc->zoom); - sclip_zoom_set_factor(C, 1.0f + pan_vec[2], NULL, false); + sclip_zoom_set_factor(C, max_ff(0.0f, 1.0f - pan_vec[2]), NULL, false); sc->xof += pan_vec[0]; sc->yof += pan_vec[1]; diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 42ebed6ec3a..85b1e2b6707 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -589,15 +589,27 @@ void ED_space_image_grid_steps(SpaceImage *sima, float grid_steps_y[SI_GRID_STEPS_LEN], const int grid_dimension) { - const int flag = sima->flag; + const eSpaceImage_GridShapeSource grid_shape_source = sima->grid_shape_source; for (int step = 0; step < SI_GRID_STEPS_LEN; step++) { - if (flag & SI_CUSTOM_GRID) { - grid_steps_x[step] = 1.0f / sima->custom_grid_subdiv[0]; - grid_steps_y[step] = 1.0f / sima->custom_grid_subdiv[1]; - } - else { - grid_steps_x[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN); - grid_steps_y[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN); + switch (grid_shape_source) { + case SI_GRID_SHAPE_DYNAMIC: + grid_steps_x[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN); + grid_steps_y[step] = powf(grid_dimension, step - SI_GRID_STEPS_LEN); + break; + case SI_GRID_SHAPE_FIXED: + grid_steps_x[step] = 1.0f / sima->custom_grid_subdiv[0]; + grid_steps_y[step] = 1.0f / sima->custom_grid_subdiv[1]; + break; + case SI_GRID_SHAPE_PIXEL: { + int pixel_width = IMG_SIZE_FALLBACK; + int pixel_height = IMG_SIZE_FALLBACK; + ED_space_image_get_size(sima, &pixel_width, &pixel_height); + BLI_assert(pixel_width > 0 && pixel_height > 0); + grid_steps_x[step] = 1.0f / pixel_width; + grid_steps_y[step] = 1.0f / pixel_height; + } break; + default: + BLI_assert_unreachable(); } } } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index bb47ad5c6c0..3503c4c8168 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -762,14 +762,14 @@ static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmE float pan_vec[3]; const wmNDOFMotionData *ndof = event->customdata; - const float speed = NDOF_PIXELS_PER_SECOND; + const float pan_speed = NDOF_PIXELS_PER_SECOND; WM_event_ndof_pan_get(ndof, pan_vec, true); - mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom); - pan_vec[2] *= -ndof->dt; + mul_v3_fl(pan_vec, ndof->dt); + mul_v2_fl(pan_vec, pan_speed / sima->zoom); - sima_zoom_set_factor(sima, region, 1.0f + pan_vec[2], NULL, false); + sima_zoom_set_factor(sima, region, max_ff(0.0f, 1.0f - pan_vec[2]), NULL, false); sima->xof += pan_vec[0]; sima->yof += pan_vec[1]; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 71cbcea1c1f..53e1bc0a1e5 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -5,6 +5,7 @@ * \ingroup spimage */ +#include "DNA_defaults.h" #include "DNA_gpencil_types.h" #include "DNA_image_types.h" #include "DNA_mask_types.h" @@ -117,6 +118,8 @@ static SpaceLink *image_create(const ScrArea *UNUSED(area), const Scene *UNUSED( simage->custom_grid_subdiv[0] = 10; simage->custom_grid_subdiv[1] = 10; + simage->mask_info = *DNA_struct_default_get(MaskSpaceInfo); + /* header */ region = MEM_callocN(sizeof(ARegion), "header for image"); diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index cac0dbb0067..e8b005b2b67 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -40,6 +40,7 @@ #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" @@ -94,8 +95,8 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st int totvert, totedge, totface, totloop; - const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg; - const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data; + const SubdivCCG *subdiv_ccg = me_eval->runtime->subdiv_ccg; + const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime->subsurf_runtime_data; if (subdiv_ccg != nullptr) { BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 9df25b1229e..8a3c6745259 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -2641,6 +2641,8 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op) void NLA_OT_fmodifier_add(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add F-Modifier"; ot->idname = "NLA_OT_fmodifier_add"; @@ -2659,11 +2661,12 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot) RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION); RNA_def_enum_funcs(ot->prop, nla_fmodifier_itemf); - RNA_def_boolean(ot->srna, - "only_active", - true, - "Only Active", - "Only add a F-Modifier of the specified type to the active strip"); + prop = RNA_def_boolean(ot->srna, + "only_active", + true, + "Only Active", + "Only add a F-Modifier of the specified type to the active strip"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION); } /** \} */ @@ -2832,8 +2835,10 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_boolean( + ot->prop = RNA_def_boolean( ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active strip"); + RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION); + RNA_def_boolean( ot->srna, "replace", diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc index 819f0abac7c..28e18c20f46 100644 --- a/source/blender/editors/space_node/add_node_search.cc +++ b/source/blender/editors/space_node/add_node_search.cc @@ -182,6 +182,9 @@ static void gather_add_node_operations(const bContext &C, /* Skip the empty group type. */ continue; } + if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) { + continue; + } AddNodeItem item{}; item.ui_name = IFACE_(node_type->ui_name); diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index 17410937d4c..ffa2d377056 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -274,7 +274,9 @@ static void gather_socket_link_operations(const bContext &C, if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { continue; } - + if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) { + continue; + } if (node_type->gather_link_search_ops) { nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops}; node_type->gather_link_search_ops(params); diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index dc155f5e28d..ee9ebd541a0 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -3011,7 +3011,7 @@ static void node_draw_nodetree(const bContext &C, } } -/* Draw the breadcrumb on the bottom of the editor. */ +/* Draw the breadcrumb on the top of the editor. */ static void draw_tree_path(const bContext &C, ARegion ®ion) { using namespace blender; diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 3a80733f06c..48b3d711bdf 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -1361,12 +1361,15 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); + bool linked = RNA_boolean_get(op->ptr, "linked") || ((U.dupflag & USER_DUP_NTREE) == 0); + const bool dupli_node_tree = !linked; bool changed = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); Map<const bNode *, bNode *> node_map; Map<const bNodeSocket *, bNodeSocket *> socket_map; + Map<const ID *, ID *> duplicated_node_groups; bNode *lastnode = (bNode *)ntree->nodes.last; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -1374,6 +1377,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) bNode *new_node = bke::node_copy_with_mapping( ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); node_map.add_new(node, new_node); + + if (node->id && dupli_node_tree) { + ID *new_group = duplicated_node_groups.lookup_or_add_cb(node->id, [&]() { + ID *new_group = BKE_id_copy(bmain, node->id); + /* Remove user added by copying. */ + id_us_min(new_group); + return new_group; + }); + id_us_plus(new_group); + id_us_min(new_node->id); + new_node->id = new_group; + } changed = true; } @@ -1462,6 +1477,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) void NODE_OT_duplicate(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Duplicate Nodes"; ot->description = "Duplicate selected nodes"; @@ -1476,6 +1493,13 @@ void NODE_OT_duplicate(wmOperatorType *ot) RNA_def_boolean( ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes"); + + prop = RNA_def_boolean(ot->srna, + "linked", + true, + "Linked", + "Duplicate node but not node trees, linking to the original data"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* XXX: some code needing updating to operators. */ @@ -2275,6 +2299,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator * /*op*/) newlink->tosock = socket_map.lookup(link->tosock); newlink->fromnode = node_map.lookup(link->fromnode); newlink->fromsock = socket_map.lookup(link->fromsock); + newlink->multi_input_socket_index = link->multi_input_socket_index; BKE_node_clipboard_add_link(newlink); } @@ -2396,11 +2421,19 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) { - nodeAddLink(ntree, - node_map.lookup(link->fromnode), - socket_map.lookup(link->fromsock), - node_map.lookup(link->tonode), - socket_map.lookup(link->tosock)); + bNodeLink *new_link = nodeAddLink(ntree, + node_map.lookup(link->fromnode), + socket_map.lookup(link->fromsock), + node_map.lookup(link->tonode), + socket_map.lookup(link->tosock)); + new_link->multi_input_socket_index = link->multi_input_socket_index; + } + + ntree->ensure_topology_cache(); + + for (bNode *new_node : node_map.values()) { + /* Update multi input socket indices in case all connected nodes weren't copied. */ + update_multi_input_indices_for_removed_links(*new_node); } Main *bmain = CTX_data_main(C); diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 50c03489027..1c3026628a6 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -270,6 +270,8 @@ void NODE_OT_group_edit(wmOperatorType *ot); /* node_relationships.cc */ +void update_multi_input_indices_for_removed_links(bNode &node); + void NODE_OT_link(wmOperatorType *ot); void NODE_OT_link_make(wmOperatorType *ot); void NODE_OT_links_cut(wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index 6c52dae5b86..d45c33a3c59 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -174,7 +174,17 @@ void ED_operatormacros_node() "Duplicate", "Duplicate selected nodes and move them", OPTYPE_UNDO | OPTYPE_REGISTER); - WM_operatortype_macro_define(ot, "NODE_OT_duplicate"); + mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate"); + RNA_boolean_set(mot->ptr, "linked", false); + WM_operatortype_macro_define(ot, "NODE_OT_translate_attach"); + + ot = WM_operatortype_append_macro( + "NODE_OT_duplicate_move_linked", + "Duplicate Linked", + "Duplicate selected nodes, but not their node trees, and move them", + OPTYPE_UNDO | OPTYPE_REGISTER); + mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate"); + RNA_boolean_set(mot->ptr, "linked", true); WM_operatortype_macro_define(ot, "NODE_OT_translate_attach"); /* modified operator call for duplicating with input links */ diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 7cf18e2f828..b12afcb1faa 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -64,6 +64,10 @@ struct NodeInsertOfsData { float offset_x; /* offset to apply to node chain */ }; +namespace blender::ed::space_node { + +bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out); + static void clear_picking_highlight(ListBase *links) { LISTBASE_FOREACH (bNodeLink *, link, links) { @@ -71,10 +75,6 @@ static void clear_picking_highlight(ListBase *links) } } -namespace blender::ed::space_node { - -void update_multi_input_indices_for_removed_links(bNode &node); - /* -------------------------------------------------------------------- */ /** \name Add Node * \{ */ @@ -1750,29 +1750,31 @@ static int node_attach_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *e } LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { - if (node->flag & NODE_SELECT) { - if (node->parent == nullptr) { - /* disallow moving a parent into its child */ - if (nodeAttachNodeCheck(frame, node) == false) { - /* attach all unparented nodes */ - nodeAttachNode(node, frame); - } + if (!(node->flag & NODE_SELECT)) { + continue; + } + + if (node->parent == nullptr) { + /* disallow moving a parent into its child */ + if (nodeAttachNodeCheck(frame, node) == false) { + /* attach all unparented nodes */ + nodeAttachNode(node, frame); } - else { - /* attach nodes which share parent with the frame */ - bNode *parent; - for (parent = frame->parent; parent; parent = parent->parent) { - if (parent == node->parent) { - break; - } + } + else { + /* attach nodes which share parent with the frame */ + bNode *parent; + for (parent = frame->parent; parent; parent = parent->parent) { + if (parent == node->parent) { + break; } + } - if (parent) { - /* disallow moving a parent into its child */ - if (nodeAttachNodeCheck(frame, node) == false) { - nodeDetachNode(node); - nodeAttachNode(node, frame); - } + if (parent) { + /* disallow moving a parent into its child */ + if (nodeAttachNodeCheck(frame, node) == false) { + nodeDetachNode(node); + nodeAttachNode(node, frame); } } } @@ -1881,100 +1883,55 @@ void NODE_OT_detach(wmOperatorType *ot) /** \name Automatic Node Insert on Dragging * \{ */ -/* prevent duplicate testing code below */ -static bool ed_node_link_conditions(ScrArea *area, - bool test, - SpaceNode **r_snode, - bNode **r_select) +static bNode *get_selected_node_for_insertion(bNodeTree &node_tree) { - SpaceNode *snode = area ? (SpaceNode *)area->spacedata.first : nullptr; - - *r_snode = snode; - *r_select = nullptr; - - /* no unlucky accidents */ - if (area == nullptr || area->spacetype != SPACE_NODE) { - return false; - } - - if (!test) { - /* no need to look for a node */ - return true; - } - - bNode *node; - bNode *select = nullptr; - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + bNode *selected_node = nullptr; + int selected_node_count = 0; + for (bNode *node : node_tree.all_nodes()) { if (node->flag & SELECT) { - if (select) { - break; - } - select = node; + selected_node = node; + selected_node_count++; + } + if (selected_node_count > 1) { + return nullptr; } } - /* only one selected */ - if (node || select == nullptr) { - return false; + if (!selected_node) { + return nullptr; } - - /* correct node */ - if (BLI_listbase_is_empty(&select->inputs) || BLI_listbase_is_empty(&select->outputs)) { - return false; + if (selected_node->input_sockets().is_empty() || selected_node->output_sockets().is_empty()) { + return nullptr; } - - ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - - /* test node for links */ - LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - if (node_link_is_hidden_or_dimmed(region->v2d, *link)) { - continue; - } - - if (link->tonode == select || link->fromnode == select) { - return false; - } + if (std::any_of(selected_node->input_sockets().begin(), + selected_node->input_sockets().end(), + [&](const bNodeSocket *socket) { return socket->is_directly_linked(); })) { + return nullptr; } - - *r_select = select; - return true; + if (std::any_of(selected_node->output_sockets().begin(), + selected_node->output_sockets().end(), + [&](const bNodeSocket *socket) { return socket->is_directly_linked(); })) { + return nullptr; + }; + return selected_node; } -/** \} */ - -} // namespace blender::ed::space_node - -/* -------------------------------------------------------------------- */ -/** \name Node Line Intersection Test - * \{ */ - -void ED_node_link_intersect_test(ScrArea *area, int test) +void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion) { - using namespace blender; - using namespace blender::ed::space_node; - - bNode *select; - SpaceNode *snode; - if (!ed_node_link_conditions(area, test, &snode, &select)) { - return; - } + bNodeTree &node_tree = *snode.edittree; + node_tree.ensure_topology_cache(); - /* clear flags */ - LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - link->flag &= ~NODE_LINKFLAG_HILITE; - } + node_insert_on_link_flags_clear(node_tree); - if (test == 0) { + bNode *node_to_insert = get_selected_node_for_insertion(node_tree); + if (!node_to_insert) { return; } - ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - /* find link to select/highlight */ bNodeLink *selink = nullptr; float dist_best = FLT_MAX; - LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - - if (node_link_is_hidden_or_dimmed(region->v2d, *link)) { + LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { + if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { continue; } @@ -1986,10 +1943,10 @@ void ED_node_link_intersect_test(ScrArea *area, int test) * upper left node edge of a intersected line segment */ for (int i = 0; i < NODE_LINK_RESOL; i++) { /* Check if the node rectangle intersects the line from this point to next one. */ - if (BLI_rctf_isect_segment(&select->totr, coords[i], coords[i + 1])) { + if (BLI_rctf_isect_segment(&node_to_insert->totr, coords[i], coords[i + 1])) { /* store the shortest distance to the upper left edge * of all intersections found so far */ - const float node_xy[] = {select->totr.xmin, select->totr.ymax}; + const float node_xy[] = {node_to_insert->totr.xmin, node_to_insert->totr.ymax}; /* to be precise coords should be clipped by select->totr, * but not done since there's no real noticeable difference */ @@ -2009,9 +1966,89 @@ void ED_node_link_intersect_test(ScrArea *area, int test) } } -/** \} */ +void node_insert_on_link_flags_clear(bNodeTree &node_tree) +{ + LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { + link->flag &= ~NODE_LINKFLAG_HILITE; + } +} -namespace blender::ed::space_node { +void node_insert_on_link_flags(Main &bmain, SpaceNode &snode) +{ + bNodeTree &node_tree = *snode.edittree; + node_tree.ensure_topology_cache(); + bNode *node_to_insert = get_selected_node_for_insertion(node_tree); + if (!node_to_insert) { + return; + } + + /* Find link to insert on. */ + bNodeTree &ntree = *snode.edittree; + bNodeLink *old_link = nullptr; + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + if (link->flag & NODE_LINKFLAG_HILITE) { + old_link = link; + break; + } + } + if (old_link == nullptr) { + return; + } + + old_link->flag &= ~NODE_LINKFLAG_HILITE; + + bNodeSocket *best_input = get_main_socket(ntree, *node_to_insert, SOCK_IN); + bNodeSocket *best_output = get_main_socket(ntree, *node_to_insert, SOCK_OUT); + + if (node_to_insert->type != NODE_REROUTE) { + /* Ignore main sockets when the types don't match. */ + if (best_input != nullptr && ntree.typeinfo->validate_link != nullptr && + !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(old_link->fromsock->type), + static_cast<eNodeSocketDatatype>(best_input->type))) { + best_input = nullptr; + } + if (best_output != nullptr && ntree.typeinfo->validate_link != nullptr && + !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(best_output->type), + static_cast<eNodeSocketDatatype>(old_link->tosock->type))) { + best_output = nullptr; + } + } + + bNode *from_node = old_link->fromnode; + bNodeSocket *from_socket = old_link->fromsock; + bNode *to_node = old_link->tonode; + + if (best_output != nullptr) { + /* Relink the "start" of the existing link to the newly inserted node. */ + old_link->fromnode = node_to_insert; + old_link->fromsock = best_output; + BKE_ntree_update_tag_link_changed(&ntree); + } + else { + nodeRemLink(&ntree, old_link); + } + + if (best_input != nullptr) { + /* Add a new link that connects the node on the left to the newly inserted node. */ + nodeAddLink(&ntree, from_node, from_socket, node_to_insert, best_input); + } + + /* Set up insert offset data, it needs stuff from here. */ + if ((snode.flag & SNODE_SKIP_INSOFFSET) == 0) { + BLI_assert(snode.runtime->iofsd == nullptr); + NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__); + + iofsd->insert = node_to_insert; + iofsd->prev = from_node; + iofsd->next = to_node; + + snode.runtime->iofsd = iofsd; + } + + ED_node_tree_propagate_change(nullptr, &bmain, &ntree); +} + +/** \} */ /* -------------------------------------------------------------------- */ /** \name Node Insert Offset Operator @@ -2048,7 +2085,7 @@ static int get_main_socket_priority(const bNodeSocket *socket) } /** Get the "main" socket based on the node declaration or an heuristic. */ -static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) +bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) { ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs; @@ -2426,85 +2463,3 @@ void NODE_OT_insert_offset(wmOperatorType *ot) /** \} */ } // namespace blender::ed::space_node - -/* -------------------------------------------------------------------- */ -/** \name Note Link Insert - * \{ */ - -void ED_node_link_insert(Main *bmain, ScrArea *area) -{ - using namespace blender::ed::space_node; - - bNode *node_to_insert; - SpaceNode *snode; - if (!ed_node_link_conditions(area, true, &snode, &node_to_insert)) { - return; - } - - /* Find link to insert on. */ - bNodeTree &ntree = *snode->edittree; - bNodeLink *old_link = nullptr; - LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { - if (link->flag & NODE_LINKFLAG_HILITE) { - old_link = link; - break; - } - } - if (old_link == nullptr) { - return; - } - - old_link->flag &= ~NODE_LINKFLAG_HILITE; - - bNodeSocket *best_input = get_main_socket(ntree, *node_to_insert, SOCK_IN); - bNodeSocket *best_output = get_main_socket(ntree, *node_to_insert, SOCK_OUT); - - if (node_to_insert->type != NODE_REROUTE) { - /* Ignore main sockets when the types don't match. */ - if (best_input != nullptr && ntree.typeinfo->validate_link != nullptr && - !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(old_link->fromsock->type), - static_cast<eNodeSocketDatatype>(best_input->type))) { - best_input = nullptr; - } - if (best_output != nullptr && ntree.typeinfo->validate_link != nullptr && - !ntree.typeinfo->validate_link(static_cast<eNodeSocketDatatype>(best_output->type), - static_cast<eNodeSocketDatatype>(old_link->tosock->type))) { - best_output = nullptr; - } - } - - bNode *from_node = old_link->fromnode; - bNodeSocket *from_socket = old_link->fromsock; - bNode *to_node = old_link->tonode; - - if (best_output != nullptr) { - /* Relink the "start" of the existing link to the newly inserted node. */ - old_link->fromnode = node_to_insert; - old_link->fromsock = best_output; - BKE_ntree_update_tag_link_changed(&ntree); - } - else { - nodeRemLink(&ntree, old_link); - } - - if (best_input != nullptr) { - /* Add a new link that connects the node on the left to the newly inserted node. */ - nodeAddLink(&ntree, from_node, from_socket, node_to_insert, best_input); - } - - /* Set up insert offset data, it needs stuff from here. */ - if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { - BLI_assert(snode->runtime->iofsd == nullptr); - NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__); - - iofsd->insert = node_to_insert; - iofsd->prev = from_node; - iofsd->next = to_node; - - snode->runtime->iofsd = iofsd; - } - - ED_node_tree_propagate_change(nullptr, bmain, snode->edittree); -} - -/** \} */ diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc index 259d879d76f..3b07c6da5fa 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.cc +++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc @@ -888,7 +888,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) static char *datastack_drop_tooltip(bContext * /*C*/, wmDrag *drag, - const int UNUSED(xy[2]), + const int /*xy*/[2], struct wmDropBox * /*drop*/) { StackDropData *drop_data = static_cast<StackDropData *>(drag->poin); diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index 8a1119d5e66..34d1e1bb546 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -2941,16 +2941,66 @@ static bool tselem_draw_icon(uiBlock *block, return true; } +static bool outliner_is_main_row(const ARegion *region, const int ys) +{ + int ystart; + + ystart = int(region->v2d.tot.ymax); + ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; + + return ((ys - ystart) / UI_UNIT_Y) % 2; +} + +/** + * Get the expected row background color to use for the data-block counter + * + * This reproduces somes of the logic of outliner_draw_highlights. + * At the moment it doesn't implement the search match color since + * we don't draw the data-block counter in those cases. + */ +static void outliner_get_row_color(const ARegion *region, + const TreeElement *te, + int ys, + float r_color[4]) +{ + const TreeStoreElem *tselem = TREESTORE(te); + + if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) { + UI_GetThemeColor3fv(TH_ACTIVE, r_color); + } + else if (tselem->flag & TSE_SELECTED) { + UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, r_color); + } + else if (outliner_is_main_row(region, ys)) { + UI_GetThemeColor3fv(TH_BACK, r_color); + } + else { + float color_alternating[4]; + UI_GetThemeColor4fv(TH_ROW_ALTERNATE, color_alternating); + UI_GetThemeColorBlend3f(TH_BACK, TH_ROW_ALTERNATE, color_alternating[3], r_color); + } + + if (tselem->flag & TSE_HIGHLIGHTED) { + const float color_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; + interp_v3_v3v3(r_color, r_color, color_highlight, color_highlight[3]); + } + r_color[3] = 1.0f; +} + /** * For icon-only children of a collapsed tree, * Draw small number over the icon to show how many items of this type are displayed. */ -static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, +static void outliner_draw_iconrow_number(const ARegion *region, + const uiFontStyle *fstyle, int offsx, int ys, + const TreeElement *te_visible, const int num_elements) { - const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float color[4]; + outliner_get_row_color(region, te_visible, ys, color); + float ufac = 0.25f * UI_UNIT_X; float offset_x = float(offsx) + UI_UNIT_X * 0.35f; rctf rect{}; @@ -2961,12 +3011,13 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, float(ys) - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa(&rect, true, float(UI_UNIT_Y) / 2.0f - ufac, color); + UI_draw_roundbox_4fv_ex( + &rect, color, NULL, 1.0f, color, U.pixelsize, float(UI_UNIT_Y) / 2.0f - ufac); /* Now the numbers. */ uchar text_col[4]; - UI_GetThemeColor3ubv(TH_TEXT_HI, text_col); + UI_GetThemeColor3ubv(TH_TEXT, text_col); text_col[3] = 255; uiFontStyle fstyle_small = *fstyle; @@ -3018,7 +3069,9 @@ static void outliner_draw_active_indicator(const float minx, GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */ } -static void outliner_draw_iconrow_doit(uiBlock *block, +static void outliner_draw_iconrow_doit(const ARegion *region, + uiBlock *block, + TreeElement *te_visible, TreeElement *te, const uiFontStyle *fstyle, int xmax, @@ -3055,7 +3108,7 @@ static void outliner_draw_iconrow_doit(uiBlock *block, te->xend = short(*offsx) + UI_UNIT_X; if (num_elements > 1) { - outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements); + outliner_draw_iconrow_number(region, fstyle, *offsx, ys, te_visible, num_elements); te->flag |= TE_ICONROW_MERGED; } else { @@ -3092,6 +3145,7 @@ static void outliner_draw_iconrow(bContext *C, const uiFontStyle *fstyle, const TreeViewContext *tvc, SpaceOutliner *space_outliner, + TreeElement *te_visible, ListBase *lb, int level, int xmax, @@ -3100,6 +3154,7 @@ static void outliner_draw_iconrow(bContext *C, float alpha_fac, MergedIconRow *merged) { + const ARegion *region = CTX_wm_region(C); eOLDrawState active = OL_DRAWSEL_NONE; LISTBASE_FOREACH (TreeElement *, te, lb) { @@ -3139,7 +3194,8 @@ static void outliner_draw_iconrow(bContext *C, TSE_POSE_CHANNEL, TSE_POSEGRP, TSE_DEFGROUP)) { - outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); + outliner_draw_iconrow_doit( + region, block, te_visible, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); } else { const int index = tree_element_id_type_to_index(te); @@ -3158,6 +3214,7 @@ static void outliner_draw_iconrow(bContext *C, fstyle, tvc, space_outliner, + te, &te->subtree, level + 1, xmax, @@ -3179,7 +3236,9 @@ static void outliner_draw_iconrow(bContext *C, for (int j = 0; j < num_subtypes; j++) { const int index = index_base + j; if (merged->num_elements[index] != 0) { - outliner_draw_iconrow_doit(block, + outliner_draw_iconrow_doit(region, + block, + te_visible, merged->tree_element[index], fstyle, xmax, @@ -3419,6 +3478,7 @@ static void outliner_draw_tree_element(bContext *C, fstyle, tvc, space_outliner, + te, &te->subtree, 0, xmax, diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 8af12590b0f..b2f9cfc6395 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -487,37 +487,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread return geometry_set; } -class GeometryComponentCacheKey : public SpreadsheetCache::Key { - public: - /* Use the pointer to the geometry component as a key to detect when the geometry changed. */ - const GeometryComponent *component; - - GeometryComponentCacheKey(const GeometryComponent &component) : component(&component) - { - } - - uint64_t hash() const override - { - return get_default_hash(this->component); - } - - bool is_equal_to(const Key &other) const override - { - if (const GeometryComponentCacheKey *other_geo = - dynamic_cast<const GeometryComponentCacheKey *>(&other)) { - return this->component == other_geo->component; - } - return false; - } -}; - -class GeometryComponentCacheValue : public SpreadsheetCache::Value { - public: - /* Stores the result of fields evaluated on a geometry component. Without this, fields would have - * to be reevaluated on every redraw. */ - Map<std::pair<eAttrDomain, GField>, GArray<>> arrays; -}; - std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 36ced74a8b7..6370d56ae8c 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -17,6 +17,7 @@ #include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "DEG_depsgraph.h" @@ -94,8 +95,8 @@ void ED_draw_object_facemap(Depsgraph *depsgraph, const MPoly *mp; int i; - if (me->runtime.looptris.array) { - const MLoopTri *mlt = me->runtime.looptris.array; + if (BKE_mesh_runtime_looptri_ensure(me)) { + const MLoopTri *mlt = BKE_mesh_runtime_looptri_ensure(me); for (mp = polys, i = 0; i < mpoly_len; i++, mp++) { if (facemap_data[i] == facemap) { for (int j = 2; j < mp->totloop; j++) { diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc index 4ac6f926818..635fbd75d74 100644 --- a/source/blender/editors/space_view3d/space_view3d.cc +++ b/source/blender/editors/space_view3d/space_view3d.cc @@ -631,7 +631,7 @@ static bool view3d_object_data_drop_poll(bContext *C, wmDrag *drag, const wmEven static char *view3d_object_data_drop_tooltip(bContext * /*C*/, wmDrag * /*drag*/, - const int UNUSED(xy[2]), + const int /*xy*/[2], wmDropBox * /*drop*/) { return BLI_strdup(TIP_("Create object instance from object-data")); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc index c61eac3c777..793ada4f577 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc @@ -19,8 +19,10 @@ #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_global.h" #include "BKE_layer.h" +#include "BKE_mesh.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -234,8 +236,8 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int Object *ob = gz_ele->bases[gz_ele->base_index]->object; Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, static_cast<ID *>(ob->data)); - if (me_eval->runtime.edit_data) { - coords = me_eval->runtime.edit_data->vertexCos; + if (me_eval->runtime->edit_data) { + coords = me_eval->runtime->edit_data->vertexCos; } } EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords); diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc index 139ac9de6e4..932563863fe 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.cc +++ b/source/blender/editors/space_view3d/view3d_iterators.cc @@ -262,7 +262,7 @@ struct foreachScreenFace_userData { static void meshobject_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no[3])) + const float /*no*/[3]) { foreachScreenObjectVert_userData *data = static_cast<foreachScreenObjectVert_userData *>( userData); @@ -316,7 +316,7 @@ void meshobject_foreachScreenVert( static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no[3])) + const float /*no*/[3]) { foreachScreenVert_userData *data = static_cast<foreachScreenVert_userData *>(userData); BMVert *eve = BM_vert_at_index(data->vc.em->bm, index); @@ -538,7 +538,7 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc, static void mesh_foreachScreenFace__mapFunc(void *userData, int index, const float cent[3], - const float UNUSED(no[3])) + const float /*no*/[3]) { foreachScreenFace_userData *data = static_cast<foreachScreenFace_userData *>(userData); BMFace *efa = BM_face_at_index(data->vc.em->bm, index); @@ -576,7 +576,7 @@ void mesh_foreachScreenFace( BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); - if (me->runtime.subsurf_face_dot_tags != nullptr) { + if (me->runtime->subsurf_face_dot_tags != nullptr) { BKE_mesh_foreach_mapped_subdiv_face_center( me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); } diff --git a/source/blender/editors/space_view3d/view3d_navigate_ndof.c b/source/blender/editors/space_view3d/view3d_navigate_ndof.c index 29e63a72daf..9fb33013c4e 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_ndof.c +++ b/source/blender/editors/space_view3d/view3d_navigate_ndof.c @@ -370,14 +370,17 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event) return OPERATOR_PASS_THROUGH; } + const float pan_speed = NDOF_PIXELS_PER_SECOND; const bool has_translate = !is_zero_v2(ndof->tvec); const bool has_zoom = ndof->tvec[2] != 0.0f; float pan_vec[3]; WM_event_ndof_pan_get(ndof, pan_vec, true); - mul_v2_fl(pan_vec, ndof->dt); - pan_vec[2] *= -ndof->dt; + mul_v3_fl(pan_vec, ndof->dt); + /* NOTE: unlike image and clip views, the 2D pan doesn't have to be scaled by the zoom level. + * #ED_view3d_camera_view_pan already takes the zoom level into account. */ + mul_v2_fl(pan_vec, pan_speed); /* NOTE(@campbellbarton): In principle rotating could pass through to regular * non-camera NDOF behavior (exiting the camera-view and rotating). @@ -393,16 +396,14 @@ static int view3d_ndof_cameraview_pan_zoom(bContext *C, const wmEvent *event) bool changed = false; if (has_translate) { - const float speed = NDOF_PIXELS_PER_SECOND; - float event_ofs[2] = {pan_vec[0] * speed, pan_vec[1] * speed}; - if (ED_view3d_camera_view_pan(region, event_ofs)) { + /* Use the X & Y of `pan_vec`. */ + if (ED_view3d_camera_view_pan(region, pan_vec)) { changed = true; } } if (has_zoom) { - const float scale = 1.0f + pan_vec[2]; - if (ED_view3d_camera_view_zoom_scale(rv3d, scale)) { + if (ED_view3d_camera_view_zoom_scale(rv3d, max_ff(0.0f, 1.0f - pan_vec[2]))) { changed = true; } } diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index ec6f62e0f5b..3787a59c83c 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -40,7 +40,7 @@ set(SRC transform_convert_mesh_uv.c transform_convert_mesh_vert_cdata.c transform_convert_nla.c - transform_convert_node.c + transform_convert_node.cc transform_convert_object.c transform_convert_object_texspace.c transform_convert_paintcurve.c diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 6f7eb317b42..93e99f97387 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1518,26 +1518,26 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - bool use_prop_edit = false; - int prop_edit_flag = 0; - if (t->flag & T_PROP_EDIT_ALL) { - if (t->flag & T_PROP_EDIT) { - use_prop_edit = true; - } - if (t->flag & T_PROP_CONNECTED) { - prop_edit_flag |= PROP_EDIT_CONNECTED; - } - if (t->flag & T_PROP_PROJECTED) { - prop_edit_flag |= PROP_EDIT_PROJECTED; + /* Save proportional edit settings. + * Skip saving proportional edit if it was not actually used. */ + if (!(t->options & CTX_NO_PET)) { + bool use_prop_edit = false; + int prop_edit_flag = 0; + if (t->flag & T_PROP_EDIT_ALL) { + if (t->flag & T_PROP_EDIT) { + use_prop_edit = true; + } + if (t->flag & T_PROP_CONNECTED) { + prop_edit_flag |= PROP_EDIT_CONNECTED; + } + if (t->flag & T_PROP_PROJECTED) { + prop_edit_flag |= PROP_EDIT_PROJECTED; + } } - } - /* If modal, save settings back in scene if not set as operator argument */ - if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) { - /* save settings if not set in operator */ - - /* skip saving proportional edit if it was not actually used */ - if (!(t->options & CTX_NO_PET)) { + /* If modal, save settings back in scene if not set as operator argument */ + if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) { + /* save settings if not set in operator */ if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit")) && !RNA_property_is_set(op->ptr, prop)) { BKE_view_layer_synced_ensure(t->scene, t->view_layer); @@ -1576,6 +1576,14 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ts->prop_mode = t->prop_mode; } } + + if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) { + RNA_property_boolean_set(op->ptr, prop, use_prop_edit); + RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED); + RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED); + RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode); + RNA_float_set(op->ptr, "proportional_size", t->prop_size); + } } /* Save snapping settings. */ @@ -1635,14 +1643,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - if ((prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) { - RNA_property_boolean_set(op->ptr, prop, use_prop_edit); - RNA_boolean_set(op->ptr, "use_proportional_connected", prop_edit_flag & PROP_EDIT_CONNECTED); - RNA_boolean_set(op->ptr, "use_proportional_projected", prop_edit_flag & PROP_EDIT_PROJECTED); - RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode); - RNA_float_set(op->ptr, "proportional_size", t->prop_size); - } - if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) { RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0); } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 09fc07f57f4..e2bab378cad 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -19,6 +19,10 @@ #include "transform_data.h" +#ifdef __cplusplus +extern "C" { +#endif + /* use node center for transform instead of upper-left corner. * disabled since it makes absolute snapping not work so nicely */ @@ -141,6 +145,7 @@ typedef enum { /** No cursor wrapping on region bounds */ T_NO_CURSOR_WRAP = 1 << 23, } eTFlag; +ENUM_OPERATORS(eTFlag, T_NO_CURSOR_WRAP); #define T_ALL_RESTRICTIONS (T_NO_CONSTRAINT | T_NULL_ONE) #define T_PROP_EDIT_ALL (T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED) @@ -864,3 +869,7 @@ bool checkUseAxisMatrix(TransInfo *t); th++, i++) /** \} */ + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index f32bff6dcff..8466fd88e1d 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -10,6 +10,10 @@ #include "RE_engine.h" +#ifdef __cplusplus +extern "C" { +#endif + struct BMEditMesh; struct BMesh; struct BezTriple; @@ -244,7 +248,7 @@ extern TransConvertTypeInfo TransConvertType_MeshVertCData; extern TransConvertTypeInfo TransConvertType_NLA; -/* transform_convert_node.c */ +/* transform_convert_node.cc */ extern TransConvertTypeInfo TransConvertType_Node; @@ -279,3 +283,7 @@ extern TransConvertTypeInfo TransConvertType_SequencerImage; /* transform_convert_tracking.c */ extern TransConvertTypeInfo TransConvertType_Tracking; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index cfa933d1600..af5a51cbff6 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -56,6 +56,29 @@ typedef struct TransDataNla { } TransDataNla; /* -------------------------------------------------------------------- */ +/** \name Transform application to NLA strips + * \{ */ + +/** + * \brief Applies a translation to the given NlaStrip. + * \param strip_rna_ptr The RNA pointer of the NLA strip to modify. + * \param transdata The transformation info structure. + */ +static void applyTransformNLA_translation(PointerRNA *strip_rna_ptr, const TransDataNla *transdata) +{ + /* NOTE: we write these twice to avoid truncation errors which can arise when + * moving the strips a large distance using numeric input T33852. + */ + RNA_float_set(strip_rna_ptr, "frame_start", transdata->h1[0]); + RNA_float_set(strip_rna_ptr, "frame_end", transdata->h2[0]); + + RNA_float_set(strip_rna_ptr, "frame_start", transdata->h1[0]); + RNA_float_set(strip_rna_ptr, "frame_end", transdata->h2[0]); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name NLA Transform Creation * \{ */ @@ -329,15 +352,8 @@ static void recalcData_nla(TransInfo *t) * * this is done as a iterative procedure (done 5 times max for now) */ - NlaStrip *prev = strip->prev; - while (prev != NULL && (prev->type & NLASTRIP_TYPE_TRANSITION)) { - prev = prev->prev; - } - - NlaStrip *next = strip->next; - while (next != NULL && (next->type & NLASTRIP_TYPE_TRANSITION)) { - next = next->next; - } + NlaStrip *prev = BKE_nlastrip_prev_in_track(strip, true); + NlaStrip *next = BKE_nlastrip_next_in_track(strip, true); for (short iter = 0; iter < 5; iter++) { const bool pExceeded = (prev != NULL) && (tdn->h1[0] < prev->end); @@ -380,17 +396,10 @@ static void recalcData_nla(TransInfo *t) /* Use RNA to write the values to ensure that constraints on these are obeyed * (e.g. for transition strips, the values are taken from the neighbors) - * - * NOTE: we write these twice to avoid truncation errors which can arise when - * moving the strips a large distance using numeric input T33852. */ RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); - RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]); - RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]); - - RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]); - RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]); + applyTransformNLA_translation(&strip_ptr, tdn); /* flush transforms to child strips (since this should be a meta) */ BKE_nlameta_flush_transforms(strip); diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.cc index ed19789fdd8..eb5eb822d69 100644 --- a/source/blender/editors/transform/transform_convert_node.c +++ b/source/blender/editors/transform/transform_convert_node.cc @@ -96,13 +96,13 @@ static bool is_node_parent_select(bNode *node) return false; } -static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) +static void createTransNodeData(bContext * /*C*/, TransInfo *t) { const float dpi_fac = UI_DPI_FAC; - SpaceNode *snode = t->area->spacedata.first; + SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first); /* Custom data to enable edge panning during the node transform */ - struct TransCustomDataNode *customdata = MEM_callocN(sizeof(*customdata), __func__); + TransCustomDataNode *customdata = MEM_cnew<TransCustomDataNode>(__func__); UI_view2d_edge_pan_init(t->context, &customdata->edgepan_data, NODE_EDGE_PAN_INSIDE_PAD, @@ -125,7 +125,7 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) } /* Nodes don't support PET and probably never will. */ - t->flag &= ~T_PROP_EDIT_ALL; + t->flag = t->flag & ~T_PROP_EDIT_ALL; /* set transform flags on nodes */ LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { @@ -142,9 +142,8 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) return; } - TransData *td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData"); - TransData2D *td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), - "TransNode TransData2D"); + TransData *td = tc->data = MEM_cnew_array<TransData>(tc->data_len, __func__); + TransData2D *td2d = tc->data_2d = MEM_cnew_array<TransData2D>(tc->data_len, __func__); LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & NODE_TRANSFORM) { @@ -161,9 +160,11 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) static void flushTransNodes(TransInfo *t) { + using namespace blender::ed; const float dpi_fac = UI_DPI_FAC; + SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first); - struct TransCustomDataNode *customdata = (struct TransCustomDataNode *)t->custom.type.data; + TransCustomDataNode *customdata = (TransCustomDataNode *)t->custom.type.data; if (t->options & CTX_VIEW2D_EDGE_PAN) { if (t->state == TRANS_CANCEL) { @@ -196,7 +197,7 @@ static void flushTransNodes(TransInfo *t) for (int i = 0; i < tc->data_len; i++) { TransData *td = &tc->data[i]; TransData2D *td2d = &tc->data_2d[i]; - bNode *node = td->extra; + bNode *node = static_cast<bNode *>(td->extra); float loc[2]; add_v2_v2v2(loc, td2d->loc, offset); @@ -221,7 +222,7 @@ static void flushTransNodes(TransInfo *t) /* handle intersection with noodles */ if (tc->data_len == 1) { - ED_node_link_intersect_test(t->area, 1); + space_node::node_insert_on_link_flags_set(*snode, *t->region); } } } @@ -234,13 +235,15 @@ static void flushTransNodes(TransInfo *t) static void special_aftertrans_update__node(bContext *C, TransInfo *t) { - struct Main *bmain = CTX_data_main(C); + using namespace blender::ed; + Main *bmain = CTX_data_main(C); + SpaceNode *snode = (SpaceNode *)t->area->spacedata.first; + bNodeTree *ntree = snode->edittree; + const bool canceled = (t->state == TRANS_CANCEL); - SpaceNode *snode = (SpaceNode *)t->area->spacedata.first; if (canceled && t->remove_on_cancel) { /* remove selected nodes on cancel */ - bNodeTree *ntree = snode->edittree; if (ntree) { LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) { if (node->flag & NODE_SELECT) { @@ -253,11 +256,10 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t) if (!canceled) { ED_node_post_apply_transform(C, snode->edittree); - ED_node_link_insert(bmain, t->area); + space_node::node_insert_on_link_flags(*bmain, *snode); } - /* clear link line */ - ED_node_link_intersect_test(t->area, 0); + space_node::node_insert_on_link_flags_clear(*ntree); } /** \} */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index dbda9a26bbf..82791b2a9f5 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -523,9 +523,7 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static bool transform_poll_property(const bContext *UNUSED(C), - wmOperator *op, - const PropertyRNA *prop) +static bool transform_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); @@ -559,12 +557,21 @@ static bool transform_poll_property(const bContext *UNUSED(C), } /* Proportional Editing. */ - { + if (STRPREFIX(prop_id, "proportional") || STRPREFIX(prop_id, "use_proportional")) { + ScrArea *area = CTX_wm_area(C); + if (area->spacetype == SPACE_NLA) { + /* Hide properties that are not supported in some spaces. */ + return false; + } + PropertyRNA *prop_pet = RNA_struct_find_property(op->ptr, "use_proportional_edit"); - if (prop_pet && (prop_pet != prop) && (RNA_property_boolean_get(op->ptr, prop_pet) == false)) { - if (STRPREFIX(prop_id, "proportional") || STRPREFIX(prop_id, "use_proportional")) { - return false; - } + if ((prop_pet != prop) && (RNA_property_boolean_get(op->ptr, prop_pet) == false)) { + /* If "use_proportional_edit" is false, hide: + * - "proportional_edit_falloff", + * - "proportional_size", + * - "use_proportional_connected", + * - "use_proportional_projected". */ + return false; } } diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 3672e76c778..2b78c554ad8 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -11,6 +11,10 @@ /* For enum. */ #include "DNA_space_types.h" +#ifdef __cplusplus +extern "C" { +#endif + bool peelObjectsTransform(struct TransInfo *t, const float mval[2], bool use_peel_object, @@ -92,3 +96,7 @@ void transform_snap_anim_flush_data(TransInfo *t, TransData *td, eAnimEdit_AutoSnap autosnap, float *r_val_final); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 90a13722b63..7971e1ca9af 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -105,7 +105,7 @@ struct SnapData_EditMesh { /* Looptris. */ BVHTreeFromEditMesh treedata_editmesh; - struct Mesh_Runtime *mesh_runtime; + blender::bke::MeshRuntime *mesh_runtime; float min[3], max[3]; void clear() @@ -189,14 +189,14 @@ static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval); if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) { - if (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { return nullptr; } me_eval = editmesh_eval_final; use_hide = true; } else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) { - if (editmesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if (editmesh_eval_cage->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { return nullptr; } me_eval = editmesh_eval_cage; @@ -253,21 +253,21 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, sod = sod_p->get(); bool is_dirty = false; if (sod->treedata_mesh.tree && sod->treedata_mesh.cached && - !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->treedata_mesh.tree)) { + !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->treedata_mesh.tree)) { /* The tree is owned by the Mesh and may have been freed since we last used. */ is_dirty = true; } else if (sod->bvhtree[0] && sod->cached[0] && - !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[0])) { + !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[0])) { /* The tree is owned by the Mesh and may have been freed since we last used. */ is_dirty = true; } else if (sod->bvhtree[1] && sod->cached[1] && - !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[1])) { + !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[1])) { /* The tree is owned by the Mesh and may have been freed since we last used. */ is_dirty = true; } - else if (sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) { + else if (sod->treedata_mesh.looptri != me_eval->looptris().data()) { is_dirty = true; } else if (sod->treedata_mesh.vert != verts.data()) { @@ -330,19 +330,19 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, /* Searches for the #Mesh_Runtime associated with the object that is most likely to be updated due * to changes in the `edit_mesh`. */ -static Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval) +static blender::bke::MeshRuntime *snap_object_data_editmesh_runtime_get(Object *ob_eval) { Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval); if (editmesh_eval_final) { - return &editmesh_eval_final->runtime; + return editmesh_eval_final->runtime; } Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval); if (editmesh_eval_cage) { - return &editmesh_eval_cage->runtime; + return editmesh_eval_cage->runtime; } - return &((Mesh *)ob_eval->data)->runtime; + return ((Mesh *)ob_eval->data)->runtime; } static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx, @@ -457,7 +457,7 @@ static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectCon 4, BVHTREE_FROM_EM_LOOPTRI, &sod->mesh_runtime->bvh_cache, - static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex)); + &sod->mesh_runtime->eval_mutex); } } if (treedata == nullptr || treedata->tree == nullptr) { @@ -2923,7 +2923,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, 2, BVHTREE_FROM_EM_VERTS, &sod->mesh_runtime->bvh_cache, - (ThreadMutex *)sod->mesh_runtime->eval_mutex); + &sod->mesh_runtime->eval_mutex); } sod->bvhtree[0] = treedata.tree; sod->cached[0] = treedata.cached; @@ -2955,7 +2955,7 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, 2, BVHTREE_FROM_EM_EDGES, &sod->mesh_runtime->bvh_cache, - static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex)); + &sod->mesh_runtime->eval_mutex); } sod->bvhtree[1] = treedata.tree; sod->cached[1] = treedata.cached; diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc index 2648ec5e2f6..bdd05b06d94 100644 --- a/source/blender/editors/uvedit/uvedit_islands.cc +++ b/source/blender/editors/uvedit/uvedit_islands.cc @@ -403,6 +403,203 @@ int bm_mesh_calc_uv_islands(const Scene *scene, /** \} */ +static float pack_islands_scale_margin(const blender::Vector<FaceIsland *> &island_vector, + BoxPack *box_array, + const float scale, + const float margin) +{ + for (const int index : island_vector.index_range()) { + FaceIsland *island = island_vector[index]; + BoxPack *box = &box_array[index]; + box->index = index; + box->w = BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin; + box->h = BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin; + } + float max_u, max_v; + BLI_box_pack_2d(box_array, island_vector.size(), &max_u, &max_v); + return max_ff(max_u, max_v); +} + +static float pack_islands_margin_fraction(const blender::Vector<FaceIsland *> &island_vector, + BoxPack *box_array, + const float margin_fraction) +{ + /* + * Root finding using a combined search / modified-secant method. + * First, use a robust search procedure to bracket the root within a factor of 10. + * Then, use a modified-secant method to converge. + * + * This is a specialized solver using domain knowledge to accelerate convergence. + */ + + float scale_low = 0.0f; + float value_low = 0.0f; + float scale_high = 0.0f; + float value_high = 0.0f; + float scale_last = 0.0f; + + /* Scaling smaller than `min_scale_roundoff` is unlikely to fit and + * will destroy information in existing UVs. */ + float min_scale_roundoff = 1e-5f; + + /* Certain inputs might have poor convergence properties. + * Use `max_iteration` to prevent an infinite loop. */ + int max_iteration = 25; + for (int iteration = 0; iteration < max_iteration; iteration++) { + float scale = 1.0f; + + if (iteration == 0) { + BLI_assert(iteration == 0); + BLI_assert(scale == 1.0f); + BLI_assert(scale_low == 0.0f); + BLI_assert(scale_high == 0.0f); + } + else if (scale_low == 0.0f) { + BLI_assert(scale_high > 0.0f); + /* Search mode, shrink layout until we can find a scale that fits. */ + scale = scale_high * 0.1f; + } + else if (scale_high == 0.0f) { + BLI_assert(scale_low > 0.0f); + /* Search mode, grow layout until we can find a scale that doesn't fit. */ + scale = scale_low * 10.0f; + } + else { + /* Bracket mode, use modified secant method to find root. */ + BLI_assert(scale_low > 0.0f); + BLI_assert(scale_high > 0.0f); + BLI_assert(value_low <= 0.0f); + BLI_assert(value_high >= 0.0f); + if (scale_high < scale_low * 1.0001f) { + /* Convergence. */ + break; + } + + /* Secant method for area. */ + scale = (sqrtf(scale_low) * value_high - sqrtf(scale_high) * value_low) / + (value_high - value_low); + scale = scale * scale; + + if (iteration & 1) { + /* Modified binary-search to improve robustness. */ + scale = sqrtf(scale * sqrtf(scale_low * scale_high)); + } + } + + scale = max_ff(scale, min_scale_roundoff); + + /* Evaluate our `f`. */ + scale_last = scale; + float max_uv = pack_islands_scale_margin( + island_vector, box_array, scale_last, margin_fraction); + float value = sqrtf(max_uv) - 1.0f; + + if (value <= 0.0f) { + scale_low = scale; + value_low = value; + } + else { + scale_high = scale; + value_high = value; + if (scale == min_scale_roundoff) { + /* Unable to pack without damaging UVs. */ + scale_low = scale; + break; + } + } + } + + const bool flush = true; + if (flush) { + /* Write back best pack as a side-effect. First get best pack. */ + if (scale_last != scale_low) { + scale_last = scale_low; + float max_uv = pack_islands_scale_margin( + island_vector, box_array, scale_last, margin_fraction); + UNUSED_VARS(max_uv); + /* TODO (?): `if (max_uv < 1.0f) { scale_last /= max_uv; }` */ + } + + /* Then expand FaceIslands by the correct amount. */ + for (const int index : island_vector.index_range()) { + BoxPack *box = &box_array[index]; + box->x /= scale_last; + box->y /= scale_last; + FaceIsland *island = island_vector[index]; + BLI_rctf_pad( + &island->bounds_rect, margin_fraction / scale_last, margin_fraction / scale_last); + } + } + return scale_last; +} + +static float calc_margin_from_aabb_length_sum(const blender::Vector<FaceIsland *> &island_vector, + const struct UVPackIsland_Params ¶ms) +{ + /* Logic matches behavior from #GEO_uv_parametrizer_pack. + * Attempt to give predictable results + * not dependent on current UV scale by using + * `aabb_length_sum` (was "`area`") to multiply + * the margin by the length (was "area"). + */ + double aabb_length_sum = 0.0f; + for (FaceIsland *island : island_vector) { + float w = BLI_rctf_size_x(&island->bounds_rect); + float h = BLI_rctf_size_y(&island->bounds_rect); + aabb_length_sum += sqrtf(w * h); + } + return params.margin * aabb_length_sum * 0.1f; +} + +static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_vector, + const struct UVPackIsland_Params ¶ms, + float r_scale[2]) +{ + BoxPack *box_array = static_cast<BoxPack *>( + MEM_mallocN(sizeof(*box_array) * island_vector.size(), __func__)); + + if (params.margin == 0.0f) { + /* Special case for zero margin. Margin_method is ignored as all formulas give same result. */ + const float max_uv = pack_islands_scale_margin(island_vector, box_array, 1.0f, 0.0f); + r_scale[0] = 1.0f / max_uv; + r_scale[1] = r_scale[0]; + return box_array; + } + + if (params.margin_method == ED_UVPACK_MARGIN_FRACTION) { + /* Uses a line search on scale. ~10x slower than other method. */ + const float scale = pack_islands_margin_fraction(island_vector, box_array, params.margin); + r_scale[0] = scale; + r_scale[1] = scale; + /* pack_islands_margin_fraction will pad FaceIslands, return early. */ + return box_array; + } + + float margin = params.margin; + switch (params.margin_method) { + case ED_UVPACK_MARGIN_ADD: /* Default for Blender 2.8 and earlier. */ + break; /* Nothing to do. */ + case ED_UVPACK_MARGIN_SCALED: /* Default for Blender 3.3 and later. */ + margin = calc_margin_from_aabb_length_sum(island_vector, params); + break; + case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */ + BLI_assert_unreachable(); /* Handled above. */ + break; + default: + BLI_assert_unreachable(); + } + + const float max_uv = pack_islands_scale_margin(island_vector, box_array, 1.0f, margin); + r_scale[0] = 1.0f / max_uv; + r_scale[1] = r_scale[0]; + + for (int index = 0; index < island_vector.size(); index++) { + FaceIsland *island = island_vector[index]; + BLI_rctf_pad(&island->bounds_rect, margin, margin); + } + return box_array; +} + /* -------------------------------------------------------------------- */ /** \name Public UV Island Packing * @@ -412,6 +609,7 @@ int bm_mesh_calc_uv_islands(const Scene *scene, void ED_uvedit_pack_islands_multi(const Scene *scene, Object **objects, const uint objects_len, + BMesh **bmesh_override, const struct UVMapUDIM_Params *udim_params, const struct UVPackIsland_Params *params) { @@ -419,9 +617,17 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BMesh *bm = nullptr; + if (bmesh_override) { + /* Note: obedit is still required for aspect ratio and ID_RECALC_GEOMETRY. */ + bm = bmesh_override[ob_index]; + } + else { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bm = em->bm; + } + BLI_assert(bm); + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); if (cd_loop_uv_offset == -1) { continue; } @@ -437,7 +643,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, ListBase island_list = {nullptr}; bm_mesh_calc_uv_islands(scene, - em->bm, + bm, &island_list, params->only_selected_faces, params->only_selected_uvs, @@ -455,19 +661,12 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, return; } - float margin = scene->toolsettings->uvcalc_margin; - double area = 0.0f; - - BoxPack *boxarray = static_cast<BoxPack *>( - MEM_mallocN(sizeof(*boxarray) * island_vector.size(), __func__)); - /* Coordinates of bounding box containing all selected UVs. */ float selection_min_co[2], selection_max_co[2]; INIT_MINMAX2(selection_min_co, selection_max_co); for (int index = 0; index < island_vector.size(); index++) { FaceIsland *island = island_vector[index]; - /* Skip calculation if using specified UDIM option. */ if (udim_params && (udim_params->use_target_udim == false)) { float bounds_min[2], bounds_max[2]; @@ -489,17 +688,6 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, bm_face_array_calc_bounds( island->faces, island->faces_len, island->cd_loop_uv_offset, &island->bounds_rect); - - BoxPack *box = &boxarray[index]; - box->index = index; - box->x = 0.0f; - box->y = 0.0f; - box->w = BLI_rctf_size_x(&island->bounds_rect); - box->h = BLI_rctf_size_y(&island->bounds_rect); - - if (margin > 0.0f) { - area += double(sqrtf(box->w * box->h)); - } } /* Center of bounding box containing all selected UVs. */ @@ -509,28 +697,8 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f; } - if (margin > 0.0f) { - /* Logic matches behavior from #GEO_uv_parametrizer_pack, - * use area so multiply the margin by the area to give - * predictable results not dependent on UV scale. */ - margin = (margin * float(area)) * 0.1f; - for (int i = 0; i < island_vector.size(); i++) { - FaceIsland *island = island_vector[i]; - BoxPack *box = &boxarray[i]; - - BLI_rctf_pad(&island->bounds_rect, margin, margin); - box->w = BLI_rctf_size_x(&island->bounds_rect); - box->h = BLI_rctf_size_y(&island->bounds_rect); - } - } - - float boxarray_size[2]; - BLI_box_pack_2d(boxarray, island_vector.size(), &boxarray_size[0], &boxarray_size[1]); - - /* Don't change the aspect when scaling. */ - boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]); - - const float scale[2] = {1.0f / boxarray_size[0], 1.0f / boxarray_size[1]}; + float scale[2] = {1.0f, 1.0f}; + BoxPack *box_array = pack_islands_params(island_vector, *params, scale); /* Tile offset. */ float base_offset[2] = {0.0f, 0.0f}; @@ -580,14 +748,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, } for (int i = 0; i < island_vector.size(); i++) { - FaceIsland *island = island_vector[boxarray[i].index]; + FaceIsland *island = island_vector[box_array[i].index]; const float pivot[2] = { island->bounds_rect.xmin, island->bounds_rect.ymin, }; const float offset[2] = { - ((boxarray[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0], - ((boxarray[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1], + ((box_array[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0], + ((box_array[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1], }; for (int j = 0; j < island->faces_len; j++) { BMFace *efa = island->faces[j]; @@ -607,7 +775,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, MEM_freeN(island); } - MEM_freeN(boxarray); + MEM_freeN(box_array); } /** \} */ diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 661a2a1b05b..2c977552e72 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1050,25 +1050,6 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /** \name Pack UV Islands Operator * \{ */ -static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm) -{ - const UnwrapOptions options = { - .topology_from_uvs = true, - .only_selected_faces = false, - .only_selected_uvs = true, - .fill_holes = false, - .correct_aspect = false, - }; - - bool rotate = true; - bool ignore_pinned = false; - - ParamHandle *handle = construct_param_handle(scene, ob, bm, &options, NULL); - GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); - GEO_uv_parametrizer_flush(handle); - GEO_uv_parametrizer_delete(handle); -} - /** * \warning Since this uses #ParamHandle it doesn't work with non-manifold meshes (see T82637). * Use #ED_uvedit_pack_islands_multi for a more general solution. @@ -1125,7 +1106,6 @@ static int pack_islands_exec(bContext *C, wmOperator *op) } /* RNA props */ - const bool rotate = RNA_boolean_get(op->ptr, "rotate"); const int udim_source = RNA_enum_get(op->ptr, "udim_source"); if (RNA_struct_property_is_set(op->ptr, "margin")) { scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin"); @@ -1139,21 +1119,36 @@ static int pack_islands_exec(bContext *C, wmOperator *op) const bool use_udim_params = ED_uvedit_udim_params_from_image_space( sima, use_active, &udim_params); - ED_uvedit_pack_islands_multi(scene, - objects, - objects_len, - use_udim_params ? &udim_params : NULL, - &(struct UVPackIsland_Params){ - .rotate = rotate, - .only_selected_uvs = true, - .only_selected_faces = true, - .correct_aspect = true, - }); + struct UVPackIsland_Params params = { + .rotate = RNA_boolean_get(op->ptr, "rotate"), + .only_selected_uvs = true, + .only_selected_faces = true, + .correct_aspect = true, + .margin_method = RNA_enum_get(op->ptr, "margin_method"), + .margin = RNA_float_get(op->ptr, "margin"), + }; + ED_uvedit_pack_islands_multi( + scene, objects, objects_len, NULL, use_udim_params ? &udim_params : NULL, ¶ms); MEM_freeN(objects); return OPERATOR_FINISHED; } +const EnumPropertyItem pack_margin_method[] = { + {ED_UVPACK_MARGIN_SCALED, + "SCALED", + 0, + "Scaled", + "Use scale of existing UVs to multiply margin"}, + {ED_UVPACK_MARGIN_ADD, "ADD", 0, "Add", "Just add the margin, ignoring any UV scale"}, + {ED_UVPACK_MARGIN_FRACTION, + "FRACTION", + 0, + "Fraction", + "Specify a precise fraction of final UV output"}, + {0, NULL, 0, NULL, NULL}, +}; + void UV_OT_pack_islands(wmOperatorType *ot) { static const EnumPropertyItem pack_target[] = { @@ -1180,6 +1175,8 @@ void UV_OT_pack_islands(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "udim_source", pack_target, PACK_UDIM_SRC_CLOSEST, "Pack to", ""); RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit"); + RNA_def_enum( + ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", ""); RNA_def_float_factor( ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } @@ -2098,6 +2095,8 @@ void UV_OT_unwrap(wmOperatorType *ot) 0, "Use Subdivision Surface", "Map UVs taking vertex position after Subdivision Surface modifier has been applied"); + RNA_def_enum( + ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", ""); RNA_def_float_factor( ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } @@ -2118,7 +2117,6 @@ typedef struct ThickFace { static int smart_uv_project_thickface_area_cmp_fn(const void *tf_a_p, const void *tf_b_p) { - const ThickFace *tf_a = (ThickFace *)tf_a_p; const ThickFace *tf_b = (ThickFace *)tf_b_p; @@ -2412,17 +2410,17 @@ static int smart_project_exec(bContext *C, wmOperator *op) /* Depsgraph refresh functions are called here. */ const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); - ED_uvedit_pack_islands_multi(scene, - objects_changed, - object_changed_len, - NULL, - &(struct UVPackIsland_Params){ - .rotate = true, - .only_selected_uvs = only_selected_uvs, - .only_selected_faces = true, - .correct_aspect = correct_aspect, - .use_seams = true, - }); + + const struct UVPackIsland_Params params = { + .rotate = true, + .only_selected_uvs = only_selected_uvs, + .only_selected_faces = true, + .correct_aspect = correct_aspect, + .use_seams = true, + .margin_method = RNA_enum_get(op->ptr, "margin_method"), + .margin = RNA_float_get(op->ptr, "island_margin"), + }; + ED_uvedit_pack_islands_multi(scene, objects_changed, object_changed_len, NULL, NULL, ¶ms); /* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */ const bool per_face_aspect = false; @@ -2464,6 +2462,8 @@ void UV_OT_smart_project(wmOperatorType *ot) DEG2RADF(89.0f)); RNA_def_property_float_default(prop, DEG2RADF(66.0f)); + RNA_def_enum( + ot->srna, "margin_method", pack_margin_method, ED_UVPACK_MARGIN_SCALED, "Margin Method", ""); RNA_def_float(ot->srna, "island_margin", 0.0f, @@ -3161,13 +3161,24 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob) .calc_face_normal = true, .calc_vert_normal = true, })); - /* select all uv loops first - pack parameters needs this to make sure charts are registered */ + /* Select all UVs for cube_project. */ ED_uvedit_select_all(bm); /* A cube size of 2.0 maps [-1..1] vertex coords to [0.0..1.0] in UV coords. */ uvedit_unwrap_cube_project(scene, bm, 2.0, false, false, NULL); - /* Set the margin really quickly before the packing operation. */ - scene->toolsettings->uvcalc_margin = 0.001f; - uvedit_pack_islands(scene, ob, bm); + + /* Pack UVs. */ + const struct UVPackIsland_Params params = { + .rotate = true, + .only_selected_uvs = false, + .only_selected_faces = false, + .correct_aspect = false, + .use_seams = true, + .margin_method = ED_UVPACK_MARGIN_SCALED, + .margin = 0.001f, + }; + ED_uvedit_pack_islands_multi(scene, &ob, 1, &bm, NULL, ¶ms); + + /* Write back from BMesh to Mesh. */ BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0})); BM_mesh_free(bm); diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc index 25935691bf4..a03c9b994a9 100644 --- a/source/blender/geometry/intern/add_curves_on_mesh.cc +++ b/source/blender/geometry/intern/add_curves_on_mesh.cc @@ -385,10 +385,11 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves, return true; } bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id); - const int new_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? new_points_num : - new_curves_num; + /* The new elements are added at the end of the array. */ + const int old_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? old_points_num : + old_curves_num; const CPPType &type = attribute.span.type(); - GMutableSpan new_data = attribute.span.take_back(new_elements_num); + GMutableSpan new_data = attribute.span.drop_front(old_elements_num); type.fill_assign_n(type.default_value(), new_data.data(), new_data.size()); attribute.finish(); return true; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c index 9a0ee4d9d92..387e3c2d5ce 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c @@ -209,6 +209,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { + gps->flag &= ~GP_STROKE_TAG; convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat); } } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index a8cba959689..c1e71bde254 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1953,8 +1953,6 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge LineartEdgeNeighbor *edge_nabr = MEM_mallocN(sizeof(LineartEdgeNeighbor) * total_edges, "LineartEdgeNeighbor arr"); - MLoopTri *mlooptri = me->runtime.looptris.array; - TaskParallelSettings en_settings; BLI_parallel_range_settings_defaults(&en_settings); /* Set the minimum amount of edges a thread has to process. */ @@ -1963,7 +1961,7 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge EdgeNeighborData en_data; en_data.adj_e = adj_e; en_data.edge_nabr = edge_nabr; - en_data.mlooptri = mlooptri; + en_data.mlooptri = BKE_mesh_runtime_looptri_ensure(me); en_data.mloop = BKE_mesh_loops(me); BLI_task_parallel_range(0, total_edges, &en_data, lineart_edge_neighbor_init_task, &en_settings); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index e2285a3fd3e..f387a4588b6 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -332,6 +332,7 @@ set(GLSL_SRC shaders/compositor/compositor_alpha_crop.glsl shaders/compositor/compositor_bilateral_blur.glsl shaders/compositor/compositor_blur.glsl + shaders/compositor/compositor_blur_variable_size.glsl shaders/compositor/compositor_bokeh_image.glsl shaders/compositor/compositor_box_mask.glsl shaders/compositor/compositor_convert.glsl @@ -346,6 +347,7 @@ set(GLSL_SRC shaders/compositor/compositor_morphological_distance_feather.glsl shaders/compositor/compositor_morphological_distance_threshold.glsl shaders/compositor/compositor_morphological_step.glsl + shaders/compositor/compositor_parallel_reduction.glsl shaders/compositor/compositor_projector_lens_distortion.glsl shaders/compositor/compositor_realize_on_domain.glsl shaders/compositor/compositor_screen_lens_distortion.glsl @@ -612,6 +614,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_alpha_crop_info.hh shaders/compositor/infos/compositor_bilateral_blur_info.hh shaders/compositor/infos/compositor_blur_info.hh + shaders/compositor/infos/compositor_blur_variable_size_info.hh shaders/compositor/infos/compositor_bokeh_image_info.hh shaders/compositor/infos/compositor_box_mask_info.hh shaders/compositor/infos/compositor_convert_info.hh @@ -626,6 +629,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_morphological_distance_info.hh shaders/compositor/infos/compositor_morphological_distance_threshold_info.hh shaders/compositor/infos/compositor_morphological_step_info.hh + shaders/compositor/infos/compositor_parallel_reduction_info.hh shaders/compositor/infos/compositor_projector_lens_distortion_info.hh shaders/compositor/infos/compositor_realize_on_domain_info.hh shaders/compositor/infos/compositor_screen_lens_distortion_info.hh diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 31354585308..3dad2a1a19a 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -162,6 +162,7 @@ GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli, uint32_t *r_hash); +GPUNodeLink *GPU_layer_attribute(GPUMaterial *mat, const char *name); GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser, @@ -357,6 +358,20 @@ struct GHash *GPU_uniform_attr_list_hash_new(const char *info); void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, const GPUUniformAttrList *src); void GPU_uniform_attr_list_free(GPUUniformAttrList *set); +typedef struct GPULayerAttr { + struct GPULayerAttr *next, *prev; + + /* Meaningful part of the attribute set key. */ + char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + /** Hash of name[64]. */ + uint32_t hash_code; + + /* Helper fields used by code generation. */ + int users; +} GPULayerAttr; + +const ListBase *GPU_material_layer_attributes(const GPUMaterial *material); + /* A callback passed to GPU_material_from_callbacks to construct the material graph by adding and * linking the necessary GPU material nodes. */ typedef void (*ConstructGPUMaterialFn)(void *thunk, GPUMaterial *material); diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h index f78719d1963..28f06d6071d 100644 --- a/source/blender/gpu/GPU_uniform_buffer.h +++ b/source/blender/gpu/GPU_uniform_buffer.h @@ -44,6 +44,7 @@ void GPU_uniformbuf_unbind_all(void); #define GPU_UBO_BLOCK_NAME "node_tree" #define GPU_ATTRIBUTE_UBO_BLOCK_NAME "unf_attrs" +#define GPU_LAYER_ATTRIBUTE_UBO_BLOCK_NAME "drw_layer_attrs" #ifdef __cplusplus } diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index b02d8a02704..4adeac1b49a 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -183,6 +183,8 @@ static std::ostream &operator<<(std::ostream &stream, const GPUInput *input) return stream << "var_attrs.v" << input->attr->id; case GPU_SOURCE_UNIFORM_ATTR: return stream << "unf_attrs[resource_id].attr" << input->uniform_attr->id; + case GPU_SOURCE_LAYER_ATTR: + return stream << "attr_load_layer(" << input->layer_attr->hash_code << ")"; case GPU_SOURCE_STRUCT: return stream << "strct" << input->id; case GPU_SOURCE_TEX: @@ -432,6 +434,10 @@ void GPUCodegen::generate_resources() info.uniform_buf(2, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH); } + if (!BLI_listbase_is_empty(&graph.layer_attrs)) { + info.additional_info("draw_layer_attributes"); + } + info.typedef_source_generated = ss.str(); } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 0f9dc8be9c5..ca2a9f5cf28 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -291,6 +291,12 @@ const GPUUniformAttrList *GPU_material_uniform_attributes(const GPUMaterial *mat return attrs->count > 0 ? attrs : NULL; } +const ListBase *GPU_material_layer_attributes(const GPUMaterial *material) +{ + const ListBase *attrs = &material->graph.layer_attrs; + return !BLI_listbase_is_empty(attrs) ? attrs : NULL; +} + #if 1 /* End of life code. */ /* Eevee Subsurface scattering. */ /* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index e1ae731d49c..c72e7097b33 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -83,6 +83,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType case GPU_SOURCE_UNIFORM_ATTR: input->uniform_attr->users++; break; + case GPU_SOURCE_LAYER_ATTR: + input->layer_attr->users++; + break; case GPU_SOURCE_TEX: case GPU_SOURCE_TEX_TILED_MAPPING: input->texture->users++; @@ -133,6 +136,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType input->source = GPU_SOURCE_UNIFORM_ATTR; input->uniform_attr = link->uniform_attr; break; + case GPU_NODE_LINK_LAYER_ATTR: + input->source = GPU_SOURCE_LAYER_ATTR; + input->layer_attr = link->layer_attr; + break; case GPU_NODE_LINK_CONSTANT: input->source = (type == GPU_CLOSURE) ? GPU_SOURCE_STRUCT : GPU_SOURCE_CONSTANT; break; @@ -430,6 +437,34 @@ static GPUUniformAttr *gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph, return attr; } +/** Add a new uniform attribute of given type and name. Returns NULL if out of slots. */ +static GPULayerAttr *gpu_node_graph_add_layer_attribute(GPUNodeGraph *graph, const char *name) +{ + /* Find existing attribute. */ + ListBase *attrs = &graph->layer_attrs; + GPULayerAttr *attr = attrs->first; + + for (; attr; attr = attr->next) { + if (STREQ(attr->name, name)) { + break; + } + } + + /* Add new requested attribute to the list. */ + if (attr == NULL) { + attr = MEM_callocN(sizeof(*attr), __func__); + STRNCPY(attr->name, name); + attr->hash_code = BLI_ghashutil_strhash_p(attr->name); + BLI_addtail(attrs, attr); + } + + if (attr != NULL) { + attr->users++; + } + + return attr; +} + static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, Image *ima, ImageUser *iuser, @@ -546,6 +581,17 @@ GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, return link; } +GPUNodeLink *GPU_layer_attribute(GPUMaterial *mat, const char *name) +{ + GPUNodeGraph *graph = gpu_material_node_graph(mat); + GPULayerAttr *attr = gpu_node_graph_add_layer_attribute(graph, name); + + GPUNodeLink *link = gpu_node_link_create(); + link->link_type = GPU_NODE_LINK_LAYER_ATTR; + link->layer_attr = attr; + return link; +} + GPUNodeLink *GPU_constant(const float *num) { GPUNodeLink *link = gpu_node_link_create(); @@ -767,14 +813,22 @@ static void gpu_inputs_free(ListBase *inputs) GPUInput *input; for (input = inputs->first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTR) { - input->attr->users--; - } - else if (input->source == GPU_SOURCE_UNIFORM_ATTR) { - input->uniform_attr->users--; - } - else if (ELEM(input->source, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING)) { - input->texture->users--; + switch (input->source) { + case GPU_SOURCE_ATTR: + input->attr->users--; + break; + case GPU_SOURCE_UNIFORM_ATTR: + input->uniform_attr->users--; + break; + case GPU_SOURCE_LAYER_ATTR: + input->layer_attr->users--; + break; + case GPU_SOURCE_TEX: + case GPU_SOURCE_TEX_TILED_MAPPING: + input->texture->users--; + break; + default: + break; } if (input->link) { @@ -826,6 +880,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph) BLI_freelistN(&graph->textures); BLI_freelistN(&graph->attributes); GPU_uniform_attr_list_free(&graph->uniform_attrs); + BLI_freelistN(&graph->layer_attrs); if (graph->used_libraries) { BLI_gset_free(graph->used_libraries, NULL); @@ -908,4 +963,10 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph) uattrs->count--; } } + + LISTBASE_FOREACH_MUTABLE (GPULayerAttr *, attr, &graph->layer_attrs) { + if (attr->users == 0) { + BLI_freelinkN(&graph->layer_attrs, attr); + } + } } diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 7db22151f86..de0a0687b13 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -31,6 +31,7 @@ typedef enum eGPUDataSource { GPU_SOURCE_UNIFORM, GPU_SOURCE_ATTR, GPU_SOURCE_UNIFORM_ATTR, + GPU_SOURCE_LAYER_ATTR, GPU_SOURCE_STRUCT, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING, @@ -42,6 +43,7 @@ typedef enum { GPU_NODE_LINK_NONE = 0, GPU_NODE_LINK_ATTR, GPU_NODE_LINK_UNIFORM_ATTR, + GPU_NODE_LINK_LAYER_ATTR, GPU_NODE_LINK_COLORBAND, GPU_NODE_LINK_CONSTANT, GPU_NODE_LINK_IMAGE, @@ -95,6 +97,8 @@ struct GPUNodeLink { struct GPUMaterialAttribute *attr; /* GPU_NODE_LINK_UNIFORM_ATTR */ struct GPUUniformAttr *uniform_attr; + /* GPU_NODE_LINK_LAYER_ATTR */ + struct GPULayerAttr *layer_attr; /* GPU_NODE_LINK_IMAGE_BLENDER */ struct GPUMaterialTexture *texture; /* GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN */ @@ -131,6 +135,8 @@ typedef struct GPUInput { struct GPUMaterialAttribute *attr; /* GPU_SOURCE_UNIFORM_ATTR */ struct GPUUniformAttr *uniform_attr; + /* GPU_SOURCE_LAYER_ATTR */ + struct GPULayerAttr *layer_attr; /* GPU_SOURCE_FUNCTION_CALL */ char function_call[64]; }; @@ -171,6 +177,9 @@ typedef struct GPUNodeGraph { /* The list of uniform attributes. */ GPUUniformAttrList uniform_attrs; + /* The list of layer attributes. */ + ListBase layer_attrs; + /** Set of all the GLSL lib code blocks . */ GSet *used_libraries; } GPUNodeGraph; diff --git a/source/blender/gpu/metal/mtl_immediate.mm b/source/blender/gpu/metal/mtl_immediate.mm index aaebe7e20f8..4b63a3b1ce2 100644 --- a/source/blender/gpu/metal/mtl_immediate.mm +++ b/source/blender/gpu/metal/mtl_immediate.mm @@ -125,7 +125,7 @@ void MTLImmediate::end() * TODO(Metal): Cache this vertex state based on Vertex format and shaders. */ for (int i = 0; i < interface->get_total_attributes(); i++) { - /* Note: Attribute in VERTEX FORMAT does not necessarily share the same array index as + /* NOTE: Attribute in VERTEX FORMAT does not necessarily share the same array index as * attributes in shader interface. */ GPUVertAttr *attr = nullptr; const MTLShaderInputAttribute &mtl_shader_attribute = interface->get_attribute(i); diff --git a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl new file mode 100644 index 00000000000..e7e5aac12a5 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl @@ -0,0 +1,60 @@ +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +/* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from + * the weights texture, where the texel (0, 0) is considered the center of weights texture. */ +vec4 load_weight(ivec2 texel, float radius) +{ + /* The center zero texel is always assigned a unit weight regardless of the corresponding weight + * in the weights texture. That's to guarantee that at last the center pixel will be accumulated + * even if the weights texture is zero at its center. */ + if (texel == ivec2(0)) { + return vec4(1.0); + } + + /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper + * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the + * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */ + return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1)); +} + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + /* The mask input is treated as a boolean. If it is zero, then no blurring happens for this + * pixel. Otherwise, the pixel is blurred normally and the mask value is irrelevant. */ + float mask = texture_load(mask_tx, texel).x; + if (mask == 0.0) { + imageStore(output_img, texel, texture_load(input_tx, texel)); + return; + } + + float center_size = texture_load(size_tx, texel).x * base_size; + + /* Go over the window of the given search radius and accumulate the colors multiplied by their + * respective weights as well as the weights themselves, but only if both the size of the center + * pixel and the size of the candidate pixel are less than both the x and y distances of the + * candidate pixel. */ + vec4 accumulated_color = vec4(0.0); + vec4 accumulated_weight = vec4(0.0); + for (int y = -search_radius; y <= search_radius; y++) { + for (int x = -search_radius; x <= search_radius; x++) { + float candidate_size = texture_load(size_tx, texel + ivec2(x, y)).x * base_size; + + /* Skip accumulation if either the x or y distances of the candidate pixel are larger than + * either the center or candidate pixel size. Note that the max and min functions here denote + * "either" in the aforementioned description. */ + float size = min(center_size, candidate_size); + if (max(abs(x), abs(y)) > size) { + continue; + } + + vec4 weight = load_weight(ivec2(x, y), size); + accumulated_color += texture_load(input_tx, texel + ivec2(x, y)) * weight; + accumulated_weight += weight; + } + } + + imageStore(output_img, texel, safe_divide(accumulated_color, accumulated_weight)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl b/source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl new file mode 100644 index 00000000000..f6f84aa24c1 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_parallel_reduction.glsl @@ -0,0 +1,98 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +/* This shader reduces the given texture into a smaller texture of a size equal to the number of + * work groups. In particular, each work group reduces its contents into a single value and writes + * that value to a single pixel in the output image. The shader can be dispatched multiple times to + * eventually reduce the image into a single pixel. + * + * The shader works by loading the whole data of each work group into a linear array, then it + * reduces the second half of the array onto the first half of the array, then it reduces the + * second quarter of the array onto the first quarter or the array, and so on until only one + * element remains. The following figure illustrates the process for sum reduction on 8 elements. + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * | 0 | | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | Original data. + * '---' '---' '---' '---' '---' '---' '---' '---' + * |.____|_____|_____|_____| | | | + * || |.____|_____|___________| | | + * || || |.____|_________________| | + * || || || |.______________________| <--First reduction. Stride = 4. + * || || || || + * .---. .---. .---. .----. + * | 4 | | 6 | | 8 | | 10 | <--Data after first reduction. + * '---' '---' '---' '----' + * |.____|_____| | + * || |.__________| <--Second reduction. Stride = 2. + * || || + * .----. .----. + * | 12 | | 16 | <--Data after second reduction. + * '----' '----' + * |.____| + * || <--Third reduction. Stride = 1. + * .----. + * | 28 | + * '----' <--Data after third reduction. + * + * + * The shader is generic enough to implement many types of reductions. This is done by using macros + * that the developer should define to implement a certain reduction operation. Those include, + * TYPE, IDENTITY, INITIALIZE, LOAD, and REDUCE. See the implementation below for more information + * as well as the compositor_parallel_reduction_info.hh for example reductions operations. */ + +/* Doing the reduction in shared memory is faster, so create a shared array where the whole data + * of the work group will be loaded and reduced. The 2D structure of the work group is irrelevant + * for reduction, so we just load the data in a 1D array to simplify reduction. The developer is + * expected to define the TYPE macro to be a float or a vec4, depending on the type of data being + * reduced. */ +const uint reduction_size = gl_WorkGroupSize.x * gl_WorkGroupSize.y; +shared TYPE reduction_data[reduction_size]; + +void main() +{ + /* Load the data from the texture, while returning IDENTITY for out of bound coordinates. The + * developer is expected to define the IDENTITY macro to be a vec4 that does not affect the + * output of the reduction. For instance, sum reductions have an identity of vec4(0.0), while + * max value reductions have an identity of vec4(FLT_MIN). */ + vec4 value = texture_load(input_tx, ivec2(gl_GlobalInvocationID.xy), IDENTITY); + + /* Initialize the shared array given the previously loaded value. This step can be different + * depending on whether this is the initial reduction pass or a latter one. Indeed, the input + * texture for the initial reduction is the source texture itself, while the input texture to a + * latter reduction pass is an intermediate texture after one or more reductions have happened. + * This is significant because the data being reduced might be computed from the original data + * and different from it, for instance, when summing the luminance of an image, the original data + * is a vec4 color, while the reduced data is a float luminance value. So for the initial + * reduction pass, the luminance will be computed from the color, reduced, then stored into an + * intermediate float texture. On the other hand, for latter reduction passes, the luminance will + * be loaded directly and reduced without extra processing. So the developer is expected to + * define the INITIALIZE and LOAD macros to be expressions that derive the needed value from the + * loaded value for the initial reduction pass and latter ones respectively. */ + reduction_data[gl_LocalInvocationIndex] = is_initial_reduction ? INITIALIZE(value) : LOAD(value); + + /* Reduce the reduction data by half on every iteration until only one element remains. See the + * above figure for an intuitive understanding of the stride value. */ + for (uint stride = reduction_size / 2; stride > 0; stride /= 2) { + barrier(); + + /* Only the threads up to the current stride should be active as can be seen in the diagram + * above. */ + if (gl_LocalInvocationIndex >= stride) { + continue; + } + + /* Reduce each two elements that are stride apart, writing the result to the element with the + * lower index, as can be seen in the diagram above. The developer is expected to define the + * REDUCE macro to be a commutative and associative binary operator suitable for parallel + * reduction. */ + reduction_data[gl_LocalInvocationIndex] = REDUCE( + reduction_data[gl_LocalInvocationIndex], reduction_data[gl_LocalInvocationIndex + stride]); + } + + /* Finally, the result of the reduction is available as the first element in the reduction data, + * write it to the pixel corresponding to the work group, making sure only the one thread writes + * it. */ + barrier(); + if (gl_LocalInvocationIndex == 0) { + imageStore(output_img, ivec2(gl_WorkGroupID.xy), vec4(reduction_data[0])); + } +} diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_blur_variable_size_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_blur_variable_size_info.hh new file mode 100644 index 00000000000..05b6385fd1e --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_blur_variable_size_info.hh @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_blur_variable_size) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "base_size") + .push_constant(Type::INT, "search_radius") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .sampler(1, ImageType::FLOAT_2D, "weights_tx") + .sampler(2, ImageType::FLOAT_2D, "size_tx") + .sampler(3, ImageType::FLOAT_2D, "mask_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_blur_variable_size.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh new file mode 100644 index 00000000000..2e661f280af --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_parallel_reduction_shared) + .local_group_size(16, 16) + .push_constant(Type::BOOL, "is_initial_reduction") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .compute_source("compositor_parallel_reduction.glsl"); + +/* -------------------------------------------------------------------- + * Sum Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_sum_float_shared) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .define("TYPE", "float") + .define("IDENTITY", "vec4(0.0)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "lhs + rhs"); + +GPU_SHADER_CREATE_INFO(compositor_sum_red) + .additional_info("compositor_sum_float_shared") + .define("INITIALIZE(value)", "value.r") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_green) + .additional_info("compositor_sum_float_shared") + .define("INITIALIZE(value)", "value.g") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_blue) + .additional_info("compositor_sum_float_shared") + .define("INITIALIZE(value)", "value.b") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_luminance) + .additional_info("compositor_sum_float_shared") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") + .do_static_compilation(true); + +/* -------------------------------------------------------------------- + * Sum Of Squared Difference Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_sum_squared_difference_float_shared) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::FLOAT, "subtrahend") + .define("TYPE", "float") + .define("IDENTITY", "vec4(subtrahend)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "lhs + rhs"); + +GPU_SHADER_CREATE_INFO(compositor_sum_red_squared_difference) + .additional_info("compositor_sum_squared_difference_float_shared") + .define("INITIALIZE(value)", "pow(value.r - subtrahend, 2.0)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_green_squared_difference) + .additional_info("compositor_sum_squared_difference_float_shared") + .define("INITIALIZE(value)", "pow(value.g - subtrahend, 2.0)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_blue_squared_difference) + .additional_info("compositor_sum_squared_difference_float_shared") + .define("INITIALIZE(value)", "pow(value.b - subtrahend, 2.0)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_luminance_squared_difference) + .additional_info("compositor_sum_squared_difference_float_shared") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("INITIALIZE(value)", "pow(dot(value.rgb, luminance_coefficients) - subtrahend, 2.0)") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl index bacf089deb1..8d0016a2206 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_attribute.glsl @@ -29,6 +29,31 @@ void node_attribute_uniform(vec4 attr, const float attr_hash, out vec4 out_attr) out_attr = attr_load_uniform(attr, floatBitsToUint(attr_hash)); } +vec4 attr_load_layer(const uint attr_hash) +{ +#ifdef VLATTR_LIB + /* The first record of the buffer stores the length. */ + uint left = 0, right = drw_layer_attrs[0].buffer_length; + + while (left < right) { + uint mid = (left + right) / 2; + uint hash = drw_layer_attrs[mid].hash_code; + + if (hash < attr_hash) { + left = mid + 1; + } + else if (hash > attr_hash) { + right = mid; + } + else { + return drw_layer_attrs[mid].data; + } + } +#endif + + return vec4(0.0); +} + void node_attribute( vec4 attr, out vec4 outcol, out vec3 outvec, out float outf, out float outalpha) { diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 78fb75ddb40..9317f14b7f1 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -1783,7 +1783,7 @@ static void execute_scene(struct Depsgraph *depsgraph, for (i = ikscene->targets.size(); i > 0; i--) { IK_Target *iktarget = ikscene->targets[i - 1]; if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF) && iktarget->constraint) { - unsigned int nvalues; + uint nvalues; const iTaSC::ConstraintValues *values; values = iktarget->constraint->getControlParameters(&nvalues); iktarget->errorCallback(values, nvalues, iktarget); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 7e652e31506..5c76dfe52df 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -895,6 +895,13 @@ eGPUTextureFormat IMB_gpu_get_texture_format(const struct ImBuf *ibuf, bool use_grayscale); /** + * Ensures that values stored in the float rect can safely loaded into half float gpu textures. + * + * Does nothing when given image_buffer doesn't contain a float rect. + */ +void IMB_gpu_clamp_half_float(struct ImBuf *image_buffer); + +/** * The `ibuf` is only here to detect the storage type. The produced texture will have undefined * content. It will need to be populated by using #IMB_update_gpu_texture_sub(). */ diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 4f8fe0d8cdc..71e0d0fe11e 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1093,12 +1093,14 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx) static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search) { - /* Step back half a frame position to make sure that we get the requested - * frame and not the one after it. This is a workaround as ffmpeg will - * sometimes not seek to a frame after the requested pts even if - * AVSEEK_FLAG_BACKWARD is specified. + /* FFmpeg seeks internally using DTS values instead of PTS. In some files DTS and PTS values are + * offset and sometimes ffmpeg fails to take this into account when seeking. + * Therefore we need to seek backwards a certain offset to make sure the frame we want is in + * front of us. It is not possible to determine the exact needed offset, this value is determined + * experimentally. Note: Too big offset can impact performance. Current 3 frame offset has no + * measurable impact. */ - return pts_to_search - (ffmpeg_steps_per_frame_get(anim) / 2); + return pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3); } /* This gives us an estimate of which pts our requested frame will have. diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc index edded204527..6d3452c64db 100644 --- a/source/blender/imbuf/intern/transform.cc +++ b/source/blender/imbuf/intern/transform.cc @@ -134,7 +134,7 @@ class NoDiscard : public BaseDiscard { * * Will never discard any pixels. */ - bool should_discard(const TransformUserData & /*user_data*/, const float UNUSED(uv[2])) override + bool should_discard(const TransformUserData & /*user_data*/, const float /*uv*/[2]) override { return false; } diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index 6f1275e1812..dd509677d8d 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -370,3 +370,19 @@ eGPUTextureFormat IMB_gpu_get_texture_format(const ImBuf *ibuf, return gpu_texture_format; } + +void IMB_gpu_clamp_half_float(ImBuf *image_buffer) +{ + const float half_min = -65504; + const float half_max = 65504; + if (!image_buffer->rect_float) { + return; + } + + int rect_float_len = image_buffer->x * image_buffer->y * + (image_buffer->channels == 0 ? 4 : image_buffer->channels); + + for (int i = 0; i < rect_float_len; i++) { + image_buffer->rect_float[i] = clamp_f(image_buffer->rect_float[i], half_min, half_max); + } +} diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index 39595089109..b92ce5b4cfb 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -608,15 +608,11 @@ static void import_endjob(void *user_data) lc = BKE_layer_collection_get_active(view_layer); - /* Add all objects to the collection (don't do sync for each object). */ - BKE_layer_collection_resync_forbid(); for (AbcObjectReader *reader : data->readers) { Object *ob = reader->object(); BKE_collection_object_add(data->bmain, lc->collection, ob); } - /* Sync the collection, and do view layer operations. */ - BKE_layer_collection_resync_allow(); - BKE_main_collection_sync(data->bmain); + /* Sync and do the view layer operations. */ BKE_view_layer_synced_ensure(scene, view_layer); for (AbcObjectReader *reader : data->readers) { Object *ob = reader->object(); diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc index 5808c6bc77a..b8cc43beeb9 100644 --- a/source/blender/io/usd/intern/usd_capi_import.cc +++ b/source/blender/io/usd/intern/usd_capi_import.cc @@ -317,8 +317,7 @@ static void import_endjob(void *customdata) lc = BKE_layer_collection_get_active(view_layer); - /* Add all objects to the collection (don't do sync for each object). */ - BKE_layer_collection_resync_forbid(); + /* Add all objects to the collection. */ for (USDPrimReader *reader : data->archive->readers()) { if (!reader) { continue; @@ -330,9 +329,7 @@ static void import_endjob(void *customdata) BKE_collection_object_add(data->bmain, lc->collection, ob); } - /* Sync the collection, and do view layer operations. */ - BKE_layer_collection_resync_allow(); - BKE_main_collection_sync(data->bmain); + /* Sync and do the view layer operations. */ BKE_view_layer_synced_ensure(scene, view_layer); for (USDPrimReader *reader : data->archive->readers()) { if (!reader) { diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h index 0a92bbca477..cf6464eeb37 100644 --- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h @@ -35,7 +35,7 @@ struct OBJExportParams { /* Geometry Transform options. */ eIOAxis forward_axis; eIOAxis up_axis; - float scaling_factor; + float global_scale; /* File Write Options. */ bool export_selected_objects; @@ -65,6 +65,7 @@ struct OBJImportParams { char filepath[FILE_MAX]; /** Value 0 disables clamping. */ float clamp_size; + float global_scale; eIOAxis forward_axis; eIOAxis up_axis; bool import_vertex_groups; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 95be927589e..5c81cf7abca 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -261,7 +261,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh, BLI_assert(tot_count == attribute.size()); obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { - float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); + float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.global_scale); ColorGeometry4f linear = attribute.get(i); float srgb[3]; linearrgb_to_srgb_v3_v3(srgb, linear); @@ -270,7 +270,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh, } else { obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { - float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); + float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.global_scale); buf.write_obj_vertex(vertex[0], vertex[1], vertex[2]); }); } @@ -435,7 +435,7 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_d const int total_vertices = obj_nurbs_data.total_spline_vertices(spline_idx); for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) { const float3 vertex_coords = obj_nurbs_data.vertex_coordinates( - spline_idx, vertex_idx, export_params_.scaling_factor); + spline_idx, vertex_idx, export_params_.global_scale); fh.write_obj_vertex(vertex_coords[0], vertex_coords[1], vertex_coords[2]); } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index 9f19a6390d3..d00c09b9013 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -265,13 +265,13 @@ const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const return mat->id.name + 2; } -float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_factor) const +float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scale) const { float3 r_coords; const Span<MVert> verts = export_mesh_eval_->verts(); copy_v3_v3(r_coords, verts[vert_index].co); mul_m4_v3(world_and_axes_transform_, r_coords); - mul_v3_fl(r_coords, scaling_factor); + mul_v3_fl(r_coords, global_scale); return r_coords; } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index db29f5651ed..ec98468e2de 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -161,7 +161,7 @@ class OBJMesh : NonCopyable { /** * Calculate coordinates of the vertex at the given index. */ - float3 calc_vertex_coords(int vert_index, float scaling_factor) const; + float3 calc_vertex_coords(int vert_index, float global_scale) const; /** * Calculate vertex indices of all vertices of the polygon at the given index. */ diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc index 172a59e5341..812c3e7b5d4 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc @@ -55,14 +55,14 @@ int OBJCurve::total_spline_vertices(const int spline_index) const float3 OBJCurve::vertex_coordinates(const int spline_index, const int vertex_index, - const float scaling_factor) const + const float global_scale) const { const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index)); float3 r_coord; const BPoint &bpoint = nurb->bp[vertex_index]; copy_v3_v3(r_coord, bpoint.vec); mul_m4_v3(world_axes_transform_, r_coord); - mul_v3_fl(r_coord, scaling_factor); + mul_v3_fl(r_coord, global_scale); return r_coord; } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh index 65389d44f59..3f93112200f 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh @@ -37,7 +37,7 @@ class OBJCurve : NonCopyable { /** * Get coordinates of the vertex at the given index on the given spline. */ - float3 vertex_coordinates(int spline_index, int vertex_index, float scaling_factor) const; + float3 vertex_coordinates(int spline_index, int vertex_index, float global_scale) const; /** * Get total control points of the NURBS spline at the given index. This is different than total * vertices of a spline. diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc index f33753d720d..204237088ab 100644 --- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc +++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc @@ -103,6 +103,9 @@ void transform_object(Object *object, const OBJImportParams &import_params) IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, axes_transform); copy_m4_m3(obmat, axes_transform); + float scale_vec[3] = { + import_params.global_scale, import_params.global_scale, import_params.global_scale}; + rescale_m4(obmat, scale_vec); BKE_object_apply_mat4(object, obmat, true, false); if (import_params.clamp_size != 0.0f) { diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index bd1c2d32a12..0781028c880 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -508,6 +508,15 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, } /* Faces. */ else if (parse_keyword(p, end, "f")) { + /* If we don't have a material index assigned yet, get one. + * It means "usemtl" state came from the previous object. */ + if (state_material_index == -1 && !state_material_name.empty() && + curr_geom->material_indices_.is_empty()) { + curr_geom->material_indices_.add_new(state_material_name, 0); + curr_geom->material_order_.append(state_material_name); + state_material_index = 0; + } + geom_add_polygon(curr_geom, p, end, @@ -524,7 +533,10 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, else if (parse_keyword(p, end, "o")) { state_shaded_smooth = false; state_group_name = ""; - state_material_name = ""; + /* Reset object-local material index that's used in face infos. + * NOTE: do not reset the material name; that has to carry over + * into the next object if needed. */ + state_material_index = -1; curr_geom = create_geometry( curr_geom, GEOM_MESH, StringRef(p, end).trim(), r_all_geometries); } diff --git a/source/blender/io/wavefront_obj/importer/obj_importer.cc b/source/blender/io/wavefront_obj/importer/obj_importer.cc index ccbcce64d65..a42ec47151d 100644 --- a/source/blender/io/wavefront_obj/importer/obj_importer.cc +++ b/source/blender/io/wavefront_obj/importer/obj_importer.cc @@ -42,9 +42,6 @@ static void geometry_to_blender_objects(Main *bmain, { LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - /* Don't do collection syncs for each object, will do once after the loop. */ - BKE_layer_collection_resync_forbid(); - /* Sort objects by name: creating many objects is much faster if the creation * order is sorted by name. */ blender::parallel_sort( @@ -73,12 +70,8 @@ static void geometry_to_blender_objects(Main *bmain, } } - /* Sync the collection after all objects are created. */ - BKE_layer_collection_resync_allow(); - BKE_main_collection_sync(bmain); + /* Do object selections in a separate loop (allows just one view layer sync). */ BKE_view_layer_synced_ensure(scene, view_layer); - - /* After collection sync, select objects in the view layer and do DEG updates. */ for (Object *obj : objects) { Base *base = BKE_view_layer_base_find(view_layer, obj); BKE_view_layer_base_select_and_set_active(view_layer, base); diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index dcba78ac99e..5de3cdcd851 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -306,7 +306,7 @@ TEST_F(obj_exporter_regression_test, all_tris) TEST_F(obj_exporter_regression_test, all_quads) { OBJExportParamsDefault _export; - _export.params.scaling_factor = 2.0f; + _export.params.global_scale = 2.0f; _export.params.export_materials = false; compare_obj_export_to_golden( "io_tests/blend_geometry/all_quads.blend", "io_tests/obj/all_quads.obj", "", _export.params); @@ -429,7 +429,7 @@ TEST_F(obj_exporter_regression_test, cubes_positioned) { OBJExportParamsDefault _export; _export.params.export_materials = false; - _export.params.scaling_factor = 2.0f; + _export.params.global_scale = 2.0f; compare_obj_export_to_golden("io_tests/blend_geometry/cubes_positioned.blend", "io_tests/obj/cubes_positioned.obj", "", diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh index 006d86312b6..a4d452e1309 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh @@ -19,7 +19,7 @@ struct OBJExportParamsDefault { params.forward_axis = IO_AXIS_NEGATIVE_Z; params.up_axis = IO_AXIS_Y; - params.scaling_factor = 1.f; + params.global_scale = 1.f; params.apply_modifiers = true; params.export_eval_mode = DAG_EVAL_VIEWPORT; diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index 8d1171097b8..f459e1ab1bd 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -8,6 +8,7 @@ #include "BKE_curve.h" #include "BKE_customdata.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -22,6 +23,7 @@ #include "DEG_depsgraph_query.h" #include "DNA_curve_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" @@ -41,6 +43,7 @@ struct Expectation { float3 normal_first; float2 uv_first; float4 color_first = {-1, -1, -1, -1}; + std::string first_mat; }; class obj_importer_test : public BlendfileLoadingBaseTest { @@ -57,6 +60,7 @@ class obj_importer_test : public BlendfileLoadingBaseTest { } OBJImportParams params; + params.global_scale = 1.0f; params.clamp_size = 0; params.forward_axis = IO_AXIS_NEGATIVE_Z; params.up_axis = IO_AXIS_Y; @@ -132,6 +136,10 @@ class obj_importer_test : public BlendfileLoadingBaseTest { // int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0; // EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic); } + if (!exp.first_mat.empty()) { + Material *mat = BKE_object_material_get(object, 1); + ASSERT_STREQ(mat ? mat->id.name : "<null>", exp.first_mat.c_str()); + } ++object_index; } DEG_OBJECT_ITER_END; @@ -309,7 +317,42 @@ TEST_F(obj_importer_test, import_materials) { Expectation expect[] = { {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)}, - {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)}, + {"OBmaterials", + OB_MESH, + 8, + 12, + 6, + 24, + float3(-1, -1, 1), + float3(1, -1, -1), + float3(0), + float2(0), + float4(-1), + "MAno_textures_red"}, + {"OBObjMtlAfter", + OB_MESH, + 3, + 3, + 1, + 3, + float3(3, 0, 0), + float3(5, 0, 0), + float3(0), + float2(0), + float4(-1), + "MAno_textures_red"}, + {"OBObjMtlBefore", + OB_MESH, + 3, + 3, + 1, + 3, + float3(6, 0, 0), + float3(8, 0, 0), + float3(0), + float2(0), + float4(-1), + "MAClay"}, }; import_and_check("materials.obj", expect, std::size(expect), 4, 8); } @@ -327,7 +370,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) float3(1, 1, -1), float3(-1, -1, 1), float3(0, 1, 0), - float2(0.9935f, 0.0020f)}, + float2(0.9935f, 0.0020f), + float4(-1), + "MAMat_BaseRoughEmissNormal10"}, {"OBCubeTexMul", OB_MESH, 8, @@ -337,7 +382,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) float3(4, -2, -1), float3(2, -4, 1), float3(0, 1, 0), - float2(0.9935f, 0.0020f)}, + float2(0.9935f, 0.0020f), + float4(-1), + "MAMat_BaseMul"}, {"OBCubeTiledTex", OB_MESH, 8, @@ -347,7 +394,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) float3(4, 1, -1), float3(2, -1, 1), float3(0, 1, 0), - float2(0.9935f, 0.0020f)}, + float2(0.9935f, 0.0020f), + float4(-1), + "MAMat_BaseTiled"}, {"OBCubeTiledTexFromAnotherFolder", OB_MESH, 8, @@ -357,7 +406,9 @@ TEST_F(obj_importer_test, import_cubes_with_textures_rel) float3(7, 1, -1), float3(5, -1, 1), float3(0, 1, 0), - float2(0.9935f, 0.0020f)}, + float2(0.9935f, 0.0020f), + float4(-1), + "MAMat_EmissTiledAnotherFolder"}, }; import_and_check("cubes_with_textures_rel.obj", expect, std::size(expect), 4, 4); } @@ -455,7 +506,10 @@ TEST_F(obj_importer_test, import_all_objects) 26, float3(28, 1, -1), float3(26, 1, 1), - float3(-1, 0, 0)}, + float3(-1, 0, 0), + float2(0), + float4(-1), + "MARed"}, {"OBNurbsCircle", OB_MESH, 96, @@ -491,7 +545,10 @@ TEST_F(obj_importer_test, import_all_objects) 26, float3(4, 1, -1), float3(2, 1, 1), - float3(0.5774f, 0.5773f, 0.5774f)}, + float3(0.5774f, 0.5773f, 0.5774f), + float2(0), + float4(-1), + "MAMaterial"}, {"OBSurface", OB_MESH, 256, diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index 570b569a4dd..8b889e17762 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -330,9 +330,8 @@ typedef enum eAutomasking_flag { BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3), BRUSH_AUTOMASKING_CAVITY_NORMAL = (1 << 4), - /* Note: normal and inverted are mutually exclusive, - * inverted has priority if both bits are set. - */ + /* NOTE: normal and inverted are mutually exclusive, + * inverted has priority if both bits are set. */ BRUSH_AUTOMASKING_CAVITY_INVERTED = (1 << 5), BRUSH_AUTOMASKING_CAVITY_ALL = (1 << 4) | (1 << 5), BRUSH_AUTOMASKING_CAVITY_USE_CURVE = (1 << 6), diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 2a17dbab8b3..3f951583741 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -19,10 +19,14 @@ namespace blender { template<typename T> class Span; template<typename T> class MutableSpan; namespace bke { +struct MeshRuntime; class AttributeAccessor; class MutableAttributeAccessor; } // namespace bke } // namespace blender +using MeshRuntimeHandle = blender::bke::MeshRuntime; +#else +typedef struct MeshRuntimeHandle MeshRuntimeHandle; #endif #ifdef __cplusplus @@ -30,133 +34,14 @@ extern "C" { #endif struct AnimData; -struct BVHCache; struct Ipo; struct Key; struct MCol; struct MEdge; struct MFace; -struct MLoopCol; struct MLoopTri; struct MVert; struct Material; -struct Mesh; -struct SubdivCCG; -struct SubsurfRuntimeData; - -# -# -typedef struct EditMeshData { - /** when set, \a vertexNos, polyNos are lazy initialized */ - const float (*vertexCos)[3]; - - /** lazy initialize (when \a vertexCos is set) */ - float const (*vertexNos)[3]; - float const (*polyNos)[3]; - /** also lazy init but don't depend on \a vertexCos */ - const float (*polyCos)[3]; -} EditMeshData; - -/** - * \warning Typical access is done via - * #BKE_mesh_runtime_looptri_ensure, #BKE_mesh_runtime_looptri_len. - */ -struct MLoopTri_Store { - DNA_DEFINE_CXX_METHODS(MLoopTri_Store) - - /* WARNING! swapping between array (ready-to-be-used data) and array_wip - * (where data is actually computed) - * shall always be protected by same lock as one used for looptris computing. */ - struct MLoopTri *array, *array_wip; - int len; - int len_alloc; -}; - -/** Runtime data, not saved in files. */ -typedef struct Mesh_Runtime { - DNA_DEFINE_CXX_METHODS(Mesh_Runtime) - - /* Evaluated mesh for objects which do not have effective modifiers. - * This mesh is used as a result of modifier stack evaluation. - * Since modifier stack evaluation is threaded on object level we need some synchronization. */ - struct Mesh *mesh_eval; - void *eval_mutex; - - /* A separate mutex is needed for normal calculation, because sometimes - * the normals are needed while #eval_mutex is already locked. */ - void *normals_mutex; - - /** Needed to ensure some thread-safety during render data pre-processing. */ - void *render_mutex; - - /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */ - struct EditMeshData *edit_data; - - /** - * Data used to efficiently draw the mesh in the viewport, especially useful when - * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`. - */ - void *batch_cache; - - /** Cache for derived triangulation of the mesh. */ - struct MLoopTri_Store looptris; - - /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */ - struct BVHCache *bvh_cache; - - /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */ - struct ShrinkwrapBoundaryData *shrinkwrap_data; - - /** Needed in case we need to lazily initialize the mesh. */ - CustomData_MeshMasks cd_mask_extra; - - struct SubdivCCG *subdiv_ccg; - int subdiv_ccg_tot_level; - - /** Set by modifier stack if only deformed from original. */ - char deformed_only; - /** - * Copied from edit-mesh (hint, draw with edit-mesh data when true). - * - * Modifiers that edit the mesh data in-place must set this to false - * (most #eModifierTypeType_NonGeometrical modifiers). Otherwise the edit-mesh - * data will be used for drawing, missing changes from modifiers. See T79517. - */ - char is_original_bmesh; - - /** #eMeshWrapperType and others. */ - char wrapper_type; - /** - * A type mask from wrapper_type, - * in case there are differences in finalizing logic between types. - */ - char wrapper_type_finalize; - - /** - * Settings for lazily evaluating the subdivision on the CPU if needed. These are - * set in the modifier when GPU subdivision can be performed, and owned by the by - * the modifier in the object. - */ - struct SubsurfRuntimeData *subsurf_runtime_data; - void *_pad1; - - /** - * Caches for lazily computed vertex and polygon normals. These are stored here rather than in - * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a - * const mesh is not thread-safe. - */ - char _pad2[6]; - char vert_normals_dirty; - char poly_normals_dirty; - float (*vert_normals)[3]; - float (*poly_normals)[3]; - - /** - * A #BLI_bitmap containing tags for the center vertices of subdivided polygons, set by the - * subdivision surface modifier and used by drawing code instead of polygon center face dots. - */ - uint32_t *subsurf_face_dot_tags; -} Mesh_Runtime; typedef struct Mesh { DNA_DEFINE_CXX_METHODS(Mesh) @@ -316,9 +201,13 @@ typedef struct Mesh { char _pad1[4]; - void *_pad2; - - Mesh_Runtime runtime; + /** + * Data that isn't saved in files, including caches of derived data, temporary data to improve + * the editing experience, etc. Runtime data is created when reading files and can be accessed + * without null checks, with the exception of some temporary meshes which should allocate and + * free the data if they are passed to functions that expect run-time data. + */ + MeshRuntimeHandle *runtime; #ifdef __cplusplus /** * Array of vertex positions (and various other data). Edges and faces are defined by indices @@ -383,16 +272,6 @@ typedef struct TFace { /* **************** MESH ********************* */ -/** #Mesh_Runtime.wrapper_type */ -typedef enum eMeshWrapperType { - /** Use mesh data (#Mesh.mvert, #Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */ - ME_WRAPPER_TYPE_MDATA = 0, - /** Use edit-mesh data (#Mesh.edit_mesh, #Mesh_Runtime.edit_data). */ - ME_WRAPPER_TYPE_BMESH = 1, - /** Use subdivision mesh data (#Mesh_Runtime.mesh_eval). */ - ME_WRAPPER_TYPE_SUBD = 2, -} eMeshWrapperType; - /** #Mesh.texflag */ enum { ME_AUTOSPACE = 1, diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 52e398ffff5..a1781265278 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -21,7 +21,7 @@ extern "C" { /** * Mesh Vertices. * - * Typically accessed from #Mesh.mvert + * Typically accessed from #Mesh.verts() */ typedef struct MVert { float co[3]; @@ -51,7 +51,7 @@ enum { /** * Mesh Edges. * - * Typically accessed from #Mesh.medge + * Typically accessed with #Mesh.edges() */ typedef struct MEdge { /** Un-ordered vertex indices (cannot match). */ @@ -79,10 +79,10 @@ enum { }; /** - * Mesh Faces + * Mesh Faces. * This only stores the polygon size & flags, the vertex & edge indices are stored in the #MLoop. * - * Typically accessed from #Mesh.mpoly. + * Typically accessed with #Mesh.polys(). */ typedef struct MPoly { /** Offset into loop array and number of loops in the face. */ @@ -109,7 +109,7 @@ enum { * Mesh Face Corners. * "Loop" is an internal name for the corner of a polygon (#MPoly). * - * Typically accessed from #Mesh.mloop. + * Typically accessed with #Mesh.loops(). */ typedef struct MLoop { /** Vertex index into an #MVert array. */ @@ -376,7 +376,7 @@ typedef struct MDisps { /** * Used for hiding parts of a multires mesh. - * Essentially the multires equivalent of the mesh ".hide_vert" boolean layer. + * Essentially the multires equivalent of the mesh ".hide_vert" boolean attribute. * * \note This is a bitmap, keep in sync with type used in BLI_bitmap.h */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 963567133d9..315bcbd971c 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -135,16 +135,16 @@ typedef struct bNodeSocket { /** Default input value used for unlinked sockets. */ void *default_value; - /* execution data */ - /** Local stack index. */ + /** Local stack index for "node_exec". */ short stack_index; - /* XXX deprecated, kept for forward compatibility */ - short stack_type DNA_DEPRECATED; char display_shape; /* #eAttrDomain used when the geometry nodes modifier creates an attribute for a group * output. */ char attribute_domain; + + char _pad[2]; + /* Runtime-only cache of the number of input links, for multi-input sockets. */ short total_inputs; @@ -170,9 +170,6 @@ typedef struct bNodeSocket { int own_index DNA_DEPRECATED; /* XXX deprecated, only used for restoring old group node links */ int to_index DNA_DEPRECATED; - /* XXX deprecated, still forward compatible since verification - * restores pointer from matching own_index. */ - struct bNodeSocket *groupsock DNA_DEPRECATED; /** A link pointer, set in #BKE_ntree_update_main. */ struct bNodeLink *link; @@ -1686,6 +1683,7 @@ enum { SHD_ATTRIBUTE_GEOMETRY = 0, SHD_ATTRIBUTE_OBJECT = 1, SHD_ATTRIBUTE_INSTANCER = 2, + SHD_ATTRIBUTE_VIEW_LAYER = 3, }; /* toon modes */ @@ -2076,6 +2074,15 @@ typedef enum CMPNodeFilterMethod { CMP_NODE_FILTER_SHARP_DIAMOND = 7, } CMPNodeFilterMethod; +/* Levels Node. Stored in custom1. */ +typedef enum CMPNodeLevelsChannel { + CMP_NODE_LEVLES_LUMINANCE = 1, + CMP_NODE_LEVLES_RED = 2, + CMP_NODE_LEVLES_GREEN = 3, + CMP_NODE_LEVLES_BLUE = 4, + CMP_NODE_LEVLES_LUMINANCE_BT709 = 5, +} CMPNodeLevelsChannel; + /* Plane track deform node. */ enum { diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 2db81693f51..5fa5d4c7787 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1761,6 +1761,8 @@ typedef struct Scene { ID id; /** Animation data (must be immediately after id for utilities to use it). */ struct AnimData *adt; + /* runtime (must be immediately after id for utilities to use it). */ + DrawDataList drawdata; struct Object *camera; struct World *world; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 7f0dd2f9be6..809c8be7bc4 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1184,6 +1184,12 @@ typedef struct SpaceImageOverlay { char _pad[4]; } SpaceImageOverlay; +typedef enum eSpaceImage_GridShapeSource { + SI_GRID_SHAPE_DYNAMIC = 0, + SI_GRID_SHAPE_FIXED = 1, + SI_GRID_SHAPE_PIXEL = 2, +} eSpaceImage_GridShapeSource; + typedef struct SpaceImage { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -1230,7 +1236,9 @@ typedef struct SpaceImage { char around; char gizmo_flag; - char _pad1[3]; + + char grid_shape_source; + char _pad1[2]; int flag; @@ -1239,7 +1247,7 @@ typedef struct SpaceImage { int tile_grid_shape[2]; /** * UV editor custom-grid. Value of `{M,N}` will produce `MxN` grid. - * Use when #SI_CUSTOM_GRID is set. + * Use when `custom_grid_shape == SI_GRID_SHAPE_FIXED`. */ int custom_grid_subdiv[2]; @@ -1266,7 +1274,7 @@ typedef enum eSpaceImage_PixelRoundMode { SI_PIXEL_ROUND_DISABLED = 0, SI_PIXEL_ROUND_CENTER = 1, SI_PIXEL_ROUND_CORNER = 2, -} eSpaceImage_Round_Mode; +} eSpaceImage_PixelRoundMode; /** #SpaceImage.mode */ typedef enum eSpaceImage_Mode { @@ -1300,7 +1308,7 @@ typedef enum eSpaceImage_Flag { SI_FULLWINDOW = (1 << 16), SI_FLAG_UNUSED_17 = (1 << 17), - SI_CUSTOM_GRID = (1 << 18), + SI_FLAG_UNUSED_18 = (1 << 18), /** * This means that the image is drawn until it reaches the view edge, diff --git a/source/blender/makesdna/DNA_userdef_enums.h b/source/blender/makesdna/DNA_userdef_enums.h index e90aa0e0f07..dc368819ab0 100644 --- a/source/blender/makesdna/DNA_userdef_enums.h +++ b/source/blender/makesdna/DNA_userdef_enums.h @@ -39,6 +39,7 @@ typedef enum eDupli_ID_Flags { USER_DUP_LATTICE = (1 << 17), USER_DUP_CAMERA = (1 << 18), USER_DUP_SPEAKER = (1 << 19), + USER_DUP_NTREE = (1 << 20), USER_DUP_OBDATA = (~0) & ((1 << 24) - 1), diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index d57cca0b055..9b235fac049 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -364,7 +364,7 @@ typedef struct wmOperatorTypeMacro { struct wmOperatorTypeMacro *next, *prev; /* operator id */ - char idname[64]; + char idname[64]; /* OP_MAX_TYPENAME */ /* rna pointer to access properties, like keymap */ /** Operator properties, assigned to ptr->data and can be written to a file. */ struct IDProperty *properties; @@ -551,7 +551,7 @@ typedef struct wmOperator { /* saved */ /** Used to retrieve type pointer. */ - char idname[64]; + char idname[64]; /* OP_MAX_TYPENAME */ /** Saved, user-settable properties. */ IDProperty *properties; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 3c9590ddcbe..5e4b08d8a41 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -92,7 +92,7 @@ static const EnumPropertyItem rna_enum_brush_texture_slot_map_texture_mode_items #endif /* clang-format off */ -/* Note: we don't actually turn these into a single enum bitmask property, +/* Note: we don't actually turn these into a single enum bit-mask property, * instead we construct individual boolean properties. */ const EnumPropertyItem RNA_automasking_flags[] = { {BRUSH_AUTOMASKING_TOPOLOGY, "use_automasking_topology", 0,"Topology", "Affect only vertices connected to the active vertex under the brush"}, diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index a12ba7d9287..bd601d0a736 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -785,29 +785,29 @@ static const EnumPropertyItem *rna_Fluid_cobafield_itemf(bContext *UNUSED(C), tmp.value = FLUID_DOMAIN_FIELD_PHI; tmp.identifier = "PHI"; tmp.icon = 0; - tmp.name = N_("Fluid Levelset"); - tmp.description = N_("Levelset representation of the fluid"); + tmp.name = N_("Fluid Level Set"); + tmp.description = N_("Level set representation of the fluid"); RNA_enum_item_add(&item, &totitem, &tmp); tmp.value = FLUID_DOMAIN_FIELD_PHI_IN; tmp.identifier = "PHI_IN"; tmp.icon = 0; - tmp.name = N_("Inflow Levelset"); - tmp.description = N_("Levelset representation of the inflow"); + tmp.name = N_("Inflow Level Set"); + tmp.description = N_("Level set representation of the inflow"); RNA_enum_item_add(&item, &totitem, &tmp); tmp.value = FLUID_DOMAIN_FIELD_PHI_OUT; tmp.identifier = "PHI_OUT"; tmp.icon = 0; - tmp.name = N_("Outflow Levelset"); - tmp.description = N_("Levelset representation of the outflow"); + tmp.name = N_("Outflow Level Set"); + tmp.description = N_("Level set representation of the outflow"); RNA_enum_item_add(&item, &totitem, &tmp); tmp.value = FLUID_DOMAIN_FIELD_PHI_OBSTACLE; tmp.identifier = "PHI_OBSTACLE"; tmp.icon = 0; - tmp.name = N_("Obstacle Levelset"); - tmp.description = N_("Levelset representation of the obstacles"); + tmp.name = N_("Obstacle Level Set"); + tmp.description = N_("Level set representation of the obstacles"); RNA_enum_item_add(&item, &totitem, &tmp); } diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 427a38094be..b08d4b60fcc 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -369,6 +369,16 @@ static bool rna_LayerCollection_has_selected_objects(LayerCollection *lc, return false; } +void rna_LayerCollection_children_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->owner_id; + LayerCollection *lc = (LayerCollection *)ptr->data; + ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc); + BKE_view_layer_synced_ensure(scene, view_layer); + + rna_iterator_listbase_begin(iter, &lc->layer_collections, NULL); +} + static bool rna_LayerCollection_children_lookupint(struct PointerRNA *ptr, int key, struct PointerRNA *r_ptr) @@ -435,7 +445,7 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_struct_type(prop, "LayerCollection"); RNA_def_property_ui_text(prop, "Children", "Child layer collections"); RNA_def_property_collection_funcs(prop, - NULL, + "rna_LayerCollection_children_begin", NULL, NULL, NULL, diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 9c6702142f7..bad099815a4 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -406,12 +406,39 @@ static int rna_MeshLoopTriangle_index_get(PointerRNA *ptr) { const Mesh *mesh = rna_mesh(ptr); const MLoopTri *ltri = (MLoopTri *)ptr->data; - const int index = (int)(ltri - mesh->runtime.looptris.array); + const int index = (int)(ltri - BKE_mesh_runtime_looptri_ensure(mesh)); BLI_assert(index >= 0); - BLI_assert(index < mesh->runtime.looptris.len); + BLI_assert(index < BKE_mesh_runtime_looptri_len(mesh)); return index; } +static void rna_Mesh_loop_triangles_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(mesh); + rna_iterator_array_begin( + iter, (void *)looptris, sizeof(MLoopTri), BKE_mesh_runtime_looptri_len(mesh), false, NULL); +} + +static int rna_Mesh_loop_triangles_length(PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + return BKE_mesh_runtime_looptri_len(mesh); +} + +int rna_Mesh_loop_triangles_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + if (index < 0 || index >= BKE_mesh_runtime_looptri_len(mesh)) { + return false; + } + /* Casting away const is okay because this RNA type doesn't allow changing the value. */ + r_ptr->owner_id = (ID *)&mesh->id; + r_ptr->type = &RNA_MeshLoopTriangle; + r_ptr->data = (void *)&BKE_mesh_runtime_looptri_ensure(mesh)[index]; + return true; +} + static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value) { Mesh *mesh = rna_mesh(ptr); @@ -1502,8 +1529,9 @@ static char *rna_MeshPolygon_path(const PointerRNA *ptr) static char *rna_MeshLoopTriangle_path(const PointerRNA *ptr) { - return BLI_sprintfN("loop_triangles[%d]", - (int)((MLoopTri *)ptr->data - rna_mesh(ptr)->runtime.looptris.array)); + return BLI_sprintfN( + "loop_triangles[%d]", + (int)((MLoopTri *)ptr->data - BKE_mesh_runtime_looptri_ensure(rna_mesh(ptr)))); } static char *rna_MeshEdge_path(const PointerRNA *ptr) @@ -3684,7 +3712,15 @@ static void rna_def_mesh(BlenderRNA *brna) NULL); prop = RNA_def_property(srna, "loop_triangles", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "runtime.looptris.array", "runtime.looptris.len"); + RNA_def_property_collection_funcs(prop, + "rna_Mesh_loop_triangles_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Mesh_loop_triangles_length", + "rna_Mesh_loop_triangles_lookup_int", + NULL, + NULL); RNA_def_property_struct_type(prop, "MeshLoopTriangle"); RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); RNA_def_property_ui_text(prop, "Loop Triangles", "Tessellation of mesh polygons into triangles"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index a0a933c3f90..0b0970a835e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5242,6 +5242,11 @@ static void def_sh_attribute(StructRNA *srna) "The attribute is associated with the instancer particle system or object, " "falling back to the Object mode if the attribute isn't found, or the object " "is not instanced"}, + {SHD_ATTRIBUTE_VIEW_LAYER, + "VIEW_LAYER", + 0, + "View Layer", + "The attribute is associated with the View Layer, Scene or World that is being rendered"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop; @@ -5504,6 +5509,7 @@ static void def_sh_tex_image(StructRNA *srna) RNA_def_property_enum_items(prop, prop_image_extension); RNA_def_property_ui_text( prop, "Extension", "How the image is extrapolated past its original bounds"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_IMAGE); RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE); @@ -5568,6 +5574,7 @@ static void def_geo_image_texture(StructRNA *srna) RNA_def_property_enum_items(prop, prop_image_extension); RNA_def_property_ui_text( prop, "Extension", "How the image is extrapolated past its original bounds"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_IMAGE); RNA_def_property_update(prop, 0, "rna_Node_update"); } @@ -6806,11 +6813,11 @@ static void def_cmp_levels(StructRNA *srna) PropertyRNA *prop; static const EnumPropertyItem channel_items[] = { - {1, "COMBINED_RGB", 0, "Combined", "Combined RGB"}, - {2, "RED", 0, "Red", "Red Channel"}, - {3, "GREEN", 0, "Green", "Green Channel"}, - {4, "BLUE", 0, "Blue", "Blue Channel"}, - {5, "LUMINANCE", 0, "Luminance", "Luminance Channel"}, + {CMP_NODE_LEVLES_LUMINANCE, "COMBINED_RGB", 0, "Combined", "Combined RGB"}, + {CMP_NODE_LEVLES_RED, "RED", 0, "Red", "Red Channel"}, + {CMP_NODE_LEVLES_GREEN, "GREEN", 0, "Green", "Green Channel"}, + {CMP_NODE_LEVLES_BLUE, "BLUE", 0, "Blue", "Blue Channel"}, + {CMP_NODE_LEVLES_LUMINANCE_BT709, "LUMINANCE", 0, "Luminance", "Luminance Channel"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 70afc763c2d..8fc504f192e 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -7861,6 +7861,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "World", "World used for rendering the scene"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WORLD); RNA_def_property_update(prop, NC_SCENE | ND_WORLD, "rna_Scene_world_update"); prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 738b41828e0..3cd8020ca6c 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3510,6 +3510,13 @@ static void rna_def_space_image_uv(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem grid_shape_source_items[] = { + {SI_GRID_SHAPE_DYNAMIC, "DYNAMIC", 0, "Dynamic", "Dynamic grid"}, + {SI_GRID_SHAPE_FIXED, "FIXED", 0, "Fixed", "Manually set grid divisions"}, + {SI_GRID_SHAPE_PIXEL, "PIXEL", 0, "Pixel", "Grid aligns with pixels from image"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "SpaceUVEditor", NULL); RNA_def_struct_sdna(srna, "SpaceImage"); RNA_def_struct_nested(brna, srna, "SpaceImageEditor"); @@ -3583,10 +3590,9 @@ static void rna_def_space_image_uv(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Grid Over Image", "Show the grid over the image"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); - prop = RNA_def_property(srna, "use_custom_grid", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_CUSTOM_GRID); - RNA_def_property_boolean_default(prop, true); - RNA_def_property_ui_text(prop, "Custom Grid", "Use a grid with a user-defined number of steps"); + prop = RNA_def_property(srna, "grid_shape_source", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, grid_shape_source_items); + RNA_def_property_ui_text(prop, "Grid Shape Source", "Specify source for the grid shape"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); prop = RNA_def_property(srna, "custom_grid_subdivisions", PROP_INT, PROP_XYZ); @@ -4087,6 +4093,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) prop = RNA_def_property(srna, "background_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, background_type_items); RNA_def_property_ui_text(prop, "Background", "Way to display the background"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_EDITOR_VIEW3D); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL); prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR); @@ -5265,6 +5272,7 @@ static void rna_def_space_properties(BlenderRNA *brna) RNA_def_property_enum_funcs( prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf"); RNA_def_property_ui_text(prop, "", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); RNA_def_property_update( prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update"); @@ -6562,6 +6570,7 @@ static void rna_def_fileselect_entry(BlenderRNA *brna) prop, "Data-block Type", "The type of the data-block, if the file represents one ('NONE' otherwise)"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); prop = RNA_def_property(srna, "local_id", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ID"); @@ -7314,12 +7323,14 @@ static void rna_def_space_node(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "texfrom"); RNA_def_property_enum_items(prop, texture_id_type_items); RNA_def_property_ui_text(prop, "Texture Type", "Type of data to take texture from"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL); prop = RNA_def_property(srna, "shader_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "shaderfrom"); RNA_def_property_enum_items(prop, shader_type_items); RNA_def_property_ui_text(prop, "Shader Type", "Type of data to take shader from"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL); prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE); @@ -7515,6 +7526,7 @@ static void rna_def_space_clip(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, rna_enum_clip_editor_mode_items); RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, "rna_SpaceClipEditor_clip_mode_update"); /* view */ diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 26849bfa622..2254db4edaf 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -24,6 +24,8 @@ #include "BKE_node_tree_update.h" #include "BKE_paint.h" +#include "BLT_translation.h" + #include "RNA_define.h" #include "RNA_enum_types.h" @@ -1191,6 +1193,7 @@ static void rna_def_texture_image(BlenderRNA *brna) RNA_def_property_enum_items(prop, prop_image_extension); RNA_def_property_ui_text( prop, "Extension", "How the image is extrapolated past its original bounds"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_IMAGE); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop = RNA_def_property(srna, "repeat_x", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index c9e3822c996..e22ae205b0a 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -4057,6 +4057,7 @@ static void rna_def_userdef_studiolights(BlenderRNA *brna) STUDIOLIGHT_TYPE_WORLD, "Type", "The type for the new studio light"); + RNA_def_property_translation_context(parm, BLT_I18NCONTEXT_ID_LIGHT); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "Newly created StudioLight"); RNA_def_function_return(func, parm); @@ -4117,6 +4118,7 @@ static void rna_def_userdef_studiolight(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_type_get", NULL, NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LIGHT); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs( @@ -5230,6 +5232,12 @@ static void rna_def_userdef_edit(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Duplicate Volume", "Causes volume data to be duplicated with the object"); + prop = RNA_def_property(srna, "use_duplicate_node_tree", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_NTREE); + RNA_def_property_ui_text(prop, + "Duplicate Node Tree", + "Make copies of node groups when duplicating nodes in the node editor"); + /* Currently only used for insert offset (aka auto-offset), * maybe also be useful for later stuff though. */ prop = RNA_def_property(srna, "node_margin", PROP_INT, PROP_PIXEL); @@ -5742,8 +5750,8 @@ static void rna_def_userdef_input(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_NO_MULTITOUCH_GESTURES); RNA_def_property_ui_text( prop, - "Multitouch Gestures", - "Use multitouch gestures for navigation with touchpad, instead of scroll wheel emulation"); + "Multi-touch Gestures", + "Use multi-touch gestures for navigation with touchpad, instead of scroll wheel emulation"); RNA_def_property_update(prop, 0, "rna_userdef_input_devices"); prop = RNA_def_property(srna, "invert_mouse_zoom", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 7fd590005fd..5b5544120a1 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1644,12 +1644,7 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, return NULL; } - if (strlen(identifier) >= sizeof(dummyop.idname)) { - BKE_reportf(reports, - RPT_ERROR, - "Registering operator class: '%s' is too long, maximum length is %d", - identifier, - (int)sizeof(dummyop.idname)); + if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) { return NULL; } @@ -1661,10 +1656,6 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, } } - if (!WM_operator_py_idname_ok_or_report(reports, identifier, dummyot.idname)) { - return NULL; - } - char idname_conv[sizeof(dummyop.idname)]; WM_operator_bl_idname(idname_conv, dummyot.idname); /* convert the idname from python */ @@ -1867,8 +1858,9 @@ static void rna_def_operator_common(StructRNA *srna) /* Registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->idname"); - /* Without setting the length the pointer size would be used. -3 because `.` -> `_OT_`. */ - RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME - 3); + /* String stored here is the 'BL' identifier (`OPMODULE_OT_my_op`), + * not the 'python' identifier (`opmodule.my_op`). */ + RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_idname_set"); // RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_REGISTER); diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 1a4942fcaf1..30be1d33653 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -23,6 +23,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_screen.h" @@ -494,7 +495,7 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, verts_num, false); } - if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { + if (mesh && BKE_mesh_wrapper_type(mesh) == ME_WRAPPER_TYPE_MDATA) { BLI_assert(mesh->totvert == verts_num); } diff --git a/source/blender/modifiers/intern/MOD_datatransfer.cc b/source/blender/modifiers/intern/MOD_datatransfer.cc index 4b6170598dd..25e8eb8fa20 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.cc +++ b/source/blender/modifiers/intern/MOD_datatransfer.cc @@ -213,7 +213,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * dtmd->defgrp_name, invert_vgroup, &reports)) { - result->runtime.is_original_bmesh = false; + result->runtime->is_original_bmesh = false; } if (BKE_reports_contain(&reports, RPT_ERROR)) { diff --git a/source/blender/modifiers/intern/MOD_multires.cc b/source/blender/modifiers/intern/MOD_multires.cc index e4c90eb237b..2bc3763c46b 100644 --- a/source/blender/modifiers/intern/MOD_multires.cc +++ b/source/blender/modifiers/intern/MOD_multires.cc @@ -230,7 +230,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * if ((ctx->object->mode & OB_MODE_SCULPT) && !for_orco && !for_render && !sculpt_base_mesh) { /* NOTE: CCG takes ownership over Subdiv. */ result = multires_as_ccg(mmd, ctx, mesh, subdiv); - result->runtime.subdiv_ccg_tot_level = mmd->totlvl; + result->runtime->subdiv_ccg_tot_level = mmd->totlvl; /* TODO(sergey): Usually it is sculpt stroke's update variants which * takes care of this, but is possible that we need this before the * stroke: i.e. when exiting blender right after stroke is done. @@ -238,7 +238,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * * surely there is a better way of solving this. */ if (ctx->object->sculpt != nullptr) { SculptSession *sculpt_session = ctx->object->sculpt; - sculpt_session->subdiv_ccg = result->runtime.subdiv_ccg; + sculpt_session->subdiv_ccg = result->runtime->subdiv_ccg; sculpt_session->multires.active = true; sculpt_session->multires.modifier = mmd; sculpt_session->multires.level = mmd->sculptlvl; @@ -343,7 +343,7 @@ static void panel_draw(const bContext *C, Panel *panel) modifier_panel_end(layout, ptr); } -static void subdivisions_panel_draw(const bContext *UNUSED(C), Panel *panel) +static void subdivisions_panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *row; uiLayout *layout = panel->layout; @@ -406,7 +406,7 @@ static void subdivisions_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemO(layout, IFACE_("Delete Higher"), ICON_NONE, "OBJECT_OT_multires_higher_levels_delete"); } -static void shape_panel_draw(const bContext *UNUSED(C), Panel *panel) +static void shape_panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *row; uiLayout *layout = panel->layout; @@ -421,7 +421,7 @@ static void shape_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemO(row, IFACE_("Apply Base"), ICON_NONE, "OBJECT_OT_multires_base_apply"); } -static void generate_panel_draw(const bContext *UNUSED(C), Panel *panel) +static void generate_panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *col, *row; uiLayout *layout = panel->layout; @@ -449,7 +449,7 @@ static void generate_panel_draw(const bContext *UNUSED(C), Panel *panel) } } -static void advanced_panel_draw(const bContext *UNUSED(C), Panel *panel) +static void advanced_panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *col; uiLayout *layout = panel->layout; diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index 6f86bf1d8cb..43ded18fcc4 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -623,7 +623,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, MEM_SAFE_FREE(loopnors); - result->runtime.is_original_bmesh = false; + result->runtime->is_original_bmesh = false; return result; } diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc index b957bd26ca6..66291520176 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.cc +++ b/source/blender/modifiers/intern/MOD_particlesystem.cc @@ -159,7 +159,7 @@ static void deformVerts(ModifierData *md, BKE_mesh_tessface_ensure(psmd->mesh_final); - if (!psmd->mesh_final->runtime.deformed_only) { + if (!psmd->mesh_final->runtime->deformed_only) { /* Get the original mesh from the object, this is what the particles * are attached to so in case of non-deform modifiers we need to remap * them to the final mesh (typically subdivision surfaces). */ diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index 4241ca5a591..d6241fcb290 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -67,10 +67,9 @@ static void init_dualcon_mesh(DualConInput *input, Mesh *mesh) input->mloop = (void *)BKE_mesh_loops(mesh); input->loop_stride = sizeof(MLoop); - BKE_mesh_runtime_looptri_ensure(mesh); - input->looptri = (void *)mesh->runtime.looptris.array; + input->looptri = (void *)BKE_mesh_runtime_looptri_ensure(mesh); input->tri_stride = sizeof(MLoopTri); - input->tottri = mesh->runtime.looptris.len; + input->tottri = BKE_mesh_runtime_looptri_len(mesh); INIT_MINMAX(input->min, input->max); BKE_mesh_minmax(mesh, input->min, input->max); diff --git a/source/blender/modifiers/intern/MOD_subsurf.cc b/source/blender/modifiers/intern/MOD_subsurf.cc index 991bd0d876c..5e77f0ffa9e 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.cc +++ b/source/blender/modifiers/intern/MOD_subsurf.cc @@ -208,7 +208,7 @@ static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx, runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */ runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals); - mesh->runtime.subsurf_runtime_data = runtime_data; + mesh->runtime->subsurf_runtime_data = runtime_data; } /* Modifier itself. */ diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index 7d66f75b20f..589a3d28ad9 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -57,7 +57,7 @@ void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *c /* TODO: to be renamed to get_texture_coords once we are done with moving modifiers to Mesh. */ void MOD_get_texture_coords(MappingInfoModifierData *dmd, - const ModifierEvalContext *UNUSED(ctx), + const ModifierEvalContext * /*ctx*/, Object *ob, Mesh *mesh, float (*cos)[3], @@ -188,7 +188,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, &mesh_prior_modifiers->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_CD_REFERENCE)); - mesh->runtime.deformed_only = 1; + mesh->runtime->deformed_only = 1; } if (em != nullptr) { @@ -218,7 +218,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, } } - if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { + if (mesh && mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) { BLI_assert(mesh->totvert == verts_num); } diff --git a/source/blender/modifiers/intern/MOD_uvproject.cc b/source/blender/modifiers/intern/MOD_uvproject.cc index 248b7b48a7c..c07b2059b5b 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.cc +++ b/source/blender/modifiers/intern/MOD_uvproject.cc @@ -52,7 +52,7 @@ static void initData(ModifierData *md) MEMCPY_STRUCT_AFTER(umd, DNA_struct_default_get(UVProjectModifierData), modifier); } -static void requiredDataMask(ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks) { /* ask for UV coordinates */ r_cddata_masks->lmask |= CD_MASK_MLOOPUV; @@ -90,7 +90,7 @@ struct Projector { }; static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, - const ModifierEvalContext *UNUSED(ctx), + const ModifierEvalContext * /*ctx*/, Object *ob, Mesh *mesh) { @@ -283,7 +283,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, } } - mesh->runtime.is_original_bmesh = false; + mesh->runtime->is_original_bmesh = false; return mesh; } @@ -298,7 +298,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * return result; } -static void panel_draw(const bContext *UNUSED(C), Panel *panel) +static void panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *sub; uiLayout *layout = panel->layout; diff --git a/source/blender/modifiers/intern/MOD_uvwarp.cc b/source/blender/modifiers/intern/MOD_uvwarp.cc index 85fd8946d0b..4ec273bcbc6 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.cc +++ b/source/blender/modifiers/intern/MOD_uvwarp.cc @@ -93,7 +93,7 @@ struct UVWarpData { static void uv_warp_compute(void *__restrict userdata, const int i, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict /*tls*/) { const UVWarpData *data = static_cast<const UVWarpData *>(userdata); @@ -216,7 +216,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * settings.use_threading = (polys_num > 1000); BLI_task_parallel_range(0, polys_num, &data, uv_warp_compute, &settings); - mesh->runtime.is_original_bmesh = false; + mesh->runtime->is_original_bmesh = false; return mesh; } @@ -241,7 +241,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_depends_on_transform_relation(ctx->node, "UVWarp Modifier"); } -static void panel_draw(const bContext *UNUSED(C), Panel *panel) +static void panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *col; uiLayout *layout = panel->layout; @@ -283,7 +283,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) modifier_panel_end(layout, ptr); } -static void transform_panel_draw(const bContext *UNUSED(C), Panel *panel) +static void transform_panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *layout = panel->layout; diff --git a/source/blender/modifiers/intern/MOD_wave.cc b/source/blender/modifiers/intern/MOD_wave.cc index 962bb60c8ad..647e0324707 100644 --- a/source/blender/modifiers/intern/MOD_wave.cc +++ b/source/blender/modifiers/intern/MOD_wave.cc @@ -21,6 +21,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_mesh.h" @@ -337,7 +338,7 @@ static void deformVertsEM(ModifierData *md, if (!ELEM(mesh_src, nullptr, mesh)) { /* Important not to free `vertexCos` owned by the caller. */ - EditMeshData *edit_data = mesh_src->runtime.edit_data; + EditMeshData *edit_data = mesh_src->runtime->edit_data; if (edit_data->vertexCos == vertexCos) { edit_data->vertexCos = nullptr; } diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index e7b1cb45234..1ebd5423d39 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -676,7 +676,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_SAFE_FREE(wn_data.mode_pair); MEM_SAFE_FREE(wn_data.items_data); - result->runtime.is_original_bmesh = false; + result->runtime->is_original_bmesh = false; return result; } @@ -705,12 +705,12 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma } } -static bool dependsOnNormals(ModifierData *UNUSED(md)) +static bool dependsOnNormals(ModifierData * /*md*/) { return true; } -static void panel_draw(const bContext *UNUSED(C), Panel *panel) +static void panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *col; uiLayout *layout = panel->layout; diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.cc b/source/blender/modifiers/intern/MOD_weightvgedit.cc index bcfd47491d5..e4fbca633f7 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.cc +++ b/source/blender/modifiers/intern/MOD_weightvgedit.cc @@ -96,7 +96,7 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } -static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *md) +static bool dependsOnTime(Scene * /*scene*/, ModifierData *md) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; @@ -142,7 +142,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } } -static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const Scene * /*scene*/, ModifierData *md, bool /*useRenderParams*/) { WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; /* If no vertex group, bypass. */ @@ -278,13 +278,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_freeN(new_w); MEM_freeN(dw); - mesh->runtime.is_original_bmesh = false; + mesh->runtime->is_original_bmesh = false; /* Return the vgroup-modified mesh. */ return mesh; } -static void panel_draw(const bContext *UNUSED(C), Panel *panel) +static void panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *sub, *col, *row; uiLayout *layout = panel->layout; @@ -326,7 +326,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) modifier_panel_end(layout, ptr); } -static void falloff_panel_draw(const bContext *UNUSED(C), Panel *panel) +static void falloff_panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *row, *sub; uiLayout *layout = panel->layout; @@ -366,7 +366,7 @@ static void panelRegister(ARegionType *region_type) region_type, "influence", "Influence", nullptr, influence_panel_draw, panel_type); } -static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md) +static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md) { const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md; diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.cc b/source/blender/modifiers/intern/MOD_weightvgmix.cc index 720f9fac948..d860e93d535 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.cc +++ b/source/blender/modifiers/intern/MOD_weightvgmix.cc @@ -144,7 +144,7 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } -static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *md) +static bool dependsOnTime(Scene * /*scene*/, ModifierData *md) { WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; @@ -190,7 +190,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } } -static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const Scene * /*scene*/, ModifierData *md, bool /*useRenderParams*/) { WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md; /* If no vertex group, bypass. */ @@ -438,13 +438,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * MEM_freeN(dw2); MEM_SAFE_FREE(indices); - mesh->runtime.is_original_bmesh = false; + mesh->runtime->is_original_bmesh = false; /* Return the vgroup-modified mesh. */ return mesh; } -static void panel_draw(const bContext *UNUSED(C), Panel *panel) +static void panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *layout = panel->layout; diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.cc b/source/blender/modifiers/intern/MOD_weightvgproximity.cc index faee2b9e6d5..93052f4215d 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.cc +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.cc @@ -345,7 +345,7 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma /* No need to ask for CD_PREVIEW_MLOOPCOL... */ } -static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *md) +static bool dependsOnTime(Scene * /*scene*/, ModifierData *md) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; @@ -403,7 +403,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } } -static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) +static bool isDisabled(const Scene * /*scene*/, ModifierData *md, bool /*useRenderParams*/) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; /* If no vertex group, bypass. */ @@ -639,13 +639,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * TIMEIT_END(perf); #endif - mesh->runtime.is_original_bmesh = false; + mesh->runtime->is_original_bmesh = false; /* Return the vgroup-modified mesh. */ return mesh; } -static void panel_draw(const bContext *UNUSED(C), Panel *panel) +static void panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *col; uiLayout *layout = panel->layout; @@ -673,7 +673,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "normalize", 0, nullptr, ICON_NONE); } -static void falloff_panel_draw(const bContext *UNUSED(C), Panel *panel) +static void falloff_panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *row, *sub; uiLayout *layout = panel->layout; @@ -714,7 +714,7 @@ static void panelRegister(ARegionType *region_type) region_type, "influence", "Influence", nullptr, influence_panel_draw, panel_type); } -static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md) +static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md) { const WeightVGProximityModifierData *wmd = (const WeightVGProximityModifierData *)md; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 422ee747649..2398aefc67a 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -50,7 +50,7 @@ set(SRC intern/node_multi_function.cc intern/node_socket.cc intern/node_socket_declarations.cc - intern/node_util.c + intern/node_util.cc intern/socket_search_link.cc NOD_common.h diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index d1504060665..9671f8148ec 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -369,7 +369,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_ DefNode(GeometryNode, GEO_NODE_MESH_TO_VOLUME, def_geo_mesh_to_volume, "MESH_TO_VOLUME", MeshToVolume, "Mesh to Volume", "Create a fog volume with the shape of the input mesh's surface") DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE, 0, "CORNERS_OF_FACE", CornersOfFace, "Corners of Face", "Retrieve corners that make up a face") DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_VERTEX, 0, "CORNERS_OF_VERTEX", CornersOfVertex, "Corners of Vertex", "Retrieve face corners connected to vertices") -DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER, 0, "EDGES_OF_CORNER", EdgesOfCorner, "Edges of Corner", "Retrieve the edges on boths sides of a face corner") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER, 0, "EDGES_OF_CORNER", EdgesOfCorner, "Edges of Corner", "Retrieve the edges on both sides of a face corner") DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_VERTEX, 0, "EDGES_OF_VERTEX", EdgesOfVertex, "Edges of Vertex", "Retrieve the edges connected to each vertex") DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_FACE_OF_CORNER, 0, "FACE_OF_CORNER", FaceOfCorner, "Face of Corner", "Retrieve the face each face corner is part of") DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_OFFSET_CORNER_IN_FACE, 0, "OFFSET_CORNER_IN_FACE", OffsetCornerInFace, "Offset Corner in Face", "Retrieve corners in the same face as another") diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt index 2537e8e93cc..4255a2dde21 100644 --- a/source/blender/nodes/composite/CMakeLists.txt +++ b/source/blender/nodes/composite/CMakeLists.txt @@ -18,6 +18,7 @@ set(INC ../../render ../../windowmanager ../../compositor/realtime_compositor + ../../compositor/realtime_compositor/algorithms ../../../../intern/guardedalloc # dna_type_offsets.h diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc index 731c559dfdc..a581d87a463 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc @@ -70,10 +70,20 @@ class BokehBlurOperation : public NodeOperation { return; } + if (get_input("Size").is_single_value() || !get_variable_size()) { + execute_constant_size(); + } + else { + execute_variable_size(); + } + } + + void execute_constant_size() + { GPUShader *shader = shader_manager().get("compositor_blur"); GPU_shader_bind(shader); - GPU_shader_uniform_1i(shader, "radius", compute_blur_radius()); + GPU_shader_uniform_1i(shader, "radius", int(compute_blur_radius())); GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds()); const Result &input_image = get_input("Image"); @@ -88,7 +98,7 @@ class BokehBlurOperation : public NodeOperation { Domain domain = compute_domain(); if (get_extend_bounds()) { /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */ - domain.size += int2(compute_blur_radius() * 2); + domain.size += int2(int(compute_blur_radius()) * 2); } Result &output_image = get_result("Image"); @@ -104,7 +114,42 @@ class BokehBlurOperation : public NodeOperation { input_mask.unbind_as_texture(); } - int compute_blur_radius() + void execute_variable_size() + { + GPUShader *shader = shader_manager().get("compositor_blur_variable_size"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "base_size", compute_blur_radius()); + GPU_shader_uniform_1i(shader, "search_radius", get_max_size()); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Result &input_weights = get_input("Bokeh"); + input_weights.bind_as_texture(shader, "weights_tx"); + + const Result &input_size = get_input("Size"); + input_size.bind_as_texture(shader, "size_tx"); + + const Result &input_mask = get_input("Bounding box"); + input_mask.bind_as_texture(shader, "mask_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + input_weights.unbind_as_texture(); + input_size.unbind_as_texture(); + input_mask.unbind_as_texture(); + } + + float compute_blur_radius() { const int2 image_size = get_input("Image").domain().size; const int max_size = math::max(image_size.x, image_size.y); @@ -124,7 +169,7 @@ class BokehBlurOperation : public NodeOperation { return true; } - if (compute_blur_radius() == 0) { + if (compute_blur_radius() == 0.0f) { return true; } @@ -142,6 +187,16 @@ class BokehBlurOperation : public NodeOperation { { return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS; } + + bool get_variable_size() + { + return bnode().custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE; + } + + int get_max_size() + { + return static_cast<int>(bnode().custom4); + } }; static NodeOperation *get_compositor_operation(Context &context, DNode node) diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc index 23a9385c4fc..fa3b14ae015 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc @@ -415,7 +415,8 @@ void register_node_type_cmp_cryptomatte_legacy() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE); + cmp_node_type_base( + &ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte (Legacy)", NODE_CLASS_MATTE); node_type_socket_templates(&ntype, nullptr, file_ns::cmp_node_cryptomatte_out); node_type_init(&ntype, legacy_file_ns::node_init_cryptomatte_legacy); node_type_storage( diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc index a4fe1f33813..4c901372b9f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_levels.cc +++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc @@ -5,9 +5,18 @@ * \ingroup cmpnodes */ +#include <cmath> + +#include "BLI_assert.h" +#include "BLI_math_vec_types.hh" +#include "BLI_math_vector.hh" + #include "UI_interface.h" #include "UI_resources.h" +#include "IMB_colormanagement.h" + +#include "COM_algorithm_parallel_reduction.hh" #include "COM_node_operation.hh" #include "node_composite_util.hh" @@ -18,7 +27,9 @@ namespace blender::nodes::node_composite_levels_cc { static void cmp_node_levels_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({0.0f, 0.0f, 0.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({0.0f, 0.0f, 0.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Float>(N_("Mean")); b.add_output<decl::Float>(N_("Std Dev")); } @@ -36,13 +47,140 @@ static void node_composit_buts_view_levels(uiLayout *layout, bContext * /*C*/, P using namespace blender::realtime_compositor; class LevelsOperation : public NodeOperation { + private: + constexpr static float luminance_coefficients_bt709_[3] = {0.2126f, 0.7152f, 0.0722f}; + public: using NodeOperation::NodeOperation; void execute() override { - get_result("Mean").allocate_invalid(); - get_result("Std Dev").allocate_invalid(); + if (get_input("Image").is_single_value()) { + execute_single_value(); + return; + } + + const float mean = compute_mean(); + + Result &mean_result = get_result("Mean"); + if (mean_result.should_compute()) { + mean_result.allocate_single_value(); + mean_result.set_float_value(mean); + } + + Result &standard_deviation_result = get_result("Std Dev"); + if (standard_deviation_result.should_compute()) { + const float standard_deviation = compute_standard_deviation(mean); + standard_deviation_result.allocate_single_value(); + standard_deviation_result.set_float_value(standard_deviation); + } + } + + void execute_single_value() + { + Result &standard_deviation_result = get_result("Std Dev"); + if (standard_deviation_result.should_compute()) { + standard_deviation_result.allocate_single_value(); + standard_deviation_result.set_float_value(0.0f); + } + + Result &mean_result = get_result("Mean"); + if (!mean_result.should_compute()) { + return; + } + + mean_result.allocate_single_value(); + const float3 input = float3(get_input("Image").get_color_value()); + + switch (get_channel()) { + case CMP_NODE_LEVLES_RED: + mean_result.set_float_value(input.x); + break; + case CMP_NODE_LEVLES_GREEN: + mean_result.set_float_value(input.y); + break; + case CMP_NODE_LEVLES_BLUE: + mean_result.set_float_value(input.z); + break; + case CMP_NODE_LEVLES_LUMINANCE_BT709: + mean_result.set_float_value(math::dot(input, float3(luminance_coefficients_bt709_))); + break; + case CMP_NODE_LEVLES_LUMINANCE: { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + mean_result.set_float_value(math::dot(input, float3(luminance_coefficients))); + break; + } + default: + BLI_assert_unreachable(); + break; + } + } + + float compute_mean() + { + const Result &input = get_input("Image"); + return compute_sum() / (input.domain().size.x * input.domain().size.y); + } + + float compute_sum() + { + const Result &input = get_input("Image"); + switch (get_channel()) { + case CMP_NODE_LEVLES_RED: + return sum_red(context(), input.texture()); + case CMP_NODE_LEVLES_GREEN: + return sum_green(context(), input.texture()); + case CMP_NODE_LEVLES_BLUE: + return sum_blue(context(), input.texture()); + case CMP_NODE_LEVLES_LUMINANCE_BT709: + return sum_luminance(context(), input.texture(), float3(luminance_coefficients_bt709_)); + case CMP_NODE_LEVLES_LUMINANCE: { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + return sum_luminance(context(), input.texture(), float3(luminance_coefficients)); + } + default: + BLI_assert_unreachable(); + return 0.0f; + } + } + + float compute_standard_deviation(float mean) + { + const Result &input = get_input("Image"); + const float sum = compute_sum_squared_difference(mean); + return std::sqrt(sum / (input.domain().size.x * input.domain().size.y)); + } + + float compute_sum_squared_difference(float subtrahend) + { + const Result &input = get_input("Image"); + switch (get_channel()) { + case CMP_NODE_LEVLES_RED: + return sum_red_squared_difference(context(), input.texture(), subtrahend); + case CMP_NODE_LEVLES_GREEN: + return sum_green_squared_difference(context(), input.texture(), subtrahend); + case CMP_NODE_LEVLES_BLUE: + return sum_blue_squared_difference(context(), input.texture(), subtrahend); + case CMP_NODE_LEVLES_LUMINANCE_BT709: + return sum_luminance_squared_difference( + context(), input.texture(), float3(luminance_coefficients_bt709_), subtrahend); + case CMP_NODE_LEVLES_LUMINANCE: { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + return sum_luminance_squared_difference( + context(), input.texture(), float3(luminance_coefficients), subtrahend); + } + default: + BLI_assert_unreachable(); + return 0.0f; + } + } + + CMPNodeLevelsChannel get_channel() + { + return static_cast<CMPNodeLevelsChannel>(bnode().custom1); } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc index c4e42f8247d..c65bb7bb747 100644 --- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc @@ -36,7 +36,10 @@ class PixelateOperation : public NodeOperation { * matches its apparent size, that is, its size after the domain transformation. The pixelate * node has no effect if the input is scaled-up. See the compute_domain method for more * information. */ - get_input("Color").pass_through(get_result("Color")); + Result &result = get_result("Color"); + get_input("Color").pass_through(result); + + result.get_realization_options().interpolation = Interpolation::Nearest; } /* Compute a smaller-sized domain that matches the apparent size of the input while having a unit diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc index b9f1f2da6a8..c524d7b8da9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scale.cc +++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc @@ -88,7 +88,6 @@ class ScaleOperation : public NodeOperation { get_translation(), 0.0f, get_scale()); result.transform(transformation); - result.get_realization_options().interpolation = Interpolation::Bilinear; } float2 get_scale() diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc index b655c0db106..3483285793a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc @@ -54,7 +54,8 @@ void register_node_type_cmp_sephsva() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_sephsva_declare; ntype.gather_link_search_ops = nullptr; ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; @@ -107,7 +108,8 @@ void register_node_type_cmp_combhsva() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_combhsva_declare; ntype.gather_link_search_ops = nullptr; ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc index 1f4c9fd153f..9308052454d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc @@ -54,7 +54,8 @@ void register_node_type_cmp_seprgba() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_seprgba_declare; ntype.gather_link_search_ops = nullptr; ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; @@ -107,7 +108,8 @@ void register_node_type_cmp_combrgba() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_combrgba_declare; ntype.gather_link_search_ops = nullptr; ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc index 78be1efbd8e..82fc37a18f6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc @@ -81,7 +81,8 @@ void register_node_type_cmp_sepycca() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA_LEGACY, "Separate YCbCrA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_SEPYCCA_LEGACY, "Separate YCbCrA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_sepycca_declare; node_type_init(&ntype, file_ns::node_composit_init_mode_sepycca); ntype.gather_link_search_ops = nullptr; @@ -168,7 +169,8 @@ void register_node_type_cmp_combycca() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA_LEGACY, "Combine YCbCrA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_COMBYCCA_LEGACY, "Combine YCbCrA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_combycca_declare; node_type_init(&ntype, file_ns::node_composit_init_mode_combycca); ntype.gather_link_search_ops = nullptr; diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc index 1f0eb04cfc3..b12e70ad9b8 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc @@ -54,7 +54,8 @@ void register_node_type_cmp_sepyuva() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_sepyuva_declare; ntype.gather_link_search_ops = nullptr; ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; @@ -107,7 +108,8 @@ void register_node_type_cmp_combyuva() static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA", NODE_CLASS_CONVERTER); + cmp_node_type_base( + &ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::cmp_node_combyuva_declare; ntype.gather_link_search_ops = nullptr; ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc index 149d44b2207..513ddd76055 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc @@ -113,7 +113,7 @@ class EdgePositionFieldInput final : public bke::MeshFieldInput { GVArray get_varray_for_context(const Mesh &mesh, const eAttrDomain domain, - IndexMask UNUSED(mask)) const final + IndexMask /*mask*/) const final { return construct_edge_positions_gvarray(mesh, vertex_, domain); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc index f45ff826a60..cce3f4e3648 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc @@ -60,8 +60,8 @@ class CornersOfVertInput final : public bke::MeshFieldInput { { const IndexRange vert_range(mesh.totvert); const Span<MLoop> loops = mesh.loops(); - Array<Vector<int>> vert_to_loop_map = mesh_topology::build_vert_to_loop_map(loops, - mesh.totvert); + Array<Vector<int>> vert_to_loop_map = bke::mesh_topology::build_vert_to_loop_map(loops, + mesh.totvert); const bke::MeshFieldContext context{mesh, domain}; fn::FieldEvaluator evaluator{context, &mask}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc index c46c64448bf..84b560cb48a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc @@ -77,13 +77,13 @@ class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput { } const Span<MPoly> polys = mesh.polys(); const Span<MLoop> loops = mesh.loops(); - Array<int> loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys, mesh.totloop); + Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop); return VArray<int>::ForFunc( mesh.totloop, [polys, loops, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) { const int poly_i = loop_to_poly_map[corner_i]; const MPoly &poly = polys[poly_i]; - const int corner_i_prev = mesh_topology::previous_poly_loop(poly, corner_i); + const int corner_i_prev = bke::mesh_topology::previous_poly_loop(poly, corner_i); return loops[corner_i_prev].e; }); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc index d099cd7f8cc..053ef61deed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc @@ -60,8 +60,8 @@ class EdgesOfVertInput final : public bke::MeshFieldInput { { const IndexRange vert_range(mesh.totvert); const Span<MEdge> edges = mesh.edges(); - Array<Vector<int>> vert_to_edge_map = mesh_topology::build_vert_to_edge_map(edges, - mesh.totvert); + Array<Vector<int>> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map(edges, + mesh.totvert); const bke::MeshFieldContext context{mesh, domain}; fn::FieldEvaluator evaluator{context, &mask}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc index 99def9e8bd1..d9f944ca11e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc @@ -36,7 +36,7 @@ class CornerFaceIndexInput final : public bke::MeshFieldInput { return {}; } return VArray<int>::ForContainer( - mesh_topology::build_loop_to_poly_map(mesh.polys(), mesh.totloop)); + bke::mesh_topology::build_loop_to_poly_map(mesh.polys(), mesh.totloop)); } uint64_t hash() const final @@ -65,7 +65,7 @@ class CornerIndexInFaceInput final : public bke::MeshFieldInput { return {}; } const Span<MPoly> polys = mesh.polys(); - Array<int> loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys, mesh.totloop); + Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop); return VArray<int>::ForFunc( mesh.totloop, [polys, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) { const int poly_i = loop_to_poly_map[corner_i]; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc index d7ea097be94..2cb9ae82fa1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc @@ -52,7 +52,7 @@ class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput { const VArray<int> corner_indices = evaluator.get_evaluated<int>(0); const VArray<int> offsets = evaluator.get_evaluated<int>(1); - Array<int> loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys, mesh.totloop); + Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys, mesh.totloop); Array<int> offset_corners(mask.min_array_size()); threading::parallel_for(mask.index_range(), 2048, [&](const IndexRange range) { diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.cc index ddab455509d..17be20b4e4b 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.cc @@ -37,7 +37,7 @@ void node_free_curves(bNode *node) { - BKE_curvemapping_free(node->storage); + BKE_curvemapping_free(static_cast<CurveMapping *>(node->storage)); } void node_free_standard_storage(bNode *node) @@ -49,7 +49,7 @@ void node_free_standard_storage(bNode *node) void node_copy_curves(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node) { - dest_node->storage = BKE_curvemapping_copy(src_node->storage); + dest_node->storage = BKE_curvemapping_copy(static_cast<CurveMapping *>(src_node->storage)); } void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), @@ -63,7 +63,7 @@ void *node_initexec_curves(bNodeExecContext *UNUSED(context), bNode *node, bNodeInstanceKey UNUSED(key)) { - BKE_curvemapping_init(node->storage); + BKE_curvemapping_init(static_cast<CurveMapping *>(node->storage)); return NULL; /* unused return */ } @@ -87,9 +87,9 @@ void node_sock_label_clear(bNodeSocket *sock) void node_math_update(bNodeTree *ntree, bNode *node) { - bNodeSocket *sock1 = BLI_findlink(&node->inputs, 0); - bNodeSocket *sock2 = BLI_findlink(&node->inputs, 1); - bNodeSocket *sock3 = BLI_findlink(&node->inputs, 2); + bNodeSocket *sock1 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 0)); + bNodeSocket *sock2 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1)); + bNodeSocket *sock3 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2)); nodeSetSocketAvailability(ntree, sock2, !ELEM(node->custom1, @@ -305,7 +305,9 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *to_socket) { - bNodeSocket *first = to_socket->in_out == SOCK_IN ? node->inputs.first : node->outputs.first; + bNodeSocket *first = to_socket->in_out == SOCK_IN ? + static_cast<bNodeSocket *>(node->inputs.first) : + static_cast<bNodeSocket *>((node->outputs.first)); /* Wrap around the list end. */ bNodeSocket *socket_iter = to_socket->next ? to_socket->next : first; diff --git a/source/blender/nodes/intern/socket_search_link.cc b/source/blender/nodes/intern/socket_search_link.cc index 0bd838ff002..b440952b503 100644 --- a/source/blender/nodes/intern/socket_search_link.cc +++ b/source/blender/nodes/intern/socket_search_link.cc @@ -125,64 +125,23 @@ void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, } } -static void search_link_ops_for_socket_templates(GatherLinkSearchOpParams ¶ms, - const bNodeSocketTemplate *templates, - const eNodeSocketInOut in_out) -{ - const bNodeType &node_type = params.node_type(); - const bNodeTreeType &node_tree_type = *params.node_tree().typeinfo; - - Set<StringRef> socket_names; - for (const bNodeSocketTemplate *socket_template = templates; socket_template->type != -1; - socket_template++) { - eNodeSocketDatatype from = (eNodeSocketDatatype)socket_template->type; - eNodeSocketDatatype to = (eNodeSocketDatatype)params.other_socket().type; - if (in_out == SOCK_IN) { - std::swap(from, to); - } - if (node_tree_type.validate_link && !node_tree_type.validate_link(from, to)) { - continue; - } - if (!socket_names.add(socket_template->name)) { - /* See comment in #search_link_ops_for_declarations. */ - continue; - } - - params.add_item( - socket_template->name, [socket_template, node_type, in_out](LinkSearchOpParams ¶ms) { - bNode &node = params.add_node(node_type); - bNodeSocket *new_node_socket = bke::node_find_enabled_socket( - node, in_out, socket_template->name); - if (new_node_socket != nullptr) { - /* Rely on the way #nodeAddLink switches in/out if necessary. */ - nodeAddLink(¶ms.node_tree, ¶ms.node, ¶ms.socket, &node, new_node_socket); - } - }); - } -} - void search_link_ops_for_basic_node(GatherLinkSearchOpParams ¶ms) { const bNodeType &node_type = params.node_type(); + if (!node_type.declare) { + return; + } - if (node_type.declare) { - if (node_type.declaration_is_dynamic) { - /* Dynamic declarations (whatever they end up being) aren't supported - * by this function, but still avoid a crash in release builds. */ - BLI_assert_unreachable(); - return; - } + if (node_type.declaration_is_dynamic) { + /* Dynamic declarations (whatever they end up being) aren't supported + * by this function, but still avoid a crash in release builds. */ + BLI_assert_unreachable(); + return; + } - const NodeDeclaration &declaration = *node_type.fixed_declaration; + const NodeDeclaration &declaration = *node_type.fixed_declaration; - search_link_ops_for_declarations(params, declaration.sockets(params.in_out())); - } - else if (node_type.inputs && params.in_out() == SOCK_IN) { - search_link_ops_for_socket_templates(params, node_type.inputs, SOCK_IN); - } - else if (node_type.outputs && params.in_out() == SOCK_OUT) { - search_link_ops_for_socket_templates(params, node_type.outputs, SOCK_OUT); - } + search_link_ops_for_declarations(params, declaration.sockets(params.in_out())); } } // namespace blender::nodes diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.cc b/source/blender/nodes/shader/nodes/node_shader_attribute.cc index 77cf6b163d0..4694599f064 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.cc +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc @@ -42,6 +42,16 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, if (is_varying) { cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name); + + if (STREQ(attr->name, "color")) { + GPU_link(mat, "node_attribute_color", cd_attr, &cd_attr); + } + else if (STREQ(attr->name, "temperature")) { + GPU_link(mat, "node_attribute_temperature", cd_attr, &cd_attr); + } + } + else if (attr->type == SHD_ATTRIBUTE_VIEW_LAYER) { + cd_attr = GPU_layer_attribute(mat, attr->name); } else { cd_attr = GPU_uniform_attribute(mat, @@ -52,13 +62,6 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, GPU_link(mat, "node_attribute_uniform", cd_attr, GPU_constant(&attr_hash), &cd_attr); } - if (STREQ(attr->name, "color")) { - GPU_link(mat, "node_attribute_color", cd_attr, &cd_attr); - } - else if (STREQ(attr->name, "temperature")) { - GPU_link(mat, "node_attribute_temperature", cd_attr, &cd_attr); - } - GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr); if (is_varying) { diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index 439f2002ebc..c4dbc3ce6f1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -12,7 +12,12 @@ namespace blender::nodes::node_shader_curves_cc { static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b) { b.is_function_node(); - b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR); + b.add_input<decl::Float>(N_("Fac")) + .no_muted_links() + .min(0.0f) + .max(1.0f) + .default_value(1.0f) + .subtype(PROP_FACTOR); b.add_input<decl::Vector>(N_("Vector")).min(-1.0f).max(1.0f); b.add_output<decl::Vector>(N_("Vector")); } @@ -127,7 +132,12 @@ namespace blender::nodes::node_shader_curves_cc { static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b) { b.is_function_node(); - b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR); + b.add_input<decl::Float>(N_("Fac")) + .no_muted_links() + .min(0.0f) + .max(1.0f) + .default_value(1.0f) + .subtype(PROP_FACTOR); b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); b.add_output<decl::Color>(N_("Color")); } @@ -270,6 +280,7 @@ static void sh_node_curve_float_declare(NodeDeclarationBuilder &b) { b.is_function_node(); b.add_input<decl::Float>(N_("Factor")) + .no_muted_links() .min(0.0f) .max(1.0f) .default_value(1.0f) diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc index 2efd57155b9..878648105d1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc @@ -123,6 +123,19 @@ static void sh_node_mix_update(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, sock_factor_vec, use_vector_factor); } +class SocketSearchOp { + public: + std::string socket_name; + int type = MA_RAMP_BLEND; + void operator()(LinkSearchOpParams ¶ms) + { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = SOCK_RGBA; + node_storage(node).blend_type = type; + params.update_and_connect_available_socket(node, socket_name); + } +}; + static void node_mix_gather_link_searches(GatherLinkSearchOpParams ¶ms) { const eNodeSocketDatatype sock_type = static_cast<eNodeSocketDatatype>( @@ -132,6 +145,17 @@ static void node_mix_gather_link_searches(GatherLinkSearchOpParams ¶ms) const eNodeSocketDatatype type = ELEM(sock_type, SOCK_BOOLEAN, SOCK_INT) ? SOCK_FLOAT : sock_type; + const int weight = ELEM(params.other_socket().type, SOCK_RGBA) ? 0 : -1; + const std::string socket_name = params.in_out() == SOCK_IN ? "A" : "Result"; + for (const EnumPropertyItem *item = rna_enum_ramp_blend_items; item->identifier != nullptr; + item++) { + if (item->name != nullptr && item->identifier[0] != '\0') { + params.add_item(CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, item->name), + SocketSearchOp{socket_name, item->value}, + weight); + } + } + if (params.in_out() == SOCK_OUT) { params.add_item(IFACE_("Result"), [type](LinkSearchOpParams ¶ms) { bNode &node = params.add_node("ShaderNodeMix"); diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index ef0374e4539..d1578b48c79 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -150,7 +150,7 @@ void register_node_type_sh_mix_rgb() static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB_LEGACY, "Mix", NODE_CLASS_OP_COLOR); + sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB_LEGACY, "Mix (Legacy)", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::sh_node_mix_rgb_declare; ntype.labelfunc = node_blend_label; node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb); diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc index 985342ac15d..b297ead1847 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc @@ -36,7 +36,7 @@ void register_node_type_sh_sephsv() static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SEPHSV_LEGACY, "Separate HSV", NODE_CLASS_CONVERTER); + sh_node_type_base(&ntype, SH_NODE_SEPHSV_LEGACY, "Separate HSV (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::node_declare_sephsv; node_type_gpu(&ntype, file_ns::gpu_shader_sephsv); ntype.gather_link_search_ops = nullptr; @@ -73,7 +73,7 @@ void register_node_type_sh_combhsv() static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_COMBHSV_LEGACY, "Combine HSV", NODE_CLASS_CONVERTER); + sh_node_type_base(&ntype, SH_NODE_COMBHSV_LEGACY, "Combine HSV (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::node_declare_combhsv; node_type_gpu(&ntype, file_ns::gpu_shader_combhsv); ntype.gather_link_search_ops = nullptr; diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc index 07586a54765..c298998cad5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc @@ -76,7 +76,8 @@ void register_node_type_sh_seprgb() static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB_LEGACY, "Separate RGB", NODE_CLASS_CONVERTER); + sh_fn_node_type_base( + &ntype, SH_NODE_SEPRGB_LEGACY, "Separate RGB (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::sh_node_seprgb_declare; node_type_gpu(&ntype, file_ns::gpu_shader_seprgb); ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function; @@ -120,7 +121,8 @@ void register_node_type_sh_combrgb() static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB_LEGACY, "Combine RGB", NODE_CLASS_CONVERTER); + sh_fn_node_type_base( + &ntype, SH_NODE_COMBRGB_LEGACY, "Combine RGB (Legacy)", NODE_CLASS_CONVERTER); ntype.declare = file_ns::sh_node_combrgb_declare; node_type_gpu(&ntype, file_ns::gpu_shader_combrgb); ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function; diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c index ef14062c72d..e36bc248ed1 100644 --- a/source/blender/nodes/texture/nodes/node_texture_compose.c +++ b/source/blender/nodes/texture/nodes/node_texture_compose.c @@ -42,7 +42,8 @@ void register_node_type_tex_compose(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_COMPOSE_LEGACY, "Combine RGBA", NODE_CLASS_OP_COLOR); + tex_node_type_base( + &ntype, TEX_NODE_COMPOSE_LEGACY, "Combine RGBA (Legacy)", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 77710d6df37..36d53d69eff 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -29,6 +29,8 @@ #include "GPU_state.h" +#include "WM_api.h" /* For #WM_ghost_backend */ + #include "bpy.h" #include "bpy_app.h" #include "bpy_capi_utils.h" @@ -536,6 +538,17 @@ static PyObject *bpy_rna_enum_items_static(PyObject *UNUSED(self)) return result; } +/* This is only exposed for (Unix/Linux), see: #GHOST_ISystem::getSystemBackend for details. */ +PyDoc_STRVAR(bpy_ghost_backend_doc, + ".. function:: _ghost_backend()\n" + "\n" + " :return: An identifier for the GHOST back-end.\n" + " :rtype: string\n"); +static PyObject *bpy_ghost_backend(PyObject *UNUSED(self)) +{ + return PyUnicode_FromString(WM_ghost_backend()); +} + static PyMethodDef bpy_methods[] = { {"script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc}, {"blend_paths", @@ -552,10 +565,6 @@ static PyMethodDef bpy_methods[] = { (PyCFunction)bpy_resource_path, METH_VARARGS | METH_KEYWORDS, bpy_resource_path_doc}, - {"_driver_secure_code_test", - (PyCFunction)bpy_driver_secure_code_test, - METH_VARARGS | METH_KEYWORDS, - bpy_driver_secure_code_test_doc}, {"escape_identifier", (PyCFunction)bpy_escape_identifier, METH_O, bpy_escape_identifier_doc}, {"unescape_identifier", (PyCFunction)bpy_unescape_identifier, @@ -566,6 +575,14 @@ static PyMethodDef bpy_methods[] = { (PyCFunction)bpy_rna_enum_items_static, METH_NOARGS, bpy_rna_enum_items_static_doc}, + + /* Private functions (not part of the public API and may be removed at any time). */ + {"_driver_secure_code_test", + (PyCFunction)bpy_driver_secure_code_test, + METH_VARARGS | METH_KEYWORDS, + bpy_driver_secure_code_test_doc}, + {"_ghost_backend", (PyCFunction)bpy_ghost_backend, METH_NOARGS, bpy_ghost_backend_doc}, + {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index 59719fb4590..8fd62f7ec34 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -590,7 +590,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low, me_highpoly[i] = highpoly[i].me; BKE_mesh_runtime_looptri_ensure(me_highpoly[i]); - if (me_highpoly[i]->runtime.looptris.len != 0) { + if (BKE_mesh_runtime_looptri_len(me_highpoly[i]) != 0) { /* Create a BVH-tree for each `highpoly` object. */ BKE_bvhtree_from_mesh_get(&treeData[i], me_highpoly[i], BVHTREE_FROM_LOOPTRI, 2); diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index a42ddb6b830..3366111ed33 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -290,8 +290,8 @@ class TextureMarginMap { void build_tables() { - loop_to_poly_map_ = blender::mesh_topology::build_loop_to_poly_map({mpoly_, totpoly_}, - totloop_); + loop_to_poly_map_ = blender::bke::mesh_topology::build_loop_to_poly_map({mpoly_, totpoly_}, + totloop_); loop_adjacency_map_.resize(totloop_, -1); diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp index cb6c963b7d2..97042f433c2 100644 --- a/source/blender/simulation/intern/hair_volume.cpp +++ b/source/blender/simulation/intern/hair_volume.cpp @@ -618,17 +618,17 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert, } void SIM_hair_volume_add_segment(HairGrid *grid, - const float UNUSED(x1[3]), - const float UNUSED(v1[3]), + const float /*x1*/[3], + const float /*v1*/[3], const float x2[3], const float v2[3], const float x3[3], const float v3[3], - const float UNUSED(x4[3]), - const float UNUSED(v4[3]), - const float UNUSED(dir1[3]), - const float UNUSED(dir2[3]), - const float UNUSED(dir3[3])) + const float /*x4*/[3], + const float /*v4*/[3], + const float /*dir1*/[3], + const float /*dir2*/[3], + const float /*dir3*/[3]) { /* XXX simplified test implementation using a series of discrete sample along the segment, * instead of finding the closest point for all affected grid vertices. */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 5b6f7939ab9..1f9de8040f6 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -119,6 +119,13 @@ void WM_init_splash(struct bContext *C); void WM_init_opengl(void); +/** + * Return an identifier for the underlying GHOST implementation. + * \warning Use of this function should be limited & never for compatibility checks. + * see: #GHOST_ISystem::getSystemBackend for details. + */ +const char *WM_ghost_backend(void); + void WM_check(struct bContext *C); void WM_reinit_gizmomap_all(struct Main *bmain); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 58791dbd00a..fa89e7a4caa 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -107,19 +107,32 @@ /** \name Operator API * \{ */ +#define OP_BL_SEP_STRING "_OT_" +#define OP_BL_SEP_LEN 4 + +#define OP_PY_SEP_CHAR '.' +#define OP_PY_SEP_LEN 1 + +/* Difference between python 'identifier' and BL/C code one ("." separator replaced by "_OT_"), + * and final `\0` char. */ +#define OP_MAX_PY_IDNAME (OP_MAX_TYPENAME - OP_BL_SEP_LEN + OP_PY_SEP_LEN - 1) + size_t WM_operator_py_idname(char *dst, const char *src) { - const char *sep = strstr(src, "_OT_"); + const char *sep = strstr(src, OP_BL_SEP_STRING); if (sep) { - int ofs = (sep - src); + const size_t sep_offset = (size_t)(sep - src); /* NOTE: we use ascii `tolower` instead of system `tolower`, because the * latter depends on the locale, and can lead to `idname` mismatch. */ - memcpy(dst, src, sizeof(char) * ofs); - BLI_str_tolower_ascii(dst, ofs); + memcpy(dst, src, sep_offset); + BLI_str_tolower_ascii(dst, sep_offset); - dst[ofs] = '.'; - return BLI_strncpy_rlen(dst + (ofs + 1), sep + 4, OP_MAX_TYPENAME - (ofs + 1)) + (ofs + 1); + dst[sep_offset] = OP_PY_SEP_CHAR; + return BLI_strncpy_rlen(dst + (sep_offset + OP_PY_SEP_LEN), + sep + OP_BL_SEP_LEN, + OP_MAX_TYPENAME - sep_offset - OP_PY_SEP_LEN) + + (sep_offset + OP_PY_SEP_LEN); } /* Should not happen but support just in case. */ return BLI_strncpy_rlen(dst, src, OP_MAX_TYPENAME); @@ -127,15 +140,19 @@ size_t WM_operator_py_idname(char *dst, const char *src) size_t WM_operator_bl_idname(char *dst, const char *src) { - const char *sep = strchr(src, '.'); - int from_len; - if (sep && (from_len = strlen(src)) < OP_MAX_TYPENAME - 3) { - const int ofs = (sep - src); - memcpy(dst, src, sizeof(char) * ofs); - BLI_str_toupper_ascii(dst, ofs); - memcpy(dst + ofs, "_OT_", 4); - memcpy(dst + (ofs + 4), sep + 1, (from_len - ofs)); - return (from_len - ofs) - 1; + const size_t from_len = (size_t)strlen(src); + + const char *sep = strchr(src, OP_PY_SEP_CHAR); + if (sep && (from_len <= OP_MAX_PY_IDNAME)) { + const size_t sep_offset = (size_t)(sep - src); + memcpy(dst, src, sep_offset); + BLI_str_toupper_ascii(dst, sep_offset); + + memcpy(dst + sep_offset, OP_BL_SEP_STRING, OP_BL_SEP_LEN); + BLI_strncpy(dst + sep_offset + OP_BL_SEP_LEN, + sep + OP_PY_SEP_LEN, + from_len - sep_offset - OP_PY_SEP_LEN + 1); + return from_len + OP_BL_SEP_LEN - OP_PY_SEP_LEN; } /* Should not happen but support just in case. */ return BLI_strncpy_rlen(dst, src, OP_MAX_TYPENAME); @@ -166,14 +183,14 @@ bool WM_operator_py_idname_ok_or_report(ReportList *reports, } } - if (i > (MAX_NAME - 3)) { + if (i > OP_MAX_PY_IDNAME) { BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', " "is too long, maximum length is %d", classname, idname, - MAX_NAME - 3); + OP_MAX_PY_IDNAME); return false; } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index a4f92da2774..b1b13390932 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -91,6 +91,9 @@ /* the global to talk to ghost */ static GHOST_SystemHandle g_system = NULL; +#if !(defined(WIN32) || defined(__APPLE__)) +static const char *g_system_backend_id = NULL; +#endif typedef enum eWinOverrideFlag { WIN_OVERRIDE_GEOM = (1 << 0), @@ -1552,6 +1555,9 @@ void wm_ghost_init(bContext *C) /* This will leak memory, it's preferable to crashing. */ exit(1); } +#if !(defined(WIN32) || defined(__APPLE__)) + g_system_backend_id = GHOST_SystemBackend(); +#endif GHOST_Debug debug = {0}; if (G.debug & G_DEBUG_GHOST) { @@ -1597,6 +1603,18 @@ void wm_ghost_exit(void) g_system = NULL; } +const char *WM_ghost_backend(void) +{ +#if !(defined(WIN32) || defined(__APPLE__)) + return g_system_backend_id ? g_system_backend_id : "NONE"; +#else + /* While this could be supported, at the moment it's only needed with GHOST X11/WAYLAND + * to check which was selected and the API call may be removed after that's no longer needed. + * Use dummy values to prevent this being used on other systems. */ + return g_system ? "DEFAULT" : "NONE"; +#endif +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index c016372e6b0..f67c4dde41d 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -66,7 +66,6 @@ static void sig_handle_fpe(int UNUSED(sig)) # endif /* Handling `Ctrl-C` event in the console. */ -# if !defined(WITH_HEADLESS) static void sig_handle_blender_esc(int sig) { G.is_break = true; /* forces render loop to read queue, not sure if its needed */ @@ -81,7 +80,6 @@ static void sig_handle_blender_esc(int sig) count++; } } -# endif static void sig_handle_crash_backtrace(FILE *fp) { diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index fe00cce2572..b3decc06161 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -630,6 +630,24 @@ add_blender_test( ) endif() +# SVG Import +if(True) + set(_svg_render_tests path) + + foreach(render_test ${_svg_render_tests}) + add_python_test( + io_curve_svg_${render_test} + ${CMAKE_CURRENT_LIST_DIR}/bl_io_curve_svg_test.py + -blender "${TEST_BLENDER_EXE}" + -testdir "${TEST_SRC_DIR}/io_tests/svg/${render_test}" + -idiff "${OPENIMAGEIO_IDIFF}" + -outdir "${TEST_OUT_DIR}/io_curve_svg" + ) + endforeach() + + unset(_svg_render_tests) +endif() + if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS) if(NOT OPENIMAGEIO_IDIFF) message(WARNING "Disabling render tests because OIIO idiff does not exist") diff --git a/tests/python/bl_io_curve_svg_test.py b/tests/python/bl_io_curve_svg_test.py new file mode 100644 index 00000000000..092dfa5497a --- /dev/null +++ b/tests/python/bl_io_curve_svg_test.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import os +import sys +from pathlib import Path + + +def get_arguments(filepath, output_filepath): + dirname = os.path.dirname(filepath) + basedir = os.path.dirname(dirname) + + args = [ + "--background", + "-noaudio", + "--factory-startup", + "--enable-autoexec", + "--debug-memory", + "--debug-exit-on-error", + filepath, + "-E", "CYCLES", + "-o", output_filepath, + "-F", "PNG", + "--python", os.path.join(basedir, "util", "import_svg.py"), + "-f", "1", + ] + + return args + + +def create_argparse(): + parser = argparse.ArgumentParser() + parser.add_argument("-blender", nargs="+") + parser.add_argument("-testdir", nargs=1) + parser.add_argument("-outdir", nargs=1) + parser.add_argument("-idiff", nargs=1) + return parser + + +def main(): + parser = create_argparse() + args = parser.parse_args() + + blender = args.blender[0] + test_dir = args.testdir[0] + idiff = args.idiff[0] + output_dir = args.outdir[0] + + from modules import render_report + report = render_report.Report('IO Curve SVG', output_dir, idiff) + report.set_pixelated(True) + print(test_dir) + + ok = report.run(test_dir, blender, get_arguments, batch=True) + + sys.exit(not ok) + + +if __name__ == "__main__": + main() diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 4f823f854bf..c7e12dd5b7c 100644 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -33,7 +33,7 @@ BLACKLIST_OPTIX = [ ] BLACKLIST_METAL = [ - # No MNEE for Metal currently + # MNEE only works on Metal with macOS >= 13 "underwater_caustics.blend", ] |