diff options
589 files changed, 12792 insertions, 11120 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 84dccae962b..6268f793062 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -281,7 +281,7 @@ option(WITH_ALEMBIC "Enable Alembic Support" ON) option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF) # Universal Scene Description support -option(WITH_USD "Enable Universal Scene Description (USD) Support" OFF) +option(WITH_USD "Enable Universal Scene Description (USD) Support" ON) # 3D format support # Disable opencollada when we don't have precompiled libs @@ -631,12 +631,6 @@ if(WITH_PYTHON_MODULE AND WITH_PYTHON_INSTALL) message(FATAL_ERROR "WITH_PYTHON_MODULE requires WITH_PYTHON_INSTALL to be OFF") endif() - -# may as well build python module without a UI -if(WITH_PYTHON_MODULE) - set(WITH_HEADLESS ON) -endif() - if(NOT WITH_PYTHON) set(WITH_CYCLES OFF) set(WITH_DRACO OFF) diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index 53d88b12129..dd90eb9adde 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -130,7 +130,6 @@ if(NOT WIN32 OR ENABLE_MINGW64) include(cmake/vpx.cmake) include(cmake/x264.cmake) include(cmake/xvidcore.cmake) - include(cmake/faad.cmake) include(cmake/ffmpeg.cmake) include(cmake/fftw.cmake) include(cmake/sndfile.cmake) diff --git a/build_files/build_environment/cmake/faad.cmake b/build_files/build_environment/cmake/faad.cmake deleted file mode 100644 index 15934cc1879..00000000000 --- a/build_files/build_environment/cmake/faad.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENSE BLOCK ***** - -set(FAAD_EXTRA_ARGS) - -if(WIN32) - set(FAAD_EXTRA_CONFIGURE "utils\\win32\\ac2ver.exe" "faad2" "configure.ac" > libfaad\\win32_ver.h) -else() - set(FAAD_EXTRA_CONFIGURE echo .) -endif() - -ExternalProject_Add(external_faad - URL ${FAAD_URI} - DOWNLOAD_DIR ${DOWNLOAD_DIR} - URL_HASH MD5=${FAAD_HASH} - PREFIX ${BUILD_DIR}/faad - CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/faad/src/external_faad/ && ${FAAD_EXTRA_CONFIGURE} && ${CONFIGURE_COMMAND} --disable-shared --enable-static --prefix=${LIBDIR}/faad - BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/faad/src/external_faad/ && make -j${MAKE_THREADS} - INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/faad/src/external_faad/ && make install - INSTALL_DIR ${LIBDIR}/faad -) - -if(MSVC) - set_target_properties(external_faad PROPERTIES FOLDER Mingw) -endif() diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake index 9ff52914f53..02e78c605af 100644 --- a/build_files/build_environment/cmake/ffmpeg.cmake +++ b/build_files/build_environment/cmake/ffmpeg.cmake @@ -127,7 +127,6 @@ endif() add_dependencies( external_ffmpeg external_zlib - external_faad external_openjpeg external_xvidcore external_x264 diff --git a/build_files/build_environment/cmake/fftw.cmake b/build_files/build_environment/cmake/fftw.cmake index 2d10cf6ad28..b359df2f47d 100644 --- a/build_files/build_environment/cmake/fftw.cmake +++ b/build_files/build_environment/cmake/fftw.cmake @@ -19,8 +19,12 @@ set(FFTW_EXTRA_ARGS) if(WIN32) - set(FFTW3_ENV set CFLAGS=-fno-stack-check -fno-stack-protector -mno-stack-arg-probe -fno-lto &&) set(FFTW3_PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/fftw3/src/external_fftw3 < ${PATCH_DIR}/fftw3.diff) + set(FFTW_EXTRA_ARGS --disable-static --enable-shared) + set(FFTW_INSTALL install-strip) +else() + set(FFTW_EXTRA_ARGS --enable-static) + set(FFTW_INSTALL install) endif() ExternalProject_Add(external_fftw3 @@ -28,10 +32,10 @@ ExternalProject_Add(external_fftw3 DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH MD5=${FFTW_HASH} PREFIX ${BUILD_DIR}/fftw3 - CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${FFTW3_ENV} cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && ${CONFIGURE_COMMAND} --enable-static --prefix=${mingw_LIBDIR}/fftw3 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && ${CONFIGURE_COMMAND} ${FFTW_EXTRA_ARGS} --prefix=${mingw_LIBDIR}/fftw3 PATCH_COMMAND ${FFTW3_PATCH_COMMAND} BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && make -j${MAKE_THREADS} - INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && make install + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3/ && make ${FFTW_INSTALL} INSTALL_DIR ${LIBDIR}/fftw3 ) @@ -39,7 +43,8 @@ if(MSVC) set_target_properties(external_fftw3 PROPERTIES FOLDER Mingw) if(BUILD_MODE STREQUAL Release) ExternalProject_Add_Step(external_fftw3 after_install - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3.a ${HARVEST_TARGET}/fftw3/lib/libfftw.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3.dll.a ${HARVEST_TARGET}/fftw3/lib/libfftw.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/bin/libfftw3-3.dll ${HARVEST_TARGET}/fftw3/lib/libfftw3-3.dll COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/include/fftw3.h ${HARVEST_TARGET}/fftw3/include/fftw3.h DEPENDEES install ) diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake index 4d27509890f..d05a06c9518 100644 --- a/build_files/build_environment/cmake/harvest.cmake +++ b/build_files/build_environment/cmake/harvest.cmake @@ -44,10 +44,6 @@ if(BUILD_MODE STREQUAL Release) # glew-> opengl ${CMAKE_COMMAND} -E copy ${LIBDIR}/glew/lib/libglew32.lib ${HARVEST_TARGET}/opengl/lib/glew.lib && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/glew/include/ ${HARVEST_TARGET}/opengl/include/ && - # sndfile - ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/lib/libsndfile.dll.a ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.lib && - ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/bin/libsndfile-1.dll ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.dll && - ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/include/sndfile.h ${HARVEST_TARGET}/sndfile/include/sndfile.h && # tiff ${CMAKE_COMMAND} -E copy ${LIBDIR}/tiff/lib/tiff.lib ${HARVEST_TARGET}/tiff/lib/libtiff.lib && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/tiff/include/ ${HARVEST_TARGET}/tiff/include/ && diff --git a/build_files/build_environment/cmake/openal.cmake b/build_files/build_environment/cmake/openal.cmake index 44f6cdf72a3..315f2e8ba7e 100644 --- a/build_files/build_environment/cmake/openal.cmake +++ b/build_files/build_environment/cmake/openal.cmake @@ -52,7 +52,6 @@ if(BUILD_MODE STREQUAL Release) PREFIX ${BUILD_DIR}/openal CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openal ${DEFAULT_CMAKE_FLAGS} ${OPENAL_EXTRA_ARGS} INSTALL_DIR ${LIBDIR}/openal - PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openal/src/external_openal < ${PATCH_DIR}/openal.diff ) if(WIN32) diff --git a/build_files/build_environment/cmake/opensubdiv.cmake b/build_files/build_environment/cmake/opensubdiv.cmake index 9ec849a219b..d183b9f02b7 100644 --- a/build_files/build_environment/cmake/opensubdiv.cmake +++ b/build_files/build_environment/cmake/opensubdiv.cmake @@ -67,7 +67,7 @@ endif() ExternalProject_Add(external_opensubdiv URL ${OPENSUBDIV_URI} DOWNLOAD_DIR ${DOWNLOAD_DIR} - URL_HASH MD5=${OPENSUBDIV_Hash} + URL_HASH MD5=${OPENSUBDIV_HASH} PREFIX ${BUILD_DIR}/opensubdiv CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opensubdiv -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${OPENSUBDIV_EXTRA_ARGS} INSTALL_DIR ${LIBDIR}/opensubdiv diff --git a/build_files/build_environment/cmake/sndfile.cmake b/build_files/build_environment/cmake/sndfile.cmake index bafd8fe2ac6..df9b14c8887 100644 --- a/build_files/build_environment/cmake/sndfile.cmake +++ b/build_files/build_environment/cmake/sndfile.cmake @@ -60,3 +60,14 @@ if(UNIX) external_flac ) endif() + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_sndfile after_install + COMMAND lib /def:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.def /machine:x64 /out:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/bin/libsndfile-1.dll ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.dll + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/include/sndfile.h ${HARVEST_TARGET}/sndfile/include/sndfile.h + + DEPENDEES install + ) +endif() diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index d1e729a29e5..70c4b0948b3 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -20,9 +20,9 @@ set(ZLIB_VERSION 1.2.11) set(ZLIB_URI https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz) set(ZLIB_HASH 1c9f62f0778697a09d36121ead88e08e) -set(OPENAL_VERSION 1.18.2) +set(OPENAL_VERSION 1.20.1) set(OPENAL_URI http://openal-soft.org/openal-releases/openal-soft-${OPENAL_VERSION}.tar.bz2) -set(OPENAL_HASH d4eeb0889812e2fdeaa1843523d76190) +set(OPENAL_HASH 556695068ce8375b89986083d810fd35) set(PNG_VERSION 1.6.35) set(PNG_URI http://prdownloads.sourceforge.net/libpng/libpng-${PNG_VERSION}.tar.xz) @@ -66,9 +66,9 @@ else() set(OPENEXR_VERSION_POSTFIX) endif() -set(FREETYPE_VERSION 2.10.1) +set(FREETYPE_VERSION 2.10.2) set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz) -set(FREETYPE_HASH c50a3c9e5e62bdc938a6e1598a782947) +set(FREETYPE_HASH b1cb620e4c875cd4d1bfa04945400945) set(GLEW_VERSION 1.13.0) set(GLEW_URI http://prdownloads.sourceforge.net/glew/glew/${GLEW_VERSION}/glew-${GLEW_VERSION}.tgz) @@ -101,13 +101,13 @@ set(CUEW_GIT_UID 1744972026de9cf27c8a7dc39cf39cd83d5f922f) set(CUEW_URI https://github.com/CudaWrangler/cuew/archive/${CUEW_GIT_UID}.zip) set(CUEW_HASH 86760d62978ebfd96cd93f5aa1abaf4a) -set(OPENSUBDIV_VERSION v3_4_0_RC2) -set(OPENSUBDIV_Hash f6a10ba9efaa82fde86fe65aad346319) +set(OPENSUBDIV_VERSION v3_4_3) set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.tar.gz) +set(OPENSUBDIV_HASH 7bbfa275d021fb829e521df749160edb) -set(SDL_VERSION 2.0.8) +set(SDL_VERSION 2.0.12) set(SDL_URI https://www.libsdl.org/release/SDL2-${SDL_VERSION}.tar.gz) -set(SDL_HASH 3800d705cef742c6a634f202c37f263f) +set(SDL_HASH 783b6f2df8ff02b19bb5ce492b99c8ff) set(OPENCOLLADA_VERSION v1.6.68) set(OPENCOLLADA_URI https://github.com/KhronosGroup/OpenCOLLADA/archive/${OPENCOLLADA_VERSION}.tar.gz) @@ -168,9 +168,9 @@ 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(OGG_VERSION 1.3.3) +set(OGG_VERSION 1.3.4) set(OGG_URI http://downloads.xiph.org/releases/ogg/libogg-${OGG_VERSION}.tar.gz) -set(OGG_HASH c2e8a485110b97550f453226ec644ebac6cb29d1caef2902c007edab4308d985) +set(OGG_HASH fe5670640bd49e828d64d2879c31cb4dde9758681bb664f9bdbf159a01b0c76e) set(VORBIS_VERSION 1.3.6) set(VORBIS_URI http://downloads.xiph.org/releases/vorbis/libvorbis-${VORBIS_VERSION}.tar.gz) @@ -180,24 +180,24 @@ set(THEORA_VERSION 1.1.1) set(THEORA_URI http://downloads.xiph.org/releases/theora/libtheora-${THEORA_VERSION}.tar.bz2) set(THEORA_HASH b6ae1ee2fa3d42ac489287d3ec34c5885730b1296f0801ae577a35193d3affbc) -set(FLAC_VERSION 1.3.2) +set(FLAC_VERSION 1.3.3) set(FLAC_URI http://downloads.xiph.org/releases/flac/flac-${FLAC_VERSION}.tar.xz) -set(FLAC_HASH 91cfc3ed61dc40f47f050a109b08610667d73477af6ef36dcad31c31a4a8d53f) +set(FLAC_HASH 213e82bd716c9de6db2f98bcadbc4c24c7e2efe8c75939a1a84e28539c4e1748) -set(VPX_VERSION 1.7.0) +set(VPX_VERSION 1.8.2) set(VPX_URI https://github.com/webmproject/libvpx/archive/v${VPX_VERSION}/libvpx-v${VPX_VERSION}.tar.gz) -set(VPX_HASH 1fec931eb5c94279ad219a5b6e0202358e94a93a90cfb1603578c326abfc1238) +set(VPX_HASH 8735d9fcd1a781ae6917f28f239a8aa358ce4864ba113ea18af4bb2dc8b474ac) set(OPUS_VERSION 1.3.1) set(OPUS_URI https://archive.mozilla.org/pub/opus/opus-${OPUS_VERSION}.tar.gz) set(OPUS_HASH 65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d) -set(X264_URI http://download.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20180811-2245-stable.tar.bz2) -set(X264_HASH ae8a868a0e236a348b35d79f3ee80294b169d1195408b689f9851383661ed7aa) +set(X264_URI https://code.videolan.org/videolan/x264/-/archive/master/x264-33f9e1474613f59392be5ab6a7e7abf60fa63622.tar.gz) +set(X264_HASH 300dfb5b6c35722516f168868ce9419252a9e9eb77a05d82c9cede925b691bd6) -set(XVIDCORE_VERSION 1.3.5) -set(XVIDCORE_URI http://downloads.xvid.org/downloads/xvidcore-${XVIDCORE_VERSION}.tar.gz) -set(XVIDCORE_HASH 165ba6a2a447a8375f7b06db5a3c91810181f2898166e7c8137401d7fc894cf0) +set(XVIDCORE_VERSION 1.3.7) +set(XVIDCORE_URI https://downloads.xvid.com/downloads/xvidcore-${XVIDCORE_VERSION}.tar.gz) +set(XVIDCORE_HASH abbdcbd39555691dd1c9b4d08f0a031376a3b211652c0d8b3b8aa9be1303ce2d) # This has to be in sync with the version in blenders /extern folder. set(OPENJPEG_VERSION 2.3.0) @@ -206,13 +206,9 @@ set(OPENJPEG_SHORT_VERSION 2.3) set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/66297f07a43.zip) set(OPENJPEG_HASH 8242b18d908c7c42174e4231a741cfa7ce7c26b6ed5c9644feb9df7b3054310b) -set(FAAD_VERSION 2-2.8.8) -set(FAAD_URI http://downloads.sourceforge.net/faac/faad${FAAD_VERSION}.tar.gz) -set(FAAD_HASH 28f6116efdbe9378269f8a6221767d1f) - -set(FFMPEG_VERSION 4.0.2) +set(FFMPEG_VERSION 4.2.3) set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2) -set(FFMPEG_HASH 5576e8a22f80b6a336db39808f427cfb) +set(FFMPEG_HASH 695fad11f3baf27784e24cb0e977b65a) set(FFTW_VERSION 3.3.8) set(FFTW_URI http://www.fftw.org/fftw-${FFTW_VERSION}.tar.gz) @@ -299,9 +295,9 @@ set(SQLITE_VERSION 3.24.0) set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip) set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7) -set(EMBREE_VERSION 3.8.0) +set(EMBREE_VERSION 3.10.0) set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip) -set(EMBREE_HASH ac504d5426945fe25dec1267e0c39d52) +set(EMBREE_HASH 4bbe29e7eaa46417efc75fc5f1e8eb87) set(USD_VERSION 19.11) set(USD_URI https://github.com/PixarAnimationStudios/USD/archive/v${USD_VERSION}.tar.gz) @@ -319,6 +315,6 @@ set(MESA_VERSION 18.3.1) set(MESA_URI ftp://ftp.freedesktop.org/pub/mesa//mesa-${MESA_VERSION}.tar.xz) set(MESA_HASH d60828056d77bfdbae0970f9b15fb1be) -set(XR_OPENXR_SDK_VERSION 1.0.6) +set(XR_OPENXR_SDK_VERSION 1.0.8) set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz) -set(XR_OPENXR_SDK_HASH 21daea7c3bfec365298d779a0e19caa1) +set(XR_OPENXR_SDK_HASH c6de63d2e0f9029aa58dfa97cad8ce07) diff --git a/build_files/build_environment/cmake/x264.cmake b/build_files/build_environment/cmake/x264.cmake index eba0709e196..8bcb5a2938f 100644 --- a/build_files/build_environment/cmake/x264.cmake +++ b/build_files/build_environment/cmake/x264.cmake @@ -18,9 +18,6 @@ if(WIN32) set(X264_EXTRA_ARGS --enable-win32thread --cross-prefix=${MINGW_HOST}- --host=${MINGW_HOST}) - set(X264_PATCH_CMD ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/x264/src/external_x264 < ${PATCH_DIR}/x264.diff) -else() - set(X264_PATCH_CMD echo .) endif() @@ -29,7 +26,6 @@ ExternalProject_Add(external_x264 DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH SHA256=${X264_HASH} PREFIX ${BUILD_DIR}/x264 - PATCH_COMMAND ${X264_PATCH_CMD} CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/x264 --enable-static --enable-pic diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 5f73756ec0b..d727ed73878 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -436,7 +436,7 @@ OSL_FORCE_REBUILD=false OSL_SKIP=false # OpenSubdiv needs to be compiled for now -OSD_VERSION="3.4.0_RC2" +OSD_VERSION="3.4.3" OSD_VERSION_MIN=$OSD_VERSION OSD_FORCE_BUILD=false OSD_FORCE_REBUILD=false @@ -468,7 +468,7 @@ OPENCOLLADA_FORCE_BUILD=false OPENCOLLADA_FORCE_REBUILD=false OPENCOLLADA_SKIP=false -EMBREE_VERSION="3.8.0" +EMBREE_VERSION="3.10.0" EMBREE_FORCE_BUILD=false EMBREE_FORCE_REBUILD=false EMBREE_SKIP=false @@ -478,14 +478,14 @@ OIDN_FORCE_BUILD=false OIDN_FORCE_REBUILD=false OIDN_SKIP=false -FFMPEG_VERSION="4.0.2" +FFMPEG_VERSION="4.3.2" FFMPEG_VERSION_MIN="2.8.4" FFMPEG_FORCE_BUILD=false FFMPEG_FORCE_REBUILD=false FFMPEG_SKIP=false _ffmpeg_list_sep=";" -XR_OPENXR_VERSION="1.0.6" +XR_OPENXR_VERSION="1.0.8" XR_OPENXR_FORCE_BUILD=false XR_OPENXR_FORCE_REBUILD=false XR_OPENXR_SKIP=false @@ -1029,7 +1029,7 @@ Those libraries should be available as packages in all recent distributions (opt * libjpeg, libpng, libtiff, [openjpeg2], [libopenal]. * libx11, libxcursor, libxi, libxrandr, libxinerama (and other libx... as needed). * libsqlite3, libbz2, libssl, libfftw3, libxml2, libtinyxml, yasm, libyaml-cpp. - * libsdl1.2, libglew, [libglewmx].\"" + * libsdl2, libglew, [libglewmx].\"" DEPS_SPECIFIC_INFO="\"BUILDABLE DEPENDENCIES: @@ -3517,7 +3517,7 @@ install_DEB() { libxcursor-dev libxi-dev wget libsqlite3-dev libxrandr-dev libxinerama-dev \ libbz2-dev libncurses5-dev libssl-dev liblzma-dev libreadline-dev \ libopenal-dev libglew-dev yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV \ - libsdl1.2-dev libfftw3-dev patch bzip2 libxml2-dev libtinyxml-dev libjemalloc-dev" + libsdl2-dev libfftw3-dev patch bzip2 libxml2-dev libtinyxml-dev libjemalloc-dev" # libglewmx-dev (broken in deb testing currently...) VORBIS_USE=true @@ -4163,7 +4163,7 @@ install_RPM() { THEORA_DEV="libtheora-devel" _packages="gcc gcc-c++ git make cmake tar bzip2 xz findutils flex bison \ - libtiff-devel libjpeg-devel libpng-devel sqlite-devel fftw-devel SDL-devel \ + libtiff-devel libjpeg-devel libpng-devel sqlite-devel fftw-devel SDL2-devel \ libX11-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel \ wget ncurses-devel readline-devel $OPENJPEG_DEV openal-soft-devel \ glew-devel yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV patch \ @@ -4724,7 +4724,7 @@ install_ARCH() { _packages="$BASE_DEVEL git cmake \ libxi libxcursor libxrandr libxinerama glew libpng libtiff wget openal \ - $OPENJPEG_DEV $VORBIS_DEV $OGG_DEV $THEORA_DEV yasm sdl fftw \ + $OPENJPEG_DEV $VORBIS_DEV $OGG_DEV $THEORA_DEV yasm sdl2 fftw \ libxml2 yaml-cpp tinyxml python-requests jemalloc" OPENJPEG_USE=true diff --git a/build_files/build_environment/patches/openal.diff b/build_files/build_environment/patches/openal.diff deleted file mode 100644 index 2c9862b95a0..00000000000 --- a/build_files/build_environment/patches/openal.diff +++ /dev/null @@ -1,13 +0,0 @@ -diff -Naur external_openal_original/CMakeLists.txt external_openal/CMakeLists.txt ---- external_openal_original/CMakeLists.txt 2016-01-24 20:12:39 -0700 -+++ external_openal/CMakeLists.txt 2018-06-02 12:16:52 -0600 -@@ -885,7 +885,8 @@ - OPTION(ALSOFT_REQUIRE_MMDEVAPI "Require MMDevApi backend" OFF) - IF(HAVE_WINDOWS_H) - # Check MMSystem backend -- CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0502) -+ set(CMAKE_REQUIRED_FLAGS "-D_WIN32_WINNT=0x0502") -+ CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H) - IF(HAVE_MMSYSTEM_H) - CHECK_SHARED_FUNCTION_EXISTS(waveOutOpen "windows.h;mmsystem.h" winmm "" HAVE_LIBWINMM) - IF(HAVE_LIBWINMM) diff --git a/build_files/build_environment/patches/x264.diff b/build_files/build_environment/patches/x264.diff deleted file mode 100644 index 2f2e68083ac..00000000000 --- a/build_files/build_environment/patches/x264.diff +++ /dev/null @@ -1,22 +0,0 @@ ---- x264-snapshot-20180811-2245-stable\configure 2018-08-11 14:45:05 -0600 -+++ external_x264\configure 2018-08-11 23:51:35 -0600 -@@ -396,7 +396,7 @@ - # list of all preprocessor HAVE values we can define - CONFIG_HAVE="MALLOC_H ALTIVEC ALTIVEC_H MMX ARMV6 ARMV6T2 NEON BEOSTHREAD POSIXTHREAD WIN32THREAD THREAD LOG2F SWSCALE \ - LAVF FFMS GPAC AVS GPL VECTOREXT INTERLACED CPU_COUNT OPENCL THP LSMASH X86_INLINE_ASM AS_FUNC INTEL_DISPATCHER \ -- MSA MMAP WINRT VSX ARM_INLINE_ASM STRTOK_R BITDEPTH8 BITDEPTH10" -+ MSA MMAP WINRT VSX ARM_INLINE_ASM BITDEPTH8 BITDEPTH10" - - # parse options - -@@ -1071,10 +1071,6 @@ - define HAVE_LOG2F - fi - --if cc_check 'string.h' '' 'strtok_r(0, 0, 0);' ; then -- define HAVE_STRTOK_R --fi -- - if [ "$SYS" != "WINDOWS" ] && cpp_check "sys/mman.h unistd.h" "" "defined(MAP_PRIVATE)"; then - define HAVE_MMAP - fi diff --git a/build_files/buildbot/buildbot_utils.py b/build_files/buildbot/buildbot_utils.py index 369bb28006d..2dc1526c5e8 100644 --- a/build_files/buildbot/buildbot_utils.py +++ b/build_files/buildbot/buildbot_utils.py @@ -78,27 +78,26 @@ class VersionInfo: blender_h = os.path.join(builder.blender_dir, "source", "blender", "blenkernel", "BKE_blender_version.h") version_number = int(self._parse_header_file(blender_h, 'BLENDER_VERSION')) - self.version = "%d.%d" % (version_number // 100, version_number % 100) - self.version_char = self._parse_header_file(blender_h, 'BLENDER_VERSION_CHAR') + version_number_patch = int(self._parse_header_file(blender_h, 'BLENDER_VERSION_PATCH')) + version_numbers = (version_number // 100, version_number % 100, version_number_patch) + self.short_version = "%d.%02d" % (version_numbers[0], version_numbers[1]) + self.version = "%d.%02d.%d" % version_numbers self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE') self.version_cycle_number = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE_NUMBER') self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1] if self.version_cycle == "release": # Final release - self.full_version = self.version + self.version_char + self.full_version = self.version self.is_development_build = False elif self.version_cycle == "rc": # Release candidate version_cycle = self.version_cycle + self.version_cycle_number - if len(self.version_char) == 0: - self.full_version = self.version + version_cycle - else: - self.full_version = self.version + self.version_char + '-' + version_cycle + self.full_version = self.version + version_cycle self.is_development_build = False else: # Development build - self.full_version = self.version + self.version_char + '-' + self.hash + self.full_version = self.version + '-' + self.hash self.is_development_build = True def _parse_header_file(self, filename, define): diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py index 3cefe2d5ec6..8549a7881e6 100644 --- a/build_files/buildbot/slave_pack.py +++ b/build_files/buildbot/slave_pack.py @@ -167,7 +167,7 @@ def pack_linux(builder): buildbot_utils.call(builder.command_prefix + ['strip', '--strip-all', blender_executable]) print("Stripping python...") - py_target = os.path.join(builder.install_dir, info.version) + py_target = os.path.join(builder.install_dir, info.short_version) buildbot_utils.call(builder.command_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';']) # Construct package name diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 6fa1c97cf4d..32c187f5f72 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -53,6 +53,7 @@ set(WITH_OPENVDB OFF CACHE BOOL "" FORCE) set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE) set(WITH_SDL OFF CACHE BOOL "" FORCE) set(WITH_TBB OFF CACHE BOOL "" FORCE) +set(WITH_USD OFF CACHE BOOL "" FORCE) if(UNIX AND NOT APPLE) set(WITH_GHOST_XDND OFF CACHE BOOL "" FORCE) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index d99e46ce76e..a906dbc0bf4 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -756,8 +756,7 @@ function(get_blender_version) # - BLENDER_VERSION (major.minor) # - BLENDER_VERSION_MAJOR # - BLENDER_VERSION_MINOR - # - BLENDER_SUBVERSION (used for internal versioning mainly) - # - BLENDER_VERSION_CHAR (a, b, c, ...or empty string) + # - BLENDER_VERSION_PATCH # - BLENDER_VERSION_CYCLE (alpha, beta, rc, release) # So cmake depends on BKE_blender.h, beware of inf-loops! @@ -767,25 +766,15 @@ function(get_blender_version) file(STRINGS ${CMAKE_SOURCE_DIR}/source/blender/blenkernel/BKE_blender_version.h _contents REGEX "^#define[ \t]+BLENDER_.*$") string(REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION[ \t]+([0-9]+).*" "\\1" _out_version "${_contents}") - string(REGEX REPLACE ".*#define[ \t]+BLENDER_SUBVERSION[ \t]+([0-9]+).*" "\\1" _out_subversion "${_contents}") - string(REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION_CHAR[ \t]+([a-z]+).*" "\\1" _out_version_char "${_contents}") + string(REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION_PATCH[ \t]+([0-9]+).*" "\\1" _out_version_patch "${_contents}") string(REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION_CYCLE[ \t]+([a-z]+).*" "\\1" _out_version_cycle "${_contents}") if(NOT ${_out_version} MATCHES "[0-9]+") message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION") endif() - if(NOT ${_out_subversion} MATCHES "[0-9]+") - message(FATAL_ERROR "Version parsing failed for BLENDER_SUBVERSION") - endif() - - # clumsy regex, only single char are ok but it could be unset - - string(LENGTH "${_out_version_char}" _out_version_char_len) - if(NOT _out_version_char_len EQUAL 1) - set(_out_version_char "") - elseif(NOT ${_out_version_char} MATCHES "[a-z]+") - message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION_CHAR") + if(NOT ${_out_version_patch} MATCHES "[0-9]+") + message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION_PATCH") endif() if(NOT ${_out_version_cycle} MATCHES "[a-z]+") @@ -795,23 +784,11 @@ function(get_blender_version) math(EXPR _out_version_major "${_out_version} / 100") math(EXPR _out_version_minor "${_out_version} % 100") - # for packaging, alpha to numbers - string(COMPARE EQUAL "${_out_version_char}" "" _out_version_char_empty) - if(${_out_version_char_empty}) - set(_out_version_char_index "0") - else() - set(_char_ls a b c d e f g h i j k l m n o p q r s t u v w x y z) - list(FIND _char_ls ${_out_version_char} _out_version_char_index) - math(EXPR _out_version_char_index "${_out_version_char_index} + 1") - endif() - # output vars set(BLENDER_VERSION "${_out_version_major}.${_out_version_minor}" PARENT_SCOPE) set(BLENDER_VERSION_MAJOR "${_out_version_major}" PARENT_SCOPE) set(BLENDER_VERSION_MINOR "${_out_version_minor}" PARENT_SCOPE) - set(BLENDER_SUBVERSION "${_out_subversion}" PARENT_SCOPE) - set(BLENDER_VERSION_CHAR "${_out_version_char}" PARENT_SCOPE) - set(BLENDER_VERSION_CHAR_INDEX "${_out_version_char_index}" PARENT_SCOPE) + set(BLENDER_VERSION_PATCH "${_out_version_patch}" PARENT_SCOPE) set(BLENDER_VERSION_CYCLE "${_out_version_cycle}" PARENT_SCOPE) endfunction() diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake index 0e530463659..de27d31323d 100644 --- a/build_files/cmake/packaging.cmake +++ b/build_files/cmake/packaging.cmake @@ -7,7 +7,7 @@ set(PROJECT_VENDOR "Blender Foundation") set(MAJOR_VERSION ${BLENDER_VERSION_MAJOR}) set(MINOR_VERSION ${BLENDER_VERSION_MINOR}) -set(PATCH_VERSION ${BLENDER_VERSION_CHAR_INDEX}) +set(PATCH_VERSION ${BLENDER_VERSION_PATCH}) set(CPACK_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}) set(CPACK_PACKAGE_DESCRIPTION ${PROJECT_DESCRIPTION}) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 1889c9773fb..57bfe19a5bc 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -190,7 +190,7 @@ if(MSVC_VERSION GREATER 1914 AND NOT MSVC_CLANG) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /JMC") endif() -set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /SUBSYSTEM:CONSOLE /STACK:2097152 ") +set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /SUBSYSTEM:CONSOLE /STACK:2097152") set(PLATFORM_LINKFLAGS_RELEASE "/NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvcrtd.lib") set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:libcmtd.lib") diff --git a/build_files/utils/make_source_archive.sh b/build_files/utils/make_source_archive.sh index cafd1c31486..5d9096f3235 100755 --- a/build_files/utils/make_source_archive.sh +++ b/build_files/utils/make_source_archive.sh @@ -7,15 +7,14 @@ BASE_DIR="$PWD" blender_srcdir=$(dirname -- $0)/../.. blender_version=$(grep "BLENDER_VERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') -blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') +blender_version_patch=$(grep "BLENDER_VERSION_PATCH\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') -blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') +VERSION=$(expr $blender_version / 100).$(expr $blender_version % 100).$blender_version_patch if [ "$blender_version_cycle" = "release" ] ; then - VERSION=$(expr $blender_version / 100).$(expr $blender_version % 100)$blender_version_char SUBMODULE_EXCLUDE="^\(release/scripts/addons_contrib\)$" else - VERSION=$(expr $blender_version / 100).$(expr $blender_version % 100)_$blender_subversion + VERSION=$VERSION-$blender_version_cycle SUBMODULE_EXCLUDE="^$" # dummy regex fi diff --git a/doc/python_api/requirements.txt b/doc/python_api/requirements.txt index c2b5b2fd794..263b12eb604 100644 --- a/doc/python_api/requirements.txt +++ b/doc/python_api/requirements.txt @@ -1,2 +1,2 @@ -Sphinx==1.8.5 -sphinx_rtd_theme==0.4.3 +Sphinx==3.0.3 +sphinx_rtd_theme==0.5.0rc1 diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 4780fe389cf..9e81760a794 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -403,32 +403,21 @@ MODULE_GROUPING = { # -------------------------------BLENDER---------------------------------------- -blender_version_strings = [str(v) for v in bpy.app.version] -is_release = bpy.app.version_cycle in {"rc", "release"} - # converting bytes to strings, due to T30154 BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8') -if is_release: - # '2.62a' - BLENDER_VERSION_DOTS = ".".join(blender_version_strings[:2]) + bpy.app.version_char -else: - # '2.62.1' - BLENDER_VERSION_DOTS = ".".join(blender_version_strings) +# '2.83.0 Beta' or '2.83.0' or '2.83.1' +BLENDER_VERSION_DOTS = bpy.app.version_string if BLENDER_REVISION != "Unknown": - # '2.62a SHA1' (release) or '2.62.1 SHA1' (non-release) + # SHA1 Git hash BLENDER_VERSION_HASH = BLENDER_REVISION else: # Fallback: Should not be used BLENDER_VERSION_HASH = "Hash Unknown" -if is_release: - # '2_62a_release' - BLENDER_VERSION_PATH = "%s%s_release" % ("_".join(blender_version_strings[:2]), bpy.app.version_char) -else: - # '2_62_1' - BLENDER_VERSION_PATH = "_".join(blender_version_strings) +# '2_83' +BLENDER_VERSION_PATH = "%d_%d" % (bpy.app.version[0], bpy.app.version[1]) # --------------------------DOWNLOADABLE FILES---------------------------------- diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh index 45cd6a229e5..1c5b9ec0b61 100755 --- a/doc/python_api/sphinx_doc_gen.sh +++ b/doc/python_api/sphinx_doc_gen.sh @@ -36,16 +36,10 @@ fi blender_srcdir=$(dirname -- $0)/../.. blender_version_header="$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" blender_version=$(grep "BLENDER_VERSION\s" "$blender_version_header" | awk '{print $3}') -blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_version_header" | awk '{print $3}') blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_version_header" | awk '{print $3}') -blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_version_header" | awk '{print $3}') unset blender_version_header -if [ "$blender_version_cycle" = "release" ] ; then - BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100)$blender_version_char"_release" -else - BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100)_$blender_subversion -fi +BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100) SSH_UPLOAD_FULL=$SSH_UPLOAD/"blender_python_api_"$BLENDER_VERSION diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py index d3f42b1d26f..6b24f4c4c09 100755 --- a/doc/python_api/sphinx_doc_update.py +++ b/doc/python_api/sphinx_doc_update.py @@ -127,11 +127,10 @@ def main(): " f.write('%d\\n' % is_release)\n" " f.write('%d\\n' % is_beta)\n" " f.write('%s\\n' % branch)\n" - " f.write('%d.%d%s\\n' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char))\n" - " f.write('%d.%d%s\\n' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n" + " f.write('%d.%d\\n' % (bpy.app.version[0], bpy.app.version[1]))\n" + " f.write('%d.%d\\n' % (bpy.app.version[0], bpy.app.version[1]))\n" " if (is_release or is_beta) else '%s\\n' % branch)\n" - " f.write('%d_%d%s_release' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n" - " if is_release else '%d_%d_%d' % bpy.app.version)\n" + " f.write('%d_%d' % (bpy.app.version[0], bpy.app.version[1]))\n" ) get_ver_cmd = (args.blender, "--background", "-noaudio", "--factory-startup", "--python-exit-code", "1", "--python-expr", getver_script, "--", getver_file) diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index e5cd4a3d6ce..023974fd6cd 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit b4a2742bd743e2913fba94dd35846042e2650212" +#define MANTA_GIT_VERSION "commit b61bf9efa7a1d8ca98635076a7e9f2c4dacb2914" diff --git a/extern/mantaflow/preprocessed/particle.h b/extern/mantaflow/preprocessed/particle.h index 2d41397a961..d9dd3f49c38 100644 --- a/extern/mantaflow/preprocessed/particle.h +++ b/extern/mantaflow/preprocessed/particle.h @@ -469,6 +469,7 @@ template<class S> class ParticleSystem : public ParticleBase { const int integrationMode, const bool deleteInObstacle = true, const bool stopInObstacle = true, + const bool skipNew = false, const ParticleDataImpl<int> *ptype = NULL, const int exclude = 0); static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds) @@ -486,13 +487,20 @@ template<class S> class ParticleSystem : public ParticleBase { const int integrationMode = _args.get<int>("integrationMode", 2, &_lock); const bool deleteInObstacle = _args.getOpt<bool>("deleteInObstacle", 3, true, &_lock); const bool stopInObstacle = _args.getOpt<bool>("stopInObstacle", 4, true, &_lock); + const bool skipNew = _args.getOpt<bool>("skipNew", 5, false, &_lock); const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>( - "ptype", 5, NULL, &_lock); - const int exclude = _args.getOpt<int>("exclude", 6, 0, &_lock); + "ptype", 6, NULL, &_lock); + const int exclude = _args.getOpt<int>("exclude", 7, 0, &_lock); pbo->_args.copy(_args); _retval = getPyNone(); - pbo->advectInGrid( - flags, vel, integrationMode, deleteInObstacle, stopInObstacle, ptype, exclude); + pbo->advectInGrid(flags, + vel, + integrationMode, + deleteInObstacle, + stopInObstacle, + skipNew, + ptype, + exclude); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(), "ParticleSystem::advectInGrid", !noTiming); @@ -1863,6 +1871,7 @@ template<class S> struct _GridAdvectKernel : public KernelBase { const Real dt, const bool deleteInObstacle, const bool stopInObstacle, + const bool skipNew, const ParticleDataImpl<int> *ptype, const int exclude, std::vector<Vec3> &u) @@ -1873,6 +1882,7 @@ template<class S> struct _GridAdvectKernel : public KernelBase { dt(dt), deleteInObstacle(deleteInObstacle), stopInObstacle(stopInObstacle), + skipNew(skipNew), ptype(ptype), exclude(exclude), u(u) @@ -1885,11 +1895,13 @@ template<class S> struct _GridAdvectKernel : public KernelBase { const Real dt, const bool deleteInObstacle, const bool stopInObstacle, + const bool skipNew, const ParticleDataImpl<int> *ptype, const int exclude, std::vector<Vec3> &u) const { - if ((p[idx].flag & ParticleBase::PDELETE) || (ptype && ((*ptype)[idx] & exclude))) { + if ((p[idx].flag & ParticleBase::PDELETE) || (ptype && ((*ptype)[idx] & exclude)) || + (skipNew && (p[idx].flag & ParticleBase::PNEW))) { u[idx] = 0.; return; } @@ -1910,7 +1922,7 @@ template<class S> struct _GridAdvectKernel : public KernelBase { void operator()(const tbb::blocked_range<IndexInt> &__r) const { for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) - op(idx, p, vel, flags, dt, deleteInObstacle, stopInObstacle, ptype, exclude, u); + op(idx, p, vel, flags, dt, deleteInObstacle, stopInObstacle, skipNew, ptype, exclude, u); } void run() { @@ -1922,6 +1934,7 @@ template<class S> struct _GridAdvectKernel : public KernelBase { const Real dt; const bool deleteInObstacle; const bool stopInObstacle; + const bool skipNew; const ParticleDataImpl<int> *ptype; const int exclude; std::vector<Vec3> &u; @@ -1933,6 +1946,7 @@ template<class S> struct GridAdvectKernel : public KernelBase { const Real dt, const bool deleteInObstacle, const bool stopInObstacle, + const bool skipNew, const ParticleDataImpl<int> *ptype, const int exclude) : KernelBase(p.size()), @@ -1943,6 +1957,7 @@ template<class S> struct GridAdvectKernel : public KernelBase { dt, deleteInObstacle, stopInObstacle, + skipNew, ptype, exclude, u), @@ -1952,6 +1967,7 @@ template<class S> struct GridAdvectKernel : public KernelBase { dt(dt), deleteInObstacle(deleteInObstacle), stopInObstacle(stopInObstacle), + skipNew(skipNew), ptype(ptype), exclude(exclude), u((size)) @@ -2001,16 +2017,21 @@ template<class S> struct GridAdvectKernel : public KernelBase { return stopInObstacle; } typedef bool type5; - inline const ParticleDataImpl<int> *getArg6() + inline const bool &getArg6() + { + return skipNew; + } + typedef bool type6; + inline const ParticleDataImpl<int> *getArg7() { return ptype; } - typedef ParticleDataImpl<int> type6; - inline const int &getArg7() + typedef ParticleDataImpl<int> type7; + inline const int &getArg8() { return exclude; } - typedef int type7; + typedef int type8; void runMessage() { debMsg("Executing kernel GridAdvectKernel ", 3); @@ -2025,6 +2046,7 @@ template<class S> struct GridAdvectKernel : public KernelBase { const Real dt; const bool deleteInObstacle; const bool stopInObstacle; + const bool skipNew; const ParticleDataImpl<int> *ptype; const int exclude; std::vector<Vec3> u; @@ -2195,6 +2217,7 @@ void ParticleSystem<S>::advectInGrid(const FlagGrid &flags, const int integrationMode, const bool deleteInObstacle, const bool stopInObstacle, + const bool skipNew, const ParticleDataImpl<int> *ptype, const int exclude) { @@ -2208,8 +2231,15 @@ void ParticleSystem<S>::advectInGrid(const FlagGrid &flags, } // update positions - GridAdvectKernel<S> kernel( - mData, vel, flags, getParent()->getDt(), deleteInObstacle, stopInObstacle, ptype, exclude); + GridAdvectKernel<S> kernel(mData, + vel, + flags, + getParent()->getDt(), + deleteInObstacle, + stopInObstacle, + skipNew, + ptype, + exclude); integratePointSet(kernel, integrationMode); if (!deleteInObstacle) { @@ -2438,15 +2468,15 @@ template<class S> void ParticleSystem<S>::compress() //! insert buffered positions as new particles, update additional particle data template<class S> void ParticleSystem<S>::insertBufferedParticles() { + // clear new flag everywhere + for (IndexInt i = 0; i < (IndexInt)mData.size(); ++i) + mData[i].flag &= ~PNEW; + if (mNewBufferPos.size() == 0) return; IndexInt newCnt = mData.size(); resizeAll(newCnt + mNewBufferPos.size()); - // clear new flag everywhere - for (IndexInt i = 0; i < (IndexInt)mData.size(); ++i) - mData[i].flag &= ~PNEW; - for (IndexInt i = 0; i < (IndexInt)mNewBufferPos.size(); ++i) { int flag = (mNewBufferFlag.size() > 0) ? mNewBufferFlag[i] : 0; // note, other fields are not initialized here... diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 08641c05941..a15daee706f 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1907,10 +1907,15 @@ class CYCLES_RENDER_PT_bake_selected_to_active(CyclesButtonsPanel, Panel): col.prop(cbk, "use_cage", text="Cage") if cbk.use_cage: - col.prop(cbk, "cage_extrusion", text="Extrusion") - col.prop(cbk, "cage_object", text="Cage Object") + col.prop(cbk, "cage_object") + col = layout.column() + col.prop(cbk, "cage_extrusion") + col.active = cbk.cage_object is None else: - col.prop(cbk, "cage_extrusion", text="Ray Distance") + col.prop(cbk, "cage_extrusion", text="Extrusion") + + col = layout.column() + col.prop(cbk, "max_ray_distance") class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel): diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 4b29c28913b..a461982a538 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -460,9 +460,12 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render, sync_objects(b_depsgraph, b_v3d, 0.0f); } - /* always sample these times for camera motion */ - motion_times.insert(-1.0f); - motion_times.insert(1.0f); + /* Insert motion times from camera. Motion times from other objects + * have already been added in a sync_objects call. */ + uint camera_motion_steps = object_motion_steps(b_cam, b_cam); + for (size_t step = 0; step < camera_motion_steps; step++) { + motion_times.insert(scene->camera->motion_time(step)); + } /* note iteration over motion_times set happens in sorted order */ foreach (float relative_time, motion_times) { @@ -487,10 +490,8 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render, b_engine.frame_set(frame, subframe); python_thread_state_save(python_thread_state); - /* sync camera, only supports two times at the moment */ - if (relative_time == -1.0f || relative_time == 1.0f) { - sync_camera_motion(b_render, b_cam, width, height, relative_time); - } + /* Syncs camera motion if relative_time is one of the camera's motion times. */ + sync_camera_motion(b_render, b_cam, width, height, relative_time); /* sync object */ sync_objects(b_depsgraph, b_v3d, relative_time); diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 31b09695632..dbe87ce2b13 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -168,9 +168,13 @@ void BlenderSession::create_session() void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph) { + /* Update data, scene and depsgraph pointers. These can change after undo. */ this->b_data = b_data; this->b_depsgraph = b_depsgraph; this->b_scene = b_depsgraph.scene_eval(); + if (sync) { + sync->reset(this->b_data, this->b_scene); + } if (preview_osl) { PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index f16305e737d..2605799f593 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -78,6 +78,14 @@ BlenderSync::~BlenderSync() { } +void BlenderSync::reset(BL::BlendData &b_data, BL::Scene &b_scene) +{ + /* Update data and scene pointers in case they change in session reset, + * for example after undo. */ + this->b_data = b_data; + this->b_scene = b_scene; +} + /* Sync */ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d) diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 650b4f5bb4e..f0ea5194c29 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -61,6 +61,8 @@ class BlenderSync { Progress &progress); ~BlenderSync(); + void reset(BL::BlendData &b_data, BL::Scene &b_scene); + /* sync */ void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d); void sync_data(BL::RenderSettings &b_render, diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp index 6254a1a1b24..4eed6be8c7c 100644 --- a/intern/cycles/blender/blender_volume.cpp +++ b/intern/cycles/blender/blender_volume.cpp @@ -34,15 +34,13 @@ CCL_NAMESPACE_BEGIN /* TODO: verify this is not loading unnecessary attributes. */ class BlenderSmokeLoader : public ImageLoader { public: - BlenderSmokeLoader(const BL::Object &b_ob, AttributeStandard attribute) - : b_ob(b_ob), attribute(attribute) + BlenderSmokeLoader(BL::Object &b_ob, AttributeStandard attribute) + : b_domain(object_fluid_gas_domain_find(b_ob)), b_mesh(b_ob.data()), attribute(attribute) { } bool load_metadata(ImageMetaData &metadata) override { - BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); - if (!b_domain) { return false; } @@ -79,7 +77,6 @@ class BlenderSmokeLoader : public ImageLoader { /* Create a matrix to transform from object space to mesh texture space. * This does not work with deformations but that can probably only be done * well with a volume grid mapping of coordinates. */ - BL::Mesh b_mesh(b_ob.data()); float3 loc, size; mesh_texture_space(b_mesh, loc, size); metadata.transform_3d = transform_translate(-loc) * transform_scale(size); @@ -90,9 +87,6 @@ class BlenderSmokeLoader : public ImageLoader { bool load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool) override { - /* smoke volume data */ - BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); - if (!b_domain) { return false; } @@ -179,10 +173,11 @@ class BlenderSmokeLoader : public ImageLoader { bool equals(const ImageLoader &other) const override { const BlenderSmokeLoader &other_loader = (const BlenderSmokeLoader &)other; - return b_ob == other_loader.b_ob && attribute == other_loader.attribute; + return b_domain == other_loader.b_domain && attribute == other_loader.attribute; } - BL::Object b_ob; + BL::FluidDomainSettings b_domain; + BL::Mesh b_mesh; AttributeStandard attribute; }; diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp index 9356adf3ea5..6735202835b 100644 --- a/intern/cycles/bvh/bvh_embree.cpp +++ b/intern/cycles/bvh/bvh_embree.cpp @@ -16,11 +16,6 @@ /* This class implements a ray accelerator for Cycles using Intel's Embree library. * It supports triangles, curves, object and deformation blur and instancing. - * Not supported are thick line segments, those have no native equivalent in Embree. - * They could be implemented using Embree's thick curves, at the expense of wasted memory. - * User defined intersections for Embree could also be an option, but since Embree only uses - * aligned BVHs for user geometry, this would come with reduced performance and/or higher memory - * usage. * * Since Embree allows object to be either curves or triangles but not both, Cycles object IDs are * mapped to Embree IDs by multiplying by two and adding one for curves. @@ -775,6 +770,21 @@ void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair } } } +# if RTC_VERSION >= 30900 + if (!use_curves) { + unsigned char *flags = (unsigned char *)rtcSetNewGeometryBuffer(geom_id, + RTC_BUFFER_TYPE_FLAGS, + 0, + RTC_FORMAT_UCHAR, + sizeof(unsigned char), + num_keys_embree); + flags[0] = RTC_CURVE_FLAG_NEIGHBOR_RIGHT; + ::memset(flags + 1, + RTC_CURVE_FLAG_NEIGHBOR_RIGHT | RTC_CURVE_FLAG_NEIGHBOR_RIGHT, + num_keys_embree - 2); + flags[num_keys_embree - 1] = RTC_CURVE_FLAG_NEIGHBOR_LEFT; + } +# endif } void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i) @@ -810,10 +820,18 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i) size_t prim_tri_index_size = pack.prim_index.size(); pack.prim_tri_index.resize(prim_tri_index_size + num_segments); +# if RTC_VERSION >= 30900 + enum RTCGeometryType type = (!use_curves) ? + (use_ribbons ? RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE : + RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE) : + (use_ribbons ? RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE : + RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE); +# else enum RTCGeometryType type = (!use_curves) ? RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE : (use_ribbons ? RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE : RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE); +# endif RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, type); rtcSetGeometryTessellationRate(geom_id, curve_subdivisions); diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index e839d852127..441fa35f8af 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -924,7 +924,8 @@ class OptiXDevice : public CUDADevice { &rtiles[9].h, &rtiles[9].offset, &rtiles[9].stride, - &task.pass_stride}; + &task.pass_stride, + &rtile.sample}; launch_filter_kernel( "kernel_cuda_filter_convert_from_rgb", rtiles[9].w, rtiles[9].h, output_args); # endif diff --git a/intern/cycles/kernel/kernel_adaptive_sampling.h b/intern/cycles/kernel/kernel_adaptive_sampling.h index ee4d1507ef1..98b7bf7e7dc 100644 --- a/intern/cycles/kernel/kernel_adaptive_sampling.h +++ b/intern/cycles/kernel/kernel_adaptive_sampling.h @@ -185,19 +185,19 @@ ccl_device bool kernel_do_adaptive_filter_x(KernelGlobals *kg, int y, ccl_global ccl_global float *buffer = tile->buffer + index * kernel_data.film.pass_stride; ccl_global float4 *aux = (ccl_global float4 *)(buffer + kernel_data.film.pass_adaptive_aux_buffer); - if (aux->w == 0.0f) { + if ((*aux).w == 0.0f) { any = true; if (x > tile->x && !prev) { index = index - 1; buffer = tile->buffer + index * kernel_data.film.pass_stride; aux = (ccl_global float4 *)(buffer + kernel_data.film.pass_adaptive_aux_buffer); - aux->w = 0.0f; + (*aux).w = 0.0f; } prev = true; } else { if (prev) { - aux->w = 0.0f; + (*aux).w = 0.0f; } prev = false; } @@ -214,19 +214,19 @@ ccl_device bool kernel_do_adaptive_filter_y(KernelGlobals *kg, int x, ccl_global ccl_global float *buffer = tile->buffer + index * kernel_data.film.pass_stride; ccl_global float4 *aux = (ccl_global float4 *)(buffer + kernel_data.film.pass_adaptive_aux_buffer); - if (aux->w == 0.0f) { + if ((*aux).w == 0.0f) { any = true; if (y > tile->y && !prev) { index = index - tile->stride; buffer = tile->buffer + index * kernel_data.film.pass_stride; aux = (ccl_global float4 *)(buffer + kernel_data.film.pass_adaptive_aux_buffer); - aux->w = 0.0f; + (*aux).w = 0.0f; } prev = true; } else { if (prev) { - aux->w = 0.0f; + (*aux).w = 0.0f; } prev = false; } diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h index 3829426f261..8344f4b4f47 100644 --- a/intern/cycles/kernel/kernel_film.h +++ b/intern/cycles/kernel/kernel_film.h @@ -28,13 +28,13 @@ ccl_device float4 film_get_pass_result(KernelGlobals *kg, int display_pass_components = kernel_data.film.display_pass_components; if (display_pass_components == 4) { - ccl_global float4 *in = (ccl_global float4 *)(buffer + display_pass_stride + - index * kernel_data.film.pass_stride); + float4 in = *(ccl_global float4 *)(buffer + display_pass_stride + + index * kernel_data.film.pass_stride); float alpha = use_display_sample_scale ? - (kernel_data.film.use_display_pass_alpha ? in->w : 1.0f / sample_scale) : + (kernel_data.film.use_display_pass_alpha ? in.w : 1.0f / sample_scale) : 1.0f; - pass_result = make_float4(in->x, in->y, in->z, alpha); + pass_result = make_float4(in.x, in.y, in.z, alpha); int display_divide_pass_stride = kernel_data.film.display_divide_pass_stride; if (display_divide_pass_stride != -1) { diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index ce908ce0fe2..d918abed381 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -1041,11 +1041,19 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, } } else { - /* compute random point in triangle */ - randu = sqrtf(randu); + /* compute random point in triangle. From Eric Heitz's "A Low-Distortion Map Between Triangle + * and Square" */ + float u = randu; + float v = randv; + if (v > u) { + u *= 0.5f; + v -= u; + } + else { + v *= 0.5f; + u -= v; + } - const float u = 1.0f - randu; - const float v = randv * randu; const float t = 1.0f - u - v; ls->P = u * V[0] + v * V[1] + t * V[2]; /* compute incoming direction, distance and pdf */ diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index db35303e3f1..ba46d84d158 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -662,7 +662,7 @@ ccl_device void kernel_path_trace( if (kernel_data.film.pass_adaptive_aux_buffer) { ccl_global float4 *aux = (ccl_global float4 *)(buffer + kernel_data.film.pass_adaptive_aux_buffer); - if (aux->w > 0.0f) { + if ((*aux).w > 0.0f) { return; } } diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 337c4fb1d10..b9569f531e6 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -526,7 +526,7 @@ ccl_device void kernel_branched_path_trace( if (kernel_data.film.pass_adaptive_aux_buffer) { ccl_global float4 *aux = (ccl_global float4 *)(buffer + kernel_data.film.pass_adaptive_aux_buffer); - if (aux->w > 0.0f) { + if ((*aux).w > 0.0f) { return; } } diff --git a/intern/cycles/kernel/kernel_work_stealing.h b/intern/cycles/kernel/kernel_work_stealing.h index c642d227e4b..d1602744f1d 100644 --- a/intern/cycles/kernel/kernel_work_stealing.h +++ b/intern/cycles/kernel/kernel_work_stealing.h @@ -99,7 +99,7 @@ ccl_device bool get_next_work(KernelGlobals *kg, ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset; ccl_global float4 *aux = (ccl_global float4 *)(buffer + kernel_data.film.pass_adaptive_aux_buffer); - if (aux->w == 0.0f) { + if ((*aux).w == 0.0f) { break; } } diff --git a/intern/cycles/kernel/kernels/cuda/filter.cu b/intern/cycles/kernel/kernels/cuda/filter.cu index 22fd5ea5634..6c9642d1f03 100644 --- a/intern/cycles/kernel/kernels/cuda/filter.cu +++ b/intern/cycles/kernel/kernels/cuda/filter.cu @@ -57,9 +57,9 @@ kernel_cuda_filter_convert_to_rgb(float *rgb, float *buf, int sw, int sh, int st if (num_inputs > 0) { float *in = buf + x * pass_stride + (y * stride + pass_offset.x) / sizeof(float); float *out = rgb + (x + y * sw) * 3; - out[0] = clamp(in[0], 0.0f, 10000.0f); - out[1] = clamp(in[1], 0.0f, 10000.0f); - out[2] = clamp(in[2], 0.0f, 10000.0f); + out[0] = clamp(in[0] / num_samples, 0.0f, 10000.0f); + out[1] = clamp(in[1] / num_samples, 0.0f, 10000.0f); + out[2] = clamp(in[2] / num_samples, 0.0f, 10000.0f); } if (num_inputs > 1) { float *in = buf + x * pass_stride + (y * stride + pass_offset.y) / sizeof(float); @@ -80,16 +80,16 @@ kernel_cuda_filter_convert_to_rgb(float *rgb, float *buf, int sw, int sh, int st extern "C" __global__ void CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS) -kernel_cuda_filter_convert_from_rgb(float *rgb, float *buf, int ix, int iy, int iw, int ih, int sx, int sy, int sw, int sh, int offset, int stride, int pass_stride) +kernel_cuda_filter_convert_from_rgb(float *rgb, float *buf, int ix, int iy, int iw, int ih, int sx, int sy, int sw, int sh, int offset, int stride, int pass_stride, int num_samples) { int x = blockDim.x*blockIdx.x + threadIdx.x; int y = blockDim.y*blockIdx.y + threadIdx.y; if(x < sw && y < sh) { float *in = rgb + ((ix + x) + (iy + y) * iw) * 3; float *out = buf + (offset + (sx + x) + (sy + y) * stride) * pass_stride; - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; + out[0] = in[0] * num_samples; + out[1] = in[1] * num_samples; + out[2] = in[2] * num_samples; } } diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 75527d50c6a..c7737392e7b 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -435,7 +435,7 @@ extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, ***************************************************************************************/ /** - * Returns the state of a modifier key (ouside the message queue). + * Returns the state of a modifier key (outside the message queue). * \param systemhandle The handle to the system * \param mask The modifier key state to retrieve. * \param isDown Pointer to return modifier state in. @@ -446,7 +446,7 @@ extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, int *isDown); /** - * Returns the state of a mouse button (ouside the message queue). + * Returns the state of a mouse button (outside the message queue). * \param systemhandle The handle to the system * \param mask The button state to retrieve. * \param isDown Pointer to return button state in. diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 9b619f5c684..33600fd1219 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -382,7 +382,7 @@ class GHOST_ISystem { ***************************************************************************************/ /** - * Returns the state of a modifier key (ouside the message queue). + * Returns the state of a modifier key (outside the message queue). * \param mask The modifier key state to retrieve. * \param isDown The state of a modifier key (true == pressed). * \return Indication of success. @@ -390,7 +390,7 @@ class GHOST_ISystem { virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const = 0; /** - * Returns the state of a mouse button (ouside the message queue). + * Returns the state of a mouse button (outside the message queue). * \param mask The button state to retrieve. * \param isDown Button state. * \return Indication of success. diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h index 88053f83fb9..13632a1c03b 100644 --- a/intern/ghost/GHOST_Rect.h +++ b/intern/ghost/GHOST_Rect.h @@ -49,14 +49,6 @@ class GHOST_Rect { } /** - * Copy constructor. - * \param r rectangle to copy - */ - GHOST_Rect(const GHOST_Rect &r) : m_l(r.m_l), m_t(r.m_t), m_r(r.m_r), m_b(r.m_b) - { - } - - /** * Destructor. */ virtual ~GHOST_Rect() diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 587e4c28102..b0d2adff4bc 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -23,8 +23,8 @@ #include "GHOST_System.h" +#include <chrono> #include <stdio.h> /* just for printf */ -#include <time.h> #include "GHOST_DisplayManager.h" #include "GHOST_EventManager.h" @@ -58,12 +58,9 @@ GHOST_System::~GHOST_System() GHOST_TUns64 GHOST_System::getMilliSeconds() const { - GHOST_TUns64 millis = ::clock(); - if (CLOCKS_PER_SEC != 1000) { - millis *= 1000; - millis /= CLOCKS_PER_SEC; - } - return millis; + return std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); } GHOST_ITimerTask *GHOST_System::installTimer(GHOST_TUns64 delay, diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index 0f58be49dff..c2d712c11cd 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -219,7 +219,7 @@ class GHOST_System : public GHOST_ISystem { ***************************************************************************************/ /** - * Returns the state of a modifier key (ouside the message queue). + * Returns the state of a modifier key (outside the message queue). * \param mask The modifier key state to retrieve. * \param isDown The state of a modifier key (true == pressed). * \return Indication of success. @@ -227,7 +227,7 @@ class GHOST_System : public GHOST_ISystem { GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const; /** - * Returns the state of a mouse button (ouside the message queue). + * Returns the state of a mouse button (outside the message queue). * \param mask The button state to retrieve. * \param isDown Button state. * \return Indication of success. @@ -247,8 +247,8 @@ class GHOST_System : public GHOST_ISystem { ***************************************************************************************/ /** - * Sets 3D mouse deadzone - * \param deadzone: Deadzone of the 3D mouse (both for rotation and pan) relative to full range + * Sets 3D mouse dead-zone + * \param deadzone: Dead-zone of the 3D mouse (both for rotation and pan) relative to full range. */ void setNDOFDeadZone(float deadzone); #endif @@ -295,7 +295,7 @@ class GHOST_System : public GHOST_ISystem { virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const = 0; /** - * Returns the state of the mouse buttons (ouside the message queue). + * Returns the state of the mouse buttons (outside the message queue). * \param buttons The state of the buttons. * \return Indication of success. */ diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index d058697470a..bbd6f1d8995 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -198,7 +198,7 @@ class GHOST_SystemCocoa : public GHOST_System { GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const; /** - * Returns the state of the mouse buttons (ouside the message queue). + * Returns the state of the mouse buttons (outside the message queue). * \param buttons The state of the buttons. * \return Indication of success. */ diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 1346e1bce20..633451feb85 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -25,6 +25,7 @@ #include "GHOST_EventDragnDrop.h" #include "GHOST_EventKey.h" #include "GHOST_EventWheel.h" +#include "GHOST_TimerManager.h" #include "GHOST_WindowManager.h" #include "GHOST_ContextEGL.h" @@ -34,7 +35,7 @@ #include <algorithm> #include <atomic> -#include <exception> +#include <stdexcept> #include <thread> #include <unordered_map> #include <unordered_set> @@ -91,6 +92,13 @@ struct data_source_t { char *buffer_out; }; +struct key_repeat_payload_t { + GHOST_SystemWayland *system; + GHOST_IWindow *window; + GHOST_TKey key; + GHOST_TEventKeyData key_data; +}; + struct input_t { GHOST_SystemWayland *system; @@ -109,6 +117,17 @@ struct input_t { struct xkb_context *xkb_context; struct xkb_state *xkb_state; + struct { + /* Key repetition in character per second. */ + int32_t rate; + /* Time (milliseconds) after which to start repeating keys. */ + int32_t delay; + /* Timer for key repeats. */ + GHOST_ITimerTask *timer = nullptr; + } key_repeat; + + struct wl_surface *focus_pointer = nullptr; + struct wl_surface *focus_keyboard = nullptr; struct wl_data_device *data_device = nullptr; struct data_offer_t *data_offer_dnd; /* Drag & Drop. */ @@ -174,6 +193,11 @@ static void display_destroy(display_t *d) } } if (input->keyboard) { + if (input->key_repeat.timer) { + delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData()); + input->system->removeTimer(input->key_repeat.timer); + input->key_repeat.timer = nullptr; + } wl_keyboard_destroy(input->keyboard); } if (input->xkb_state) { @@ -420,22 +444,26 @@ static void relative_pointer_relative_motion( input->x += wl_fixed_to_int(dx); input->y += wl_fixed_to_int(dy); - input->system->pushEvent( - new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - input->system->getWindowManager()->getActiveWindow(), - input->x, - input->y, - GHOST_TABLET_DATA_NONE)); + GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(input->focus_pointer)); + + input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), + GHOST_kEventCursorMove, + win, + input->x, + input->y, + GHOST_TABLET_DATA_NONE)); } static const zwp_relative_pointer_v1_listener relative_pointer_listener = { - relative_pointer_relative_motion}; + relative_pointer_relative_motion, +}; static void dnd_events(const input_t *const input, const GHOST_TEventType event) { const GHOST_TUns64 time = input->system->getMilliSeconds(); - GHOST_IWindow *const window = input->system->getWindowManager()->getActiveWindow(); + GHOST_IWindow *const window = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(input->focus_pointer)); for (const std::string &type : mime_preference_order) { input->system->pushEvent(new GHOST_EventDragnDrop(time, event, @@ -641,7 +669,7 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic data_offer->types.begin(), data_offer->types.end()); - auto read_uris = [](GHOST_SystemWayland *const system, + auto read_uris = [](input_t *const input, data_offer_t *data_offer, const std::string mime_receive) { const int x = data_offer->dnd.x; @@ -655,6 +683,8 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic delete data_offer; data_offer = nullptr; + GHOST_SystemWayland *const system = input->system; + if (mime_receive == mime_text_uri) { static constexpr const char *file_proto = "file://"; static constexpr const char *crlf = "\r\n"; @@ -683,10 +713,12 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic malloc((uris[i].size() + 1) * sizeof(GHOST_TUns8))); memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1); } + GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(input->focus_pointer)); system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(), GHOST_kEventDraggingDropDone, GHOST_kDragnDropTypeFilenames, - system->getWindowManager()->getActiveWindow(), + win, x, y, flist)); @@ -698,7 +730,7 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic wl_display_roundtrip(system->display()); }; - std::thread read_thread(read_uris, input->system, data_offer, mime_receive); + std::thread read_thread(read_uris, input, data_offer, mime_receive); read_thread.detach(); } @@ -778,17 +810,24 @@ static void pointer_enter(void *data, input->pointer_serial = serial; input->x = wl_fixed_to_int(surface_x); input->y = wl_fixed_to_int(surface_y); + input->focus_pointer = surface; - static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface))->activate(); + input->system->pushEvent( + new GHOST_EventCursor(input->system->getMilliSeconds(), + GHOST_kEventCursorMove, + static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface)), + input->x, + input->y, + GHOST_TABLET_DATA_NONE)); } -static void pointer_leave(void * /*data*/, +static void pointer_leave(void *data, struct wl_pointer * /*wl_pointer*/, uint32_t /*serial*/, struct wl_surface *surface) { if (surface != nullptr) { - static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface))->deactivate(); + static_cast<input_t *>(data)->focus_pointer = nullptr; } } @@ -800,16 +839,22 @@ static void pointer_motion(void *data, { input_t *input = static_cast<input_t *>(data); + GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(input->focus_pointer)); + + if (!win) { + return; + } + input->x = wl_fixed_to_int(surface_x); input->y = wl_fixed_to_int(surface_y); - input->system->pushEvent( - new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - input->system->getWindowManager()->getActiveWindow(), - wl_fixed_to_int(surface_x), - wl_fixed_to_int(surface_y), - GHOST_TABLET_DATA_NONE)); + input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), + GHOST_kEventCursorMove, + win, + wl_fixed_to_int(surface_x), + wl_fixed_to_int(surface_y), + GHOST_TABLET_DATA_NONE)); } static void pointer_button(void *data, @@ -843,14 +888,12 @@ static void pointer_button(void *data, } input_t *input = static_cast<input_t *>(data); + GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(input->focus_pointer)); input->data_source->source_serial = serial; input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); - input->system->pushEvent( - new GHOST_EventButton(input->system->getMilliSeconds(), - etype, - input->system->getWindowManager()->getActiveWindow(), - ebutton, - GHOST_TABLET_DATA_NONE)); + input->system->pushEvent(new GHOST_EventButton( + input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE)); } static void pointer_axis(void *data, @@ -863,10 +906,10 @@ static void pointer_axis(void *data, return; } input_t *input = static_cast<input_t *>(data); + GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(input->focus_pointer)); input->system->pushEvent( - new GHOST_EventWheel(input->system->getMilliSeconds(), - input->system->getWindowManager()->getActiveWindow(), - std::signbit(value) ? +1 : -1)); + new GHOST_EventWheel(input->system->getMilliSeconds(), win, std::signbit(value) ? +1 : -1)); } static const struct wl_pointer_listener pointer_listener = { @@ -913,13 +956,15 @@ static void keyboard_keymap( * Notification that this seat's keyboard focus is on a certain * surface. */ -static void keyboard_enter(void * /*data*/, +static void keyboard_enter(void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t /*serial*/, - struct wl_surface * /*surface*/, + struct wl_surface *surface, struct wl_array * /*keys*/) { - /* pass */ + if (surface != nullptr) { + static_cast<input_t *>(data)->focus_keyboard = surface; + } } /** @@ -928,12 +973,14 @@ static void keyboard_enter(void * /*data*/, * Notification that this seat's keyboard focus is no longer on a * certain surface. */ -static void keyboard_leave(void * /*data*/, +static void keyboard_leave(void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t /*serial*/, - struct wl_surface * /*surface*/) + struct wl_surface *surface) { - /* pass */ + if (surface != nullptr) { + static_cast<input_t *>(data)->focus_keyboard = nullptr; + } } /** @@ -988,6 +1035,14 @@ static void keyboard_key(void *data, } const GHOST_TKey gkey = xkb_map_gkey(sym); + /* Delete previous timer. */ + if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) && + input->key_repeat.timer) { + delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData()); + input->system->removeTimer(input->key_repeat.timer); + input->key_repeat.timer = nullptr; + } + GHOST_TEventKeyData key_data; if (etype == GHOST_kEventKeyDown) { @@ -999,13 +1054,38 @@ static void keyboard_key(void *data, } input->data_source->source_serial = serial; - input->system->pushEvent(new GHOST_EventKey(input->system->getMilliSeconds(), - etype, - input->system->getWindowManager()->getActiveWindow(), - gkey, - '\0', - key_data.utf8_buf, - false)); + + GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(input->focus_keyboard)); + input->system->pushEvent(new GHOST_EventKey( + input->system->getMilliSeconds(), etype, win, gkey, '\0', key_data.utf8_buf, false)); + + /* Start timer for repeating key, if applicable. */ + if (input->key_repeat.rate > 0 && + xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) && + etype == GHOST_kEventKeyDown) { + + key_repeat_payload_t *payload = new key_repeat_payload_t({ + .system = input->system, + .window = win, + .key = gkey, + .key_data = key_data, + }); + + auto cb = [](GHOST_ITimerTask *task, GHOST_TUns64 /*time*/) { + struct key_repeat_payload_t *payload = static_cast<key_repeat_payload_t *>( + task->getUserData()); + payload->system->pushEvent(new GHOST_EventKey(payload->system->getMilliSeconds(), + GHOST_kEventKeyDown, + payload->window, + payload->key, + '\0', + payload->key_data.utf8_buf, + true)); + }; + input->key_repeat.timer = input->system->installTimer( + input->key_repeat.delay, 1000 / input->key_repeat.rate, cb, payload); + } } static void keyboard_modifiers(void *data, @@ -1025,12 +1105,24 @@ static void keyboard_modifiers(void *data, group); } +static void keyboard_repeat_info(void *data, + struct wl_keyboard * /*wl_keyboard*/, + int32_t rate, + int32_t delay) +{ + input_t *input = static_cast<input_t *>(data); + + input->key_repeat.rate = rate; + input->key_repeat.delay = delay; +} + static const struct wl_keyboard_listener keyboard_listener = { keyboard_keymap, keyboard_enter, keyboard_leave, keyboard_key, keyboard_modifiers, + keyboard_repeat_info, }; static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) @@ -1163,7 +1255,7 @@ static void global_add(void *data, input->relative_pointer = nullptr; input->locked_pointer = nullptr; input->seat = static_cast<wl_seat *>( - wl_registry_bind(wl_registry, name, &wl_seat_interface, 2)); + wl_registry_bind(wl_registry, name, &wl_seat_interface, 4)); display->inputs.push_back(input); wl_seat_add_listener(input->seat, &seat_listener, input); } @@ -1260,10 +1352,18 @@ GHOST_SystemWayland::~GHOST_SystemWayland() display_destroy(d); } -bool GHOST_SystemWayland::processEvents(bool /*waitForEvent*/) +bool GHOST_SystemWayland::processEvents(bool waitForEvent) { - wl_display_dispatch(d->display); - return true; + const bool fired = getTimerManager()->fireTimers(getMilliSeconds()); + + if (waitForEvent) { + wl_display_dispatch(d->display); + } + else { + wl_display_roundtrip(d->display); + } + + return fired || (getEventManager()->getNumEvents() > 0); } int GHOST_SystemWayland::toggleConsole(int /*action*/) @@ -1352,7 +1452,7 @@ GHOST_TUns8 GHOST_SystemWayland::getNumDisplays() const GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const { - if (getWindowManager()->getActiveWindow() != nullptr && !d->inputs.empty()) { + if (!d->inputs.empty() && (d->inputs[0]->focus_pointer != nullptr)) { x = d->inputs[0]->x; y = d->inputs[0]->y; return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index b23f907608c..6b7901c2ade 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -212,7 +212,7 @@ class GHOST_SystemWin32 : public GHOST_System { GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const; /** - * Returns the state of the mouse buttons (ouside the message queue). + * Returns the state of the mouse buttons (outside the message queue). * \param buttons The state of the buttons. * \return Indication of success. */ diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index bb01ef7e0cc..5888605ec95 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -182,7 +182,7 @@ class GHOST_SystemX11 : public GHOST_System { GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const; /** - * Returns the state of the mouse buttons (ouside the message queue). + * Returns the state of the mouse buttons (outside the message queue). * \param buttons The state of the buttons. * \return Indication of success. */ @@ -211,7 +211,7 @@ class GHOST_SystemX11 : public GHOST_System { } #endif - /* Helped function for get data from the clipboard. */ + /** Helped function for get data from the clipboard. */ void getClipboard_xcout(const XEvent *evt, Atom sel, Atom target, @@ -337,7 +337,7 @@ class GHOST_SystemX11 : public GHOST_System { private: Display *m_display; - /* Use for scancode lookups. */ + /** Use for scan-code look-ups. */ XkbDescRec *m_xkb_descr; #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) @@ -349,20 +349,22 @@ class GHOST_SystemX11 : public GHOST_System { std::vector<GHOST_TabletX11> m_xtablets; #endif - /// The vector of windows that need to be updated. + /** The vector of windows that need to be updated. */ std::vector<GHOST_WindowX11 *> m_dirty_windows; - /// Start time at initialization. + /** Start time at initialization. */ GHOST_TUns64 m_start_time; - /// A vector of keyboard key masks + /** A vector of keyboard key masks. */ char m_keyboard_vector[32]; - /* to prevent multiple warp, we store the time of the last warp event - * and stop accumulating all events generated before that */ + /** + * To prevent multiple warp, we store the time of the last warp event + * and stop accumulating all events generated before that. + */ Time m_last_warp; - /* detect autorepeat glitch */ + /* Detect auto-repeat glitch. */ unsigned int m_last_release_keycode; Time m_last_release_time; diff --git a/intern/guardedalloc/CMakeLists.txt b/intern/guardedalloc/CMakeLists.txt index 1d4f846623c..cb24df65ba0 100644 --- a/intern/guardedalloc/CMakeLists.txt +++ b/intern/guardedalloc/CMakeLists.txt @@ -53,6 +53,14 @@ if(WIN32 AND NOT UNIX) mmap_win.h ) + + list(APPEND INC_SYS + ${PTHREADS_INC} + ) + + list(APPEND LIB + ${PTHREADS_LIBRARIES} + ) endif() # Jemalloc 5.0.0+ needs extra configuration. diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h index d5b109ee59f..602297576c8 100644 --- a/intern/guardedalloc/MEM_guardedalloc.h +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -145,14 +145,6 @@ extern void *(*MEM_mallocN_aligned)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3); -/** - * Same as callocN, clears memory and uses mmap (disk cached) if supported. - * Can be free'd with MEM_freeN as usual. - * */ -extern void *(*MEM_mapallocN)(size_t len, - const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT - ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2); - /** Print a list of the names and sizes of all allocated memory * blocks. as a python dict for easy investigation */ extern void (*MEM_printmemlist_pydict)(void); @@ -176,20 +168,11 @@ extern void (*MEM_set_error_callback)(void (*func)(const char *)); * @retval true for correct memory, false for corrupted memory. */ extern bool (*MEM_consistency_check)(void); -/** Set thread locking functions for safe memory allocation from multiple - * threads, pass NULL pointers to disable thread locking again. */ -extern void (*MEM_set_lock_callback)(void (*lock)(void), void (*unlock)(void)); - /** Attempt to enforce OSX (or other OS's) to have malloc and stack nonzero */ extern void (*MEM_set_memory_debug)(void); -/** - * Memory usage stats - * - MEM_get_memory_in_use is all memory - * - MEM_get_mapped_memory_in_use is a subset of all memory */ +/** Memory usage stats. */ extern size_t (*MEM_get_memory_in_use)(void); -/** Get mapped memory usage. */ -extern size_t (*MEM_get_mapped_memory_in_use)(void); /** Get amount of memory blocks in use. */ extern unsigned int (*MEM_get_memory_blocks_in_use)(void); diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c index d24437c85f2..e85f8eb03ed 100644 --- a/intern/guardedalloc/intern/mallocn.c +++ b/intern/guardedalloc/intern/mallocn.c @@ -48,18 +48,14 @@ void *(*MEM_malloc_arrayN)(size_t len, size_t size, const char *str) = MEM_lockf void *(*MEM_mallocN_aligned)(size_t len, size_t alignment, const char *str) = MEM_lockfree_mallocN_aligned; -void *(*MEM_mapallocN)(size_t len, const char *str) = MEM_lockfree_mapallocN; void (*MEM_printmemlist_pydict)(void) = MEM_lockfree_printmemlist_pydict; void (*MEM_printmemlist)(void) = MEM_lockfree_printmemlist; void (*MEM_callbackmemlist)(void (*func)(void *)) = MEM_lockfree_callbackmemlist; void (*MEM_printmemlist_stats)(void) = MEM_lockfree_printmemlist_stats; void (*MEM_set_error_callback)(void (*func)(const char *)) = MEM_lockfree_set_error_callback; bool (*MEM_consistency_check)(void) = MEM_lockfree_consistency_check; -void (*MEM_set_lock_callback)(void (*lock)(void), - void (*unlock)(void)) = MEM_lockfree_set_lock_callback; 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; -size_t (*MEM_get_mapped_memory_in_use)(void) = MEM_lockfree_get_mapped_memory_in_use; unsigned int (*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; @@ -111,17 +107,14 @@ void MEM_use_guarded_allocator(void) MEM_mallocN = MEM_guarded_mallocN; MEM_malloc_arrayN = MEM_guarded_malloc_arrayN; MEM_mallocN_aligned = MEM_guarded_mallocN_aligned; - MEM_mapallocN = MEM_guarded_mapallocN; MEM_printmemlist_pydict = MEM_guarded_printmemlist_pydict; MEM_printmemlist = MEM_guarded_printmemlist; MEM_callbackmemlist = MEM_guarded_callbackmemlist; MEM_printmemlist_stats = MEM_guarded_printmemlist_stats; MEM_set_error_callback = MEM_guarded_set_error_callback; MEM_consistency_check = MEM_guarded_consistency_check; - MEM_set_lock_callback = MEM_guarded_set_lock_callback; MEM_set_memory_debug = MEM_guarded_set_memory_debug; MEM_get_memory_in_use = MEM_guarded_get_memory_in_use; - MEM_get_mapped_memory_in_use = MEM_guarded_get_mapped_memory_in_use; MEM_get_memory_blocks_in_use = MEM_guarded_get_memory_blocks_in_use; MEM_reset_peak_memory = MEM_guarded_reset_peak_memory; MEM_get_peak_memory = MEM_guarded_get_peak_memory; diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c index f601609c6e0..20dcbed7235 100644 --- a/intern/guardedalloc/intern/mallocn_guarded_impl.c +++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c @@ -28,6 +28,8 @@ #include <string.h> /* memcpy */ #include <sys/types.h> +#include <pthread.h> + #include "MEM_guardedalloc.h" /* to ensure strict conversions */ @@ -51,17 +53,6 @@ //#define DEBUG_MEMCOUNTER /* Only for debugging: - * defining DEBUG_THREADS will enable check whether memory manager - * is locked with a mutex when allocation is called from non-main - * thread. - * - * This helps troubleshooting memory issues caused by the fact - * guarded allocator is not thread-safe, however this check will - * fail to check allocations from openmp threads. - */ -//#define DEBUG_THREADS - -/* Only for debugging: * Defining DEBUG_BACKTRACE will store a backtrace from where * memory block was allocated and print this trace for all * unfreed blocks. @@ -104,7 +95,7 @@ typedef struct MemHead { const char *name; const char *nextname; int tag2; - short mmap; /* if true, memory was mmapped */ + short pad1; short alignment; /* if non-zero aligned alloc was used * and alignment is stored here. */ @@ -124,24 +115,6 @@ typedef struct MemHead { typedef MemHead MemHeadAligned; -/* for openmp threading asserts, saves time troubleshooting - * we may need to extend this if blender code starts using MEM_ - * functions inside OpenMP correctly with omp_set_lock() */ - -#if 0 /* disable for now, only use to debug openmp code which doesn lock threads for malloc */ -# if defined(_OPENMP) && defined(DEBUG) -# include <assert.h> -# include <omp.h> -# define DEBUG_OMP_MALLOC -# endif -#endif - -#ifdef DEBUG_THREADS -# include <assert.h> -# include <pthread.h> -static pthread_t mainid; -#endif - #ifdef DEBUG_BACKTRACE # if defined(__linux__) || defined(__APPLE__) # include <execinfo.h> @@ -187,13 +160,11 @@ static const char *check_memlist(MemHead *memh); /* --------------------------------------------------------------------- */ static unsigned int totblock = 0; -static size_t mem_in_use = 0, mmap_in_use = 0, peak_mem = 0; +static size_t mem_in_use = 0, peak_mem = 0; static volatile struct localListBase _membase; static volatile struct localListBase *membase = &_membase; static void (*error_callback)(const char *) = NULL; -static void (*thread_lock_callback)(void) = NULL; -static void (*thread_unlock_callback)(void) = NULL; static bool malloc_debug_memset = false; @@ -233,40 +204,16 @@ print_error(const char *str, ...) fputs(buf, stderr); } +static pthread_mutex_t thread_lock = PTHREAD_MUTEX_INITIALIZER; + static void mem_lock_thread(void) { -#ifdef DEBUG_THREADS - static int initialized = 0; - - if (initialized == 0) { - /* assume first allocation happens from main thread */ - mainid = pthread_self(); - initialized = 1; - } - - if (!pthread_equal(pthread_self(), mainid) && thread_lock_callback == NULL) { - assert(!"Memory function is called from non-main thread without lock"); - } -#endif - -#ifdef DEBUG_OMP_MALLOC - assert(omp_in_parallel() == 0); -#endif - - if (thread_lock_callback) - thread_lock_callback(); + pthread_mutex_lock(&thread_lock); } static void mem_unlock_thread(void) { -#ifdef DEBUG_THREADS - if (!pthread_equal(pthread_self(), mainid) && thread_lock_callback == NULL) { - assert(!"Thread lock was removed while allocation from thread is in progress"); - } -#endif - - if (thread_unlock_callback) - thread_unlock_callback(); + pthread_mutex_unlock(&thread_lock); } bool MEM_guarded_consistency_check(void) @@ -287,12 +234,6 @@ void MEM_guarded_set_error_callback(void (*func)(const char *)) error_callback = func; } -void MEM_guarded_set_lock_callback(void (*lock)(void), void (*unlock)(void)) -{ - thread_lock_callback = lock; - thread_unlock_callback = unlock; -} - void MEM_guarded_set_memory_debug(void) { malloc_debug_memset = true; @@ -320,10 +261,8 @@ void *MEM_guarded_dupallocN(const void *vmemh) memh--; #ifndef DEBUG_MEMDUPLINAME - if (UNLIKELY(memh->mmap)) - newp = MEM_guarded_mapallocN(memh->len, "dupli_mapalloc"); - else if (LIKELY(memh->alignment == 0)) - newp = MEM_guarded_mapallocN(memh->len, "dupli_mapalloc"); + if (LIKELY(memh->alignment == 0)) + newp = MEM_guarded_mallocN(memh->len, "dupli_alloc"); else newp = MEM_guarded_mallocN_aligned(memh->len, (size_t)memh->alignment, "dupli_alloc"); @@ -334,11 +273,7 @@ void *MEM_guarded_dupallocN(const void *vmemh) MemHead *nmemh; char *name = malloc(strlen(memh->name) + 24); - if (UNLIKELY(memh->mmap)) { - sprintf(name, "%s %s", "dupli_mapalloc", memh->name); - newp = MEM_guarded_mapallocN(memh->len, name); - } - else if (LIKELY(memh->alignment == 0)) { + if (LIKELY(memh->alignment == 0)) { sprintf(name, "%s %s", "dupli_alloc", memh->name); newp = MEM_guarded_mallocN(memh->len, name); } @@ -478,7 +413,7 @@ static void make_memhead_header(MemHead *memh, size_t len, const char *str) memh->name = str; memh->nextname = NULL; memh->len = len; - memh->mmap = 0; + memh->pad1 = 0; memh->alignment = 0; memh->tag2 = MEMTAG2; @@ -646,58 +581,6 @@ void *MEM_guarded_calloc_arrayN(size_t len, size_t size, const char *str) return MEM_guarded_callocN(total_size, str); } -/* note; mmap returns zero'd memory */ -void *MEM_guarded_mapallocN(size_t len, const char *str) -{ - MemHead *memh; - - /* on 64 bit, simply use calloc instead, as mmap does not support - * allocating > 4 GB on Windows. the only reason mapalloc exists - * is to get around address space limitations in 32 bit OSes. */ - if (sizeof(void *) >= 8) - return MEM_guarded_callocN(len, str); - - len = SIZET_ALIGN_4(len); - -#if defined(WIN32) - /* our windows mmap implementation is not thread safe */ - mem_lock_thread(); -#endif - memh = mmap(NULL, - len + sizeof(MemHead) + sizeof(MemTail), - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON, - -1, - 0); -#if defined(WIN32) - mem_unlock_thread(); -#endif - - if (memh != (MemHead *)-1) { - make_memhead_header(memh, len, str); - memh->mmap = 1; - atomic_add_and_fetch_z(&mmap_in_use, len); - mem_lock_thread(); - peak_mem = mmap_in_use > peak_mem ? mmap_in_use : peak_mem; - mem_unlock_thread(); -#ifdef DEBUG_MEMCOUNTER - if (_mallocn_count == DEBUG_MEMCOUNTER_ERROR_VAL) - memcount_raise(__func__); - memh->_count = _mallocn_count++; -#endif - return (++memh); - } - else { - print_error( - "Mapalloc returns null, fallback to regular malloc: " - "len=" SIZET_FORMAT " in %s, total %u\n", - SIZET_ARG(len), - str, - (unsigned int)mmap_in_use); - return MEM_guarded_callocN(len, str); - } -} - /* Memory statistics print */ typedef struct MemPrintBlock { const char *name; @@ -765,7 +648,7 @@ void MEM_guarded_printmemlist_stats(void) pb++; #ifdef USE_MALLOC_USABLE_SIZE - if (!membl->mmap && membl->alignment == 0) { + if (membl->alignment == 0) { mem_in_use_slop += (sizeof(MemHead) + sizeof(MemTail) + malloc_usable_size((void *)membl)) - membl->len; } @@ -1098,27 +981,13 @@ static void rem_memblock(MemHead *memh) free((char *)memh->name); #endif - if (memh->mmap) { - atomic_sub_and_fetch_z(&mmap_in_use, memh->len); -#if defined(WIN32) - /* our windows mmap implementation is not thread safe */ - mem_lock_thread(); -#endif - if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail))) - printf("Couldn't unmap memory %s\n", memh->name); -#if defined(WIN32) - mem_unlock_thread(); -#endif + if (UNLIKELY(malloc_debug_memset && memh->len)) + memset(memh + 1, 255, memh->len); + if (LIKELY(memh->alignment == 0)) { + free(memh); } else { - if (UNLIKELY(malloc_debug_memset && memh->len)) - memset(memh + 1, 255, memh->len); - if (LIKELY(memh->alignment == 0)) { - free(memh); - } - else { - aligned_free(MEMHEAD_REAL_PTR(memh)); - } + aligned_free(MEMHEAD_REAL_PTR(memh)); } } @@ -1270,17 +1139,6 @@ size_t MEM_guarded_get_memory_in_use(void) return _mem_in_use; } -size_t MEM_guarded_get_mapped_memory_in_use(void) -{ - size_t _mmap_in_use; - - mem_lock_thread(); - _mmap_in_use = mmap_in_use; - mem_unlock_thread(); - - return _mmap_in_use; -} - unsigned int MEM_guarded_get_memory_blocks_in_use(void) { unsigned int _totblock; diff --git a/intern/guardedalloc/intern/mallocn_intern.h b/intern/guardedalloc/intern/mallocn_intern.h index 876607fdb77..ef8845a66b3 100644 --- a/intern/guardedalloc/intern/mallocn_intern.h +++ b/intern/guardedalloc/intern/mallocn_intern.h @@ -24,13 +24,6 @@ #ifndef __MALLOCN_INTERN_H__ #define __MALLOCN_INTERN_H__ -/* mmap exception */ -#if defined(WIN32) -# include "mmap_win.h" -#else -# include <sys/mman.h> -#endif - #ifdef __GNUC__ # define UNUSED(x) UNUSED_##x __attribute__((__unused__)) #else @@ -140,19 +133,14 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *UNUSED(str)) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3); -void *MEM_lockfree_mapallocN(size_t len, - const char *UNUSED(str)) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT - ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2); void MEM_lockfree_printmemlist_pydict(void); void MEM_lockfree_printmemlist(void); void MEM_lockfree_callbackmemlist(void (*func)(void *)); void MEM_lockfree_printmemlist_stats(void); void MEM_lockfree_set_error_callback(void (*func)(const char *)); bool MEM_lockfree_consistency_check(void); -void MEM_lockfree_set_lock_callback(void (*lock)(void), void (*unlock)(void)); void MEM_lockfree_set_memory_debug(void); size_t MEM_lockfree_get_memory_in_use(void); -size_t MEM_lockfree_get_mapped_memory_in_use(void); unsigned int MEM_lockfree_get_memory_blocks_in_use(void); void MEM_lockfree_reset_peak_memory(void); size_t MEM_lockfree_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT; @@ -188,19 +176,14 @@ void *MEM_guarded_mallocN_aligned(size_t len, size_t alignment, const char *UNUSED(str)) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3); -void *MEM_guarded_mapallocN(size_t len, - const char *UNUSED(str)) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT - ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2); void MEM_guarded_printmemlist_pydict(void); void MEM_guarded_printmemlist(void); void MEM_guarded_callbackmemlist(void (*func)(void *)); void MEM_guarded_printmemlist_stats(void); void MEM_guarded_set_error_callback(void (*func)(const char *)); bool MEM_guarded_consistency_check(void); -void MEM_guarded_set_lock_callback(void (*lock)(void), void (*unlock)(void)); void MEM_guarded_set_memory_debug(void); size_t MEM_guarded_get_memory_in_use(void); -size_t MEM_guarded_get_mapped_memory_in_use(void); unsigned int MEM_guarded_get_memory_blocks_in_use(void); void MEM_guarded_reset_peak_memory(void); size_t MEM_guarded_get_peak_memory(void) ATTR_WARN_UNUSED_RESULT; diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c index ab7d9097669..205cc688d72 100644 --- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c +++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c @@ -44,22 +44,18 @@ typedef struct MemHeadAligned { } MemHeadAligned; static unsigned int totblock = 0; -static size_t mem_in_use = 0, mmap_in_use = 0, peak_mem = 0; +static size_t mem_in_use = 0, peak_mem = 0; static bool malloc_debug_memset = false; static void (*error_callback)(const char *) = NULL; -static void (*thread_lock_callback)(void) = NULL; -static void (*thread_unlock_callback)(void) = NULL; enum { - MEMHEAD_MMAP_FLAG = 1, - MEMHEAD_ALIGN_FLAG = 2, + MEMHEAD_ALIGN_FLAG = 1, }; #define MEMHEAD_FROM_PTR(ptr) (((MemHead *)ptr) - 1) #define PTR_FROM_MEMHEAD(memhead) (memhead + 1) #define MEMHEAD_ALIGNED_FROM_PTR(ptr) (((MemHeadAligned *)ptr) - 1) -#define MEMHEAD_IS_MMAP(memhead) ((memhead)->len & (size_t)MEMHEAD_MMAP_FLAG) #define MEMHEAD_IS_ALIGNED(memhead) ((memhead)->len & (size_t)MEMHEAD_ALIGN_FLAG) /* Uncomment this to have proper peak counter. */ @@ -93,24 +89,10 @@ print_error(const char *str, ...) } } -#if defined(WIN32) -static void mem_lock_thread(void) -{ - if (thread_lock_callback) - thread_lock_callback(); -} - -static void mem_unlock_thread(void) -{ - if (thread_unlock_callback) - thread_unlock_callback(); -} -#endif - size_t MEM_lockfree_allocN_len(const void *vmemh) { if (vmemh) { - return MEMHEAD_FROM_PTR(vmemh)->len & ~((size_t)(MEMHEAD_MMAP_FLAG | MEMHEAD_ALIGN_FLAG)); + return MEMHEAD_FROM_PTR(vmemh)->len & ~((size_t)(MEMHEAD_ALIGN_FLAG)); } else { return 0; @@ -133,29 +115,15 @@ void MEM_lockfree_freeN(void *vmemh) atomic_sub_and_fetch_u(&totblock, 1); atomic_sub_and_fetch_z(&mem_in_use, len); - if (MEMHEAD_IS_MMAP(memh)) { - atomic_sub_and_fetch_z(&mmap_in_use, len); -#if defined(WIN32) - /* our windows mmap implementation is not thread safe */ - mem_lock_thread(); -#endif - if (munmap(memh, len + sizeof(MemHead))) - printf("Couldn't unmap memory\n"); -#if defined(WIN32) - mem_unlock_thread(); -#endif + if (UNLIKELY(malloc_debug_memset && len)) { + memset(memh + 1, 255, len); + } + if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) { + MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh); + aligned_free(MEMHEAD_REAL_PTR(memh_aligned)); } else { - if (UNLIKELY(malloc_debug_memset && len)) { - memset(memh + 1, 255, len); - } - if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) { - MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh); - aligned_free(MEMHEAD_REAL_PTR(memh_aligned)); - } - else { - free(memh); - } + free(memh); } } @@ -165,10 +133,7 @@ void *MEM_lockfree_dupallocN(const void *vmemh) if (vmemh) { MemHead *memh = MEMHEAD_FROM_PTR(vmemh); const size_t prev_size = MEM_lockfree_allocN_len(vmemh); - if (UNLIKELY(MEMHEAD_IS_MMAP(memh))) { - newp = MEM_lockfree_mapallocN(prev_size, "dupli_mapalloc"); - } - else if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) { + if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) { MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh); newp = MEM_lockfree_mallocN_aligned( prev_size, (size_t)memh_aligned->alignment, "dupli_malloc"); @@ -397,47 +362,6 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str return NULL; } -void *MEM_lockfree_mapallocN(size_t len, const char *str) -{ - MemHead *memh; - - /* on 64 bit, simply use calloc instead, as mmap does not support - * allocating > 4 GB on Windows. the only reason mapalloc exists - * is to get around address space limitations in 32 bit OSes. */ - if (sizeof(void *) >= 8) - return MEM_lockfree_callocN(len, str); - - len = SIZET_ALIGN_4(len); - -#if defined(WIN32) - /* our windows mmap implementation is not thread safe */ - mem_lock_thread(); -#endif - memh = mmap(NULL, len + sizeof(MemHead), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); -#if defined(WIN32) - mem_unlock_thread(); -#endif - - if (memh != (MemHead *)-1) { - memh->len = len | (size_t)MEMHEAD_MMAP_FLAG; - atomic_add_and_fetch_u(&totblock, 1); - atomic_add_and_fetch_z(&mem_in_use, len); - atomic_add_and_fetch_z(&mmap_in_use, len); - - update_maximum(&peak_mem, mem_in_use); - update_maximum(&peak_mem, mmap_in_use); - - return PTR_FROM_MEMHEAD(memh); - } - print_error( - "Mapalloc returns null, fallback to regular malloc: " - "len=" SIZET_FORMAT " in %s, total %u\n", - SIZET_ARG(len), - str, - (unsigned int)mmap_in_use); - return MEM_lockfree_callocN(len, str); -} - void MEM_lockfree_printmemlist_pydict(void) { } @@ -476,12 +400,6 @@ bool MEM_lockfree_consistency_check(void) return true; } -void MEM_lockfree_set_lock_callback(void (*lock)(void), void (*unlock)(void)) -{ - thread_lock_callback = lock; - thread_unlock_callback = unlock; -} - void MEM_lockfree_set_memory_debug(void) { malloc_debug_memset = true; @@ -492,11 +410,6 @@ size_t MEM_lockfree_get_memory_in_use(void) return mem_in_use; } -size_t MEM_lockfree_get_mapped_memory_in_use(void) -{ - return mmap_in_use; -} - unsigned int MEM_lockfree_get_memory_blocks_in_use(void) { return totblock; diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 11ce32fb828..95013958561 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -81,6 +81,7 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) mUsingNoise = (mds->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke; mUsingFractions = (mds->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid; mUsingMesh = (mds->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid; + mUsingDiffusion = (mds->flags & FLUID_DOMAIN_USE_DIFFUSION) && mUsingLiquid; mUsingMVel = (mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid; mUsingGuiding = (mds->flags & FLUID_DOMAIN_USE_GUIDE); mUsingDrops = (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid; @@ -230,6 +231,10 @@ MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID) initLiquidMesh(); } + if (mUsingDiffusion) { + initCurvature(); + } + if (mUsingGuiding) { mResGuiding = (mds->guide_parent) ? mds->guide_res : mds->res; initGuiding(); @@ -438,6 +443,16 @@ void MANTA::initLiquidMesh(FluidModifierData *mmd) mUsingMesh = true; } +void MANTA::initCurvature(FluidModifierData *mmd) +{ + std::vector<std::string> pythonCommands; + std::string finalString = parseScript(liquid_alloc_curvature, mmd); + pythonCommands.push_back(finalString); + + runPythonString(pythonCommands); + mUsingDiffusion = true; +} + void MANTA::initObstacle(FluidModifierData *mmd) { if (!mPhiObsIn) { @@ -549,7 +564,7 @@ MANTA::~MANTA() result = runPythonString(pythonCommands); assert(result); - (void)result; // not needed in release + UNUSED_VARS(result); } /** @@ -574,8 +589,8 @@ bool MANTA::runPythonString(vector<string> commands) manta_main_module = PyImport_ImportModule("__main__"); } - for (vector<std::string>::iterator it = commands.begin(); it != commands.end(); ++it) { - std::string command = *it; + for (vector<string>::iterator it = commands.begin(); it != commands.end(); ++it) { + string command = *it; PyObject *globals_dict = PyModule_GetDict(manta_main_module); PyObject *return_value = PyRun_String( @@ -843,6 +858,23 @@ void MANTA::initializeRNAMap(FluidModifierData *mmd) mRNAMap["GRAVITY_Y"] = to_string(mds->gravity[1]); mRNAMap["GRAVITY_Z"] = to_string(mds->gravity[2]); mRNAMap["CACHE_DIR"] = cacheDirectory; + mRNAMap["NAME_DENSITY"] = FLUID_GRIDNAME_DENSITY; + mRNAMap["NAME_SHADOW"] = FLUID_GRIDNAME_SHADOW; + mRNAMap["NAME_HEAT"] = FLUID_GRIDNAME_HEAT; + mRNAMap["NAME_VELOCITY"] = FLUID_GRIDNAME_VELOCITY; + mRNAMap["NAME_COLORR"] = FLUID_GRIDNAME_COLORR; + mRNAMap["NAME_COLORG"] = FLUID_GRIDNAME_COLORG; + mRNAMap["NAME_COLORB"] = FLUID_GRIDNAME_COLORB; + mRNAMap["NAME_FLAME"] = FLUID_GRIDNAME_FLAME; + mRNAMap["NAME_FUEL"] = FLUID_GRIDNAME_FUEL; + mRNAMap["NAME_REACT"] = FLUID_GRIDNAME_REACT; + mRNAMap["NAME_DENSITYNOISE"] = FLUID_GRIDNAME_DENSITYNOISE; + mRNAMap["NAME_COLORRNOISE"] = FLUID_GRIDNAME_COLORRNOISE; + mRNAMap["NAME_COLORGNOISE"] = FLUID_GRIDNAME_COLORGNOISE; + mRNAMap["NAME_COLORBNOISE"] = FLUID_GRIDNAME_COLORBNOISE; + mRNAMap["NAME_FLAMENOISE"] = FLUID_GRIDNAME_FLAMENOISE; + mRNAMap["NAME_FUELNOISE"] = FLUID_GRIDNAME_FUELNOISE; + mRNAMap["NAME_REACTNOISE"] = FLUID_GRIDNAME_REACTNOISE; } string MANTA::getRealValue(const string &varName) @@ -933,8 +965,7 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) mFlipParticleVelocity->clear(); string pformat = getCacheFileEnding(mds->cache_particle_format); - string file = getFile( - mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_PP, pformat.c_str(), framenr); + string file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_PP, pformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { @@ -942,7 +973,7 @@ bool MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr) assert(result == expected); } - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_PVEL, pformat.c_str(), framenr); + file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_PVEL, pformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { result += updateParticlesFromFile(file, false, true); @@ -980,7 +1011,7 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) string mformat = getCacheFileEnding(mds->cache_mesh_format); string dformat = getCacheFileEnding(mds->cache_data_format); - string file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, mformat, framenr); + string file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_FILENAME_MESH, mformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { @@ -989,7 +1020,7 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) } if (mUsingMVel) { - file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESHVEL, dformat, framenr); + file = getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_FILENAME_MESHVEL, dformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { result += updateMeshFromFile(file); @@ -1025,8 +1056,7 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) mSndParticleLife->clear(); string pformat = getCacheFileEnding(mds->cache_particle_format); - string file = getFile( - mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PPSND, pformat, framenr); + string file = getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_FILENAME_PPSND, pformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { @@ -1034,14 +1064,14 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) assert(result == expected); } - file = getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PVELSND, pformat, framenr); + file = getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_FILENAME_PVELSND, pformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { result += updateParticlesFromFile(file, true, true); assert(result == expected); } - file = getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PLIFESND, pformat, framenr); + file = getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_FILENAME_PLIFESND, pformat, framenr); expected += 1; if (BLI_exists(file.c_str())) { result += updateParticlesFromFile(file, true, false); @@ -1051,6 +1081,26 @@ bool MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr) return mParticlesFromFile = (result == expected); } +static void assertGridItems(vector<MANTA::GridItem> gList) +{ + vector<MANTA::GridItem>::iterator gIter = gList.begin(); + int *resPrev = (*gIter).res; + + for (vector<MANTA::GridItem>::iterator it = gList.begin(); it != gList.end(); ++it) { + MANTA::GridItem item = *it; + assert( + ELEM(item.type, FLUID_DOMAIN_GRID_FLOAT, FLUID_DOMAIN_GRID_INT, FLUID_DOMAIN_GRID_VEC3F)); + assert(item.pointer[0]); + if (item.type == FLUID_DOMAIN_GRID_VEC3F) { + assert(item.pointer[1] && item.pointer[2]); + } + assert(item.res[0] == resPrev[0] && item.res[1] == resPrev[1] && item.res[2] == resPrev[2]); + assert((item.name).compare("") != 0); + } + + UNUSED_VARS(resPrev); +} + bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) { if (MANTA::with_debug) @@ -1065,80 +1115,106 @@ bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) return false; int result = 0; - int expected = 0; /* Expected number of read successes for this frame. */ - string dformat = getCacheFileEnding(mds->cache_data_format); - string file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_DENSITY, dformat, framenr); - - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mDensity, false); - assert(result == expected); - } - - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_SHADOW, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mShadow, false); - assert(result == expected); - } - if (mUsingHeat) { - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_HEAT, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mHeat, false); - assert(result == expected); + vector<FileItem> filesData; + vector<GridItem> gridsData; + + int res[] = {mResX, mResY, mResZ}; + + /* Put grid pointers into pointer lists, some grids have more than 1 pointer. */ + void *aDensity[] = {mDensity}; + void *aShadow[] = {mShadow}; + void *aVelocities[] = {mVelocityX, mVelocityY, mVelocityZ}; + void *aHeat[] = {mHeat}; + void *aColorR[] = {mColorR}; + void *aColorG[] = {mColorG}; + void *aColorB[] = {mColorB}; + void *aFlame[] = {mFlame}; + void *aFuel[] = {mFuel}; + void *aReact[] = {mReact}; + + /* File names for grids. */ + string fDensity = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_DENSITY, dformat, framenr); + string fShadow = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_SHADOW, dformat, framenr); + string fVel = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_VELOCITY, dformat, framenr); + string fHeat = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_HEAT, dformat, framenr); + string fColorR = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_COLORR, dformat, framenr); + string fColorG = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_COLORG, dformat, framenr); + string fColorB = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_COLORB, dformat, framenr); + string fFlame = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_FLAME, dformat, framenr); + string fFuel = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_FUEL, dformat, framenr); + string fReact = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_REACT, dformat, framenr); + string fFluid = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_DATA, dformat, framenr); + + /* Prepare grid info containers. */ + GridItem gDensity = {aDensity, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_DENSITY}; + GridItem gShadow = {aShadow, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_SHADOW}; + GridItem gVel = {aVelocities, FLUID_DOMAIN_GRID_VEC3F, res, FLUID_GRIDNAME_VELOCITY}; + GridItem gHeat = {aHeat, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_HEAT}; + GridItem gColorR = {aColorR, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_COLORR}; + GridItem gColorG = {aColorG, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_COLORG}; + GridItem gColorB = {aColorB, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_COLORB}; + GridItem gFlame = {aFlame, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_FLAME}; + GridItem gFuel = {aFuel, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_FUEL}; + GridItem gReact = {aReact, FLUID_DOMAIN_GRID_FLOAT, res, FLUID_GRIDNAME_REACT}; + + /* TODO (sebbas): For now, only allow single file mode. Combined grid file export is todo. */ + const int fileMode = FLUID_DOMAIN_CACHE_FILES_SINGLE; + if (fileMode == FLUID_DOMAIN_CACHE_FILES_SINGLE) { + + filesData.push_back({fDensity, {gDensity}}); + filesData.push_back({fShadow, {gShadow}}); + filesData.push_back({fVel, {gVel}}); + if (mUsingHeat) { + filesData.push_back({fHeat, {gHeat}}); } - } - - if (mUsingColors) { - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_COLORR, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mColorR, false); - assert(result == expected); - } - - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_COLORG, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mColorG, false); - assert(result == expected); + if (mUsingColors) { + filesData.push_back({fColorR, {gColorR}}); + filesData.push_back({fColorG, {gColorG}}); + filesData.push_back({fColorB, {gColorB}}); } - - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_COLORB, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mColorB, false); - assert(result == expected); + if (mUsingFire) { + filesData.push_back({fFlame, {gFlame}}); + filesData.push_back({fFuel, {gFuel}}); + filesData.push_back({fReact, {gReact}}); } } + else if (fileMode == FLUID_DOMAIN_CACHE_FILES_COMBINED) { - if (mUsingFire) { - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_FLAME, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mFlame, false); - assert(result == expected); + gridsData.push_back(gDensity); + gridsData.push_back(gShadow); + gridsData.push_back(gVel); + if (mUsingHeat) { + gridsData.push_back(gHeat); + } + if (mUsingColors) { + gridsData.push_back(gColorR); + gridsData.push_back(gColorG); + gridsData.push_back(gColorB); + } + if (mUsingFire) { + gridsData.push_back(gFlame); + gridsData.push_back(gFuel); + gridsData.push_back(gReact); } - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_FUEL, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mFuel, false); - assert(result == expected); + if (with_debug) { + assertGridItems(gridsData); } + filesData.push_back({fFluid, gridsData}); + } - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_REACT, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mReact, false); - assert(result == expected); + /* Update files from data directory. */ + for (vector<FileItem>::iterator it = filesData.begin(); it != filesData.end(); ++it) { + FileItem item = *it; + if (BLI_exists(item.filename.c_str())) { + result += updateGridsFromFile(item.filename, item.grids); + assert(result); } } - return mSmokeFromFile = (result == expected); + return mSmokeFromFile = result; } bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) @@ -1155,73 +1231,121 @@ bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) return false; int result = 0; - int expected = 0; /* Expected number of read successes for this frame. */ - string dformat = getCacheFileEnding(mds->cache_data_format); string nformat = getCacheFileEnding(mds->cache_noise_format); - string file = getFile( - mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_DENSITYNOISE, nformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mDensityHigh, true); - assert(result == expected); + vector<FileItem> filesData, filesNoise; + vector<GridItem> gridsData, gridsNoise; + + int resData[] = {mResX, mResY, mResZ}; + int resNoise[] = {mResXNoise, mResYNoise, mResZNoise}; + + /* Put grid pointers into pointer lists, some grids have more than 1 pointer. */ + void *aShadow[] = {mShadow}; + void *aVelocities[] = {mVelocityX, mVelocityY, mVelocityZ}; + void *aDensity[] = {mDensityHigh}; + void *aColorR[] = {mColorRHigh}; + void *aColorG[] = {mColorGHigh}; + void *aColorB[] = {mColorBHigh}; + void *aFlame[] = {mFlameHigh}; + void *aFuel[] = {mFuelHigh}; + void *aReact[] = {mReactHigh}; + + /* File names for grids. */ + string fShadow = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_SHADOW, dformat, framenr); + string fVel = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_FILENAME_VELOCITY, dformat, framenr); + string fFluid = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_DATA, dformat, framenr); + + string fDensity = getFile( + mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_DENSITYNOISE, nformat, framenr); + string fColorR = getFile( + mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_COLORRNOISE, nformat, framenr); + string fColorG = getFile( + mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_COLORGNOISE, nformat, framenr); + string fColorB = getFile( + mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_COLORBNOISE, nformat, framenr); + string fFlame = getFile( + mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_FLAMENOISE, nformat, framenr); + string fFuel = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_FUELNOISE, nformat, framenr); + string fReact = getFile( + mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_REACTNOISE, nformat, framenr); + string fNoise = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_NOISE, nformat, framenr); + + /* Prepare grid info containers. */ + GridItem gShadow = {aShadow, FLUID_DOMAIN_GRID_FLOAT, resData, FLUID_GRIDNAME_SHADOW}; + GridItem gVel = {aVelocities, FLUID_DOMAIN_GRID_VEC3F, resData, FLUID_GRIDNAME_VELOCITY}; + + GridItem gDensity = {aDensity, FLUID_DOMAIN_GRID_FLOAT, resNoise, FLUID_GRIDNAME_DENSITYNOISE}; + GridItem gColorR = {aColorR, FLUID_DOMAIN_GRID_FLOAT, resNoise, FLUID_GRIDNAME_COLORRNOISE}; + GridItem gColorG = {aColorG, FLUID_DOMAIN_GRID_FLOAT, resNoise, FLUID_GRIDNAME_COLORGNOISE}; + GridItem gColorB = {aColorB, FLUID_DOMAIN_GRID_FLOAT, resNoise, FLUID_GRIDNAME_COLORBNOISE}; + GridItem gFlame = {aFlame, FLUID_DOMAIN_GRID_FLOAT, resNoise, FLUID_GRIDNAME_FLAMENOISE}; + GridItem gFuel = {aFuel, FLUID_DOMAIN_GRID_FLOAT, resNoise, FLUID_GRIDNAME_FUELNOISE}; + GridItem gReact = {aReact, FLUID_DOMAIN_GRID_FLOAT, resNoise, FLUID_GRIDNAME_REACTNOISE}; + + /* TODO (sebbas): For now, only allow single file mode. Combined grid file export is todo. */ + const int fileMode = FLUID_DOMAIN_CACHE_FILES_SINGLE; + if (fileMode == FLUID_DOMAIN_CACHE_FILES_SINGLE) { + + filesData.push_back({fShadow, {gShadow}}); + filesData.push_back({fVel, {gVel}}); + + filesNoise.push_back({fDensity, {gDensity}}); + if (mUsingColors) { + filesNoise.push_back({fColorR, {gColorR}}); + filesNoise.push_back({fColorG, {gColorG}}); + filesNoise.push_back({fColorB, {gColorB}}); + } + if (mUsingFire) { + filesNoise.push_back({fFlame, {gFlame}}); + filesNoise.push_back({fFuel, {gFuel}}); + filesNoise.push_back({fReact, {gReact}}); + } } + else if (fileMode == FLUID_DOMAIN_CACHE_FILES_COMBINED) { - file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_SHADOW, dformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mShadow, false); - assert(result == expected); - } + gridsData.push_back(gShadow); + gridsData.push_back(gVel); - if (mUsingColors) { - file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_COLORRNOISE, nformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mColorRHigh, true); - assert(result == expected); + gridsNoise.push_back(gDensity); + if (mUsingColors) { + gridsNoise.push_back(gColorR); + gridsNoise.push_back(gColorG); + gridsNoise.push_back(gColorB); } - - file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_COLORGNOISE, nformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mColorGHigh, true); - assert(result == expected); + if (mUsingFire) { + gridsNoise.push_back(gFlame); + gridsNoise.push_back(gFuel); + gridsNoise.push_back(gReact); } - file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_COLORBNOISE, nformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mColorBHigh, true); - assert(result == expected); + if (with_debug) { + assertGridItems(gridsData); + assertGridItems(gridsNoise); } + filesData.push_back({fFluid, gridsData}); + filesNoise.push_back({fNoise, gridsNoise}); } - if (mUsingFire) { - file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_FLAMENOISE, nformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mFlameHigh, true); - assert(result == expected); - } - - file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_FUELNOISE, nformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mFuelHigh, true); - assert(result == expected); + /* Update files from data directory. */ + for (vector<FileItem>::iterator it = filesData.begin(); it != filesData.end(); ++it) { + FileItem item = *it; + if (BLI_exists(item.filename.c_str())) { + result += updateGridsFromFile(item.filename, item.grids); + assert(result); } + } - file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_REACTNOISE, nformat, framenr); - expected += 1; - if (BLI_exists(file.c_str())) { - result += updateGridFromFile(file, mReactHigh, true); - assert(result == expected); + /* Update files from noise directory. */ + for (vector<FileItem>::iterator it = filesNoise.begin(); it != filesNoise.end(); ++it) { + FileItem item = *it; + if (BLI_exists(item.filename.c_str())) { + result += updateGridsFromFile(item.filename, item.grids); + assert(result); } } - return mNoiseFromFile = (result == expected); + return mNoiseFromFile = result; } /* Dirty hack: Needed to format paths from python code that is run via PyRun_SimpleString */ @@ -1247,7 +1371,7 @@ bool MANTA::writeConfiguration(FluidModifierData *mmd, int framenr) string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG); string format = FLUID_DOMAIN_EXTENSION_UNI; - string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr); + string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_FILENAME_CONFIG, format, framenr); /* Create 'config' subdir if it does not exist already. */ BLI_dir_create_recursive(directory.c_str()); @@ -1347,7 +1471,7 @@ bool MANTA::readConfiguration(FluidModifierData *mmd, int framenr) string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_CONFIG); string format = FLUID_DOMAIN_EXTENSION_UNI; - string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, format, framenr); + string file = getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_FILENAME_CONFIG, format, framenr); if (!hasConfig(mmd, framenr)) return false; @@ -2741,14 +2865,13 @@ bool MANTA::updateParticlesFromUni(string filename, bool isSecondarySys, bool is return (gzclose(gzf) == Z_OK); } -bool MANTA::updateGridFromFile(string filename, float *grid, bool isNoise) +bool MANTA::updateGridsFromFile(string filename, vector<GridItem> grids) { if (with_debug) - cout << "MANTA::updateGridFromFile()" << endl; + cout << "MANTA::updateGridsFromFile()" << endl; - if (!grid) { - cerr << "Fluid Error -- updateGridFromFile(): Cannot read into uninitialized grid (grid " - "is null)." + if (grids.empty()) { + cerr << "Fluid Error -- updateGridsFromFile(): Cannot read into uninitialized grid vector." << endl; return false; } @@ -2758,118 +2881,142 @@ bool MANTA::updateGridFromFile(string filename, float *grid, bool isNoise) idx = fname.rfind('.'); if (idx != string::npos) { - string extension = fname.substr(idx + 1); + string extension = fname.substr(idx); - if (extension.compare("uni") == 0) - return updateGridFromUni(filename, grid, isNoise); + if (extension.compare(FLUID_DOMAIN_EXTENSION_UNI) == 0) { + return updateGridsFromUni(filename, grids); + } #if OPENVDB == 1 - else if (extension.compare("vdb") == 0) - return updateGridFromVDB(filename, grid, isNoise); + else if (extension.compare(FLUID_DOMAIN_EXTENSION_OPENVDB) == 0) { + return updateGridsFromVDB(filename, grids); + } #endif - else if (extension.compare("raw") == 0) - return updateGridFromRaw(filename, grid, isNoise); - else - cerr << "Fluid Error -- updateGridFromFile(): Invalid file extension in file: " << filename + else if (extension.compare(FLUID_DOMAIN_EXTENSION_RAW) == 0) { + return updateGridsFromRaw(filename, grids); + } + else { + cerr << "Fluid Error -- updateGridsFromFile(): Invalid file extension in file: " << filename << endl; + } return false; } else { - cerr << "Fluid Error -- updateGridFromFile(): Unable to open file: " << filename << endl; + cerr << "Fluid Error -- updateGridsFromFile(): Unable to open file: " << filename << endl; return false; } } -bool MANTA::updateGridFromUni(string filename, float *grid, bool isNoise) +bool MANTA::updateGridsFromUni(string filename, vector<GridItem> grids) { if (with_debug) - cout << "MANTA::updateGridFromUni()" << endl; + cout << "MANTA::updateGridsFromUni()" << endl; gzFile gzf; + int expectedBytes = 0, readBytes = 0; int ibuffer[4]; gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb1"); if (!gzf) { - cerr << "Fluid Error -- updateGridFromUni(): Unable to open file: " << filename << endl; + cerr << "Fluid Error -- updateGridsFromUni(): Unable to open file: " << filename << endl; return false; } - int readBytes = 0; char file_magic[5] = {0, 0, 0, 0, 0}; readBytes = gzread(gzf, file_magic, 4); if (!readBytes) { - cerr << "Fluid Error -- updateGridFromUni(): Unable to read header in file: " << filename - << endl; - gzclose(gzf); - return false; - } - - if (!strcmp(file_magic, "DDF2")) { - cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format DDF2 not supported anymore." - << endl; - gzclose(gzf); - return false; - } - - if (!strcmp(file_magic, "MNT1")) { - cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT1 not supported anymore." - << endl; + cerr << "Fluid Error -- updateGridsFromUni(): Invalid header in file: " << filename << endl; gzclose(gzf); return false; } - - if (!strcmp(file_magic, "MNT2")) { - cerr << "Fluid Error -- updateGridFromUni(): Grid uni file format MNT2 not supported anymore." + if (!strcmp(file_magic, "DDF2") || !strcmp(file_magic, "MNT1") || !strcmp(file_magic, "MNT2")) { + cerr << "Fluid Error -- updateGridsFromUni(): Unsupported header in file: " << filename << endl; gzclose(gzf); return false; } - // grid uni header - const int STR_LEN_GRID = 252; - int elementType, bytesPerElement; // data type info - char info[STR_LEN_GRID]; // mantaflow build information - int dimT; // optionally store forth dimension for 4d grids - unsigned long long timestamp; // creation time + if (!strcmp(file_magic, "MNT3")) { - // read grid header - gzread(gzf, &ibuffer, sizeof(int) * 4); // dimX, dimY, dimZ, gridType - gzread(gzf, &elementType, sizeof(int)); - gzread(gzf, &bytesPerElement, sizeof(int)); - gzread(gzf, &info, sizeof(info)); - gzread(gzf, &dimT, sizeof(int)); - gzread(gzf, ×tamp, sizeof(unsigned long long)); + // grid uni header + const int STR_LEN_GRID = 252; + int elementType, bytesPerElement; // data type info + char info[STR_LEN_GRID]; // mantaflow build information + int dimT; // optionally store forth dimension for 4d grids + unsigned long long timestamp; // creation time + + // read grid header + gzread(gzf, &ibuffer, sizeof(int) * 4); // dimX, dimY, dimZ, gridType + gzread(gzf, &elementType, sizeof(int)); + gzread(gzf, &bytesPerElement, sizeof(int)); + gzread(gzf, &info, sizeof(info)); + gzread(gzf, &dimT, sizeof(int)); + gzread(gzf, ×tamp, sizeof(unsigned long long)); - int resX = (isNoise) ? mResXNoise : mResX; - int resY = (isNoise) ? mResYNoise : mResY; - int resZ = (isNoise) ? mResZNoise : mResZ; + if (with_debug) + cout << "Fluid: Read " << ibuffer[3] << " grid type in file: " << filename << endl; + + for (vector<GridItem>::iterator gIter = grids.begin(); gIter != grids.end(); ++gIter) { + GridItem gridItem = *gIter; + void **pointerList = gridItem.pointer; + int type = gridItem.type; + int *res = gridItem.res; + assert(pointerList[0]); + assert(res[0] == res[0] && res[1] == res[1] && res[2] == res[2]); + UNUSED_VARS(res); + + switch (type) { + case FLUID_DOMAIN_GRID_VEC3F: { + assert(pointerList[1] && pointerList[2]); + float **fpointers = (float **)pointerList; + expectedBytes = sizeof(float) * 3 * ibuffer[0] * ibuffer[1] * ibuffer[2]; + readBytes = 0; + for (int i = 0; i < ibuffer[0] * ibuffer[1] * ibuffer[2]; ++i) { + for (int j = 0; j < 3; ++j) { + readBytes += gzread(gzf, fpointers[j], sizeof(float)); + ++fpointers[j]; + } + } + break; + } + case FLUID_DOMAIN_GRID_FLOAT: { + float **fpointers = (float **)pointerList; + expectedBytes = sizeof(float) * ibuffer[0] * ibuffer[1] * ibuffer[2]; + readBytes = gzread( + gzf, fpointers[0], sizeof(float) * ibuffer[0] * ibuffer[1] * ibuffer[2]); + break; + } + default: { + cerr << "Fluid Error -- Unknown grid type" << endl; + } + } - if (with_debug) - cout << "Fluid: Read " << ibuffer[3] << " grid type in file: " << filename << endl; + if (!readBytes) { + cerr << "Fluid Error -- updateGridFromRaw(): Unable to read raw file: " << filename + << endl; + gzclose(gzf); + return false; + } + assert(expectedBytes == readBytes); + UNUSED_VARS(expectedBytes); - // Sanity checks - if (ibuffer[0] != resX || ibuffer[1] != resY || ibuffer[2] != resZ) { - cout << "Fluid: Grid dim doesn't match, read: (" << ibuffer[0] << ", " << ibuffer[1] << ", " - << ibuffer[2] << ") vs setup: (" << resX << ", " << resY << ", " << resZ << ")" << endl; + if (with_debug) + cout << "Fluid: Read successfully: " << filename << endl; + } + } + else { + cerr << "Fluid Error -- updateGridsFromUni(): Unknown header in file: " << filename << endl; gzclose(gzf); return false; } - // Actual data reading - if (!strcmp(file_magic, "MNT3")) { - gzread(gzf, grid, sizeof(float) * ibuffer[0] * ibuffer[1] * ibuffer[2]); - } - - if (with_debug) - cout << "Fluid: Read successfully: " << filename << endl; - return (gzclose(gzf) == Z_OK); } #if OPENVDB == 1 -bool MANTA::updateGridFromVDB(string filename, float *grid, bool isNoise) +bool MANTA::updateGridsFromVDB(string filename, vector<GridItem> grids) { if (with_debug) - cout << "MANTA::updateGridFromVDB()" << endl; + cout << "MANTA::updateGridsFromVDB()" << endl; openvdb::initialize(); openvdb::io::File file(filename); @@ -2877,66 +3024,191 @@ bool MANTA::updateGridFromVDB(string filename, float *grid, bool isNoise) file.open(); } catch (const openvdb::IoError &) { - cerr << "Fluid Error -- updateGridFromVDB(): IOError, invalid OpenVDB file: " << filename + cerr << "Fluid Error -- updateGridsFromVDB(): IOError, invalid OpenVDB file: " << filename << endl; return false; } + if (grids.empty()) { + cerr << "Fluid Error -- updateGridsFromVDB(): No grids found in grid vector" << endl; + return false; + } + unordered_map<string, openvdb::FloatGrid::Accessor> floatAccessors; + unordered_map<string, openvdb::Vec3SGrid::Accessor> vec3fAccessors; openvdb::GridBase::Ptr baseGrid; - for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); - ++nameIter) { - baseGrid = file.readGrid(nameIter.gridName()); - break; + + /* Get accessors to all grids in this OpenVDB file.*/ + for (vector<GridItem>::iterator gIter = grids.begin(); gIter != grids.end(); ++gIter) { + GridItem gridItem = *gIter; + string itemName = gridItem.name; + int itemType = gridItem.type; + + for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); + ++nameIter) { + string vdbName = nameIter.gridName(); + bool nameMatch = !itemName.compare(vdbName); + + /* Support for <= 2.83: If file has only one grid in it, use that grid. */ + openvdb::io::File::NameIterator peekNext = nameIter; + bool onlyGrid = (++peekNext == file.endName()); + if (onlyGrid) { + vdbName = itemName; + } + + if (nameMatch || onlyGrid) { + baseGrid = file.readGrid(nameIter.gridName()); + + switch (itemType) { + case FLUID_DOMAIN_GRID_VEC3F: { + openvdb::Vec3SGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::Vec3SGrid>(baseGrid); + openvdb::Vec3SGrid::Accessor vdbAccessor = gridVDB->getAccessor(); + vec3fAccessors.emplace(vdbName, vdbAccessor); + break; + } + case FLUID_DOMAIN_GRID_FLOAT: { + openvdb::FloatGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::FloatGrid>(baseGrid); + openvdb::FloatGrid::Accessor vdbAccessor = gridVDB->getAccessor(); + floatAccessors.emplace(vdbName, vdbAccessor); + break; + } + default: { + cerr << "Fluid Error -- Unknown grid type" << endl; + } + } + } + else { + cerr << "Fluid Error -- Could not read grid from file" << endl; + return false; + } + } } file.close(); - openvdb::FloatGrid::Ptr gridVDB = openvdb::gridPtrCast<openvdb::FloatGrid>(baseGrid); - openvdb::FloatGrid::Accessor accessor = gridVDB->getAccessor(); - - int resX = (isNoise) ? mResXNoise : mResX; - int resY = (isNoise) ? mResYNoise : mResY; - int resZ = (isNoise) ? mResZNoise : mResZ; size_t index = 0; - for (int z = 0; z < resZ; ++z) { - for (int y = 0; y < resY; ++y) { - for (int x = 0; x < resX; ++x, ++index) { + + /* Use res of first grid for grid loop. All grids must be same size anyways. */ + vector<GridItem>::iterator gIter = grids.begin(); + int *res = (*gIter).res; + + for (int z = 0; z < res[2]; ++z) { + for (int y = 0; y < res[1]; ++y) { + for (int x = 0; x < res[0]; ++x, ++index) { openvdb::Coord xyz(x, y, z); - float v = accessor.getValue(xyz); - grid[index] = v; + + for (vector<GridItem>::iterator gIter = grids.begin(); gIter != grids.end(); ++gIter) { + GridItem gridItem = *gIter; + void **pointerList = gridItem.pointer; + int type = gridItem.type; + int *res = gridItem.res; + assert(pointerList[0]); + assert(res[0] == res[0] && res[1] == res[1] && res[2] == res[2]); + UNUSED_VARS(res); + + switch (type) { + case FLUID_DOMAIN_GRID_VEC3F: { + unordered_map<string, openvdb::Vec3SGrid::Accessor>::iterator it; + it = vec3fAccessors.find(gridItem.name); + if (it == vec3fAccessors.end()) { + cerr << "Fluid Error -- '" << gridItem.name << "' not in vdb grid map" << endl; + return false; + } + openvdb::Vec3f v = it->second.getValue(xyz); + + assert(pointerList[1] && pointerList[2]); + float **fpointers = (float **)pointerList; + for (int j = 0; j < 3; ++j) { + (fpointers[j])[index] = (float)v[j]; + } + break; + } + case FLUID_DOMAIN_GRID_FLOAT: { + unordered_map<string, openvdb::FloatGrid::Accessor>::iterator it; + it = floatAccessors.find(gridItem.name); + if (it == floatAccessors.end()) { + cerr << "Fluid Error -- '" << gridItem.name << "' not in vdb grid map" << endl; + return false; + } + float v = it->second.getValue(xyz); + float **fpointers = (float **)pointerList; + (fpointers[0])[index] = v; + break; + } + default: { + cerr << "Fluid Error -- Unknown grid type" << endl; + } + } + } } } } + if (with_debug) + cout << "Fluid: Read successfully: " << filename << endl; + return true; } #endif -bool MANTA::updateGridFromRaw(string filename, float *grid, bool isNoise) +bool MANTA::updateGridsFromRaw(string filename, vector<GridItem> grids) { if (with_debug) - cout << "MANTA::updateGridFromRaw()" << endl; + cout << "MANTA::updateGridsFromRaw()" << endl; gzFile gzf; int expectedBytes, readBytes; gzf = (gzFile)BLI_gzopen(filename.c_str(), "rb"); if (!gzf) { - cout << "MANTA::updateGridFromRaw(): unable to open file" << endl; + cout << "MANTA::updateGridsFromRaw(): unable to open file" << endl; return false; } - int resX = (isNoise) ? mResXNoise : mResX; - int resY = (isNoise) ? mResYNoise : mResY; - int resZ = (isNoise) ? mResZNoise : mResZ; + for (vector<GridItem>::iterator gIter = grids.begin(); gIter != grids.end(); ++gIter) { + GridItem gridItem = *gIter; + void **pointerList = gridItem.pointer; + int type = gridItem.type; + int *res = gridItem.res; + assert(pointerList[0]); + assert(res[0] == res[0] && res[1] == res[1] && res[2] == res[2]); + UNUSED_VARS(res); + + switch (type) { + case FLUID_DOMAIN_GRID_VEC3F: { + assert(pointerList[1] && pointerList[2]); + float **fpointers = (float **)pointerList; + expectedBytes = sizeof(float) * 3 * res[0] * res[1] * res[2]; + readBytes = 0; + for (int i = 0; i < res[0] * res[1] * res[2]; ++i) { + for (int j = 0; j < 3; ++j) { + readBytes += gzread(gzf, fpointers[j], sizeof(float)); + ++fpointers[j]; + } + } + break; + } + case FLUID_DOMAIN_GRID_FLOAT: { + float **fpointers = (float **)pointerList; + expectedBytes = sizeof(float) * res[0] * res[1] * res[2]; + readBytes = gzread(gzf, fpointers[0], expectedBytes); + break; + } + default: { + cerr << "Fluid Error -- Unknown grid type" << endl; + } + } + + if (!readBytes) { + cerr << "Fluid Error -- updateGridsFromRaw(): Unable to read raw file: " << filename << endl; + gzclose(gzf); + return false; + } + assert(expectedBytes == readBytes); - expectedBytes = sizeof(float) * resX * resY * resZ; - readBytes = gzread(gzf, grid, expectedBytes); - if (!readBytes) { - cerr << "Fluid Error -- updateGridFromRaw(): Unable to read raw file: " << filename << endl; - gzclose(gzf); - return false; + if (with_debug) + cout << "Fluid: Read successfully: " << filename << endl; } - assert(expectedBytes == readBytes); + if (with_debug) + cout << "Fluid: Read successfully: " << filename << endl; return (gzclose(gzf) == Z_OK); } @@ -3084,12 +3356,12 @@ bool MANTA::hasConfig(FluidModifierData *mmd, int framenr) { string extension = FLUID_DOMAIN_EXTENSION_UNI; return BLI_exists( - getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_DOMAIN_FILE_CONFIG, extension, framenr).c_str()); + getFile(mmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_FILENAME_CONFIG, extension, framenr).c_str()); } bool MANTA::hasData(FluidModifierData *mmd, int framenr) { - string filename = (mUsingSmoke) ? FLUID_DOMAIN_FILE_DENSITY : FLUID_DOMAIN_FILE_PP; + string filename = (mUsingSmoke) ? FLUID_FILENAME_DENSITY : FLUID_FILENAME_PP; string extension = getCacheFileEnding(mmd->domain->cache_data_format); return BLI_exists(getFile(mmd, FLUID_DOMAIN_DIR_DATA, filename, extension, framenr).c_str()); } @@ -3098,7 +3370,7 @@ bool MANTA::hasNoise(FluidModifierData *mmd, int framenr) { string extension = getCacheFileEnding(mmd->domain->cache_noise_format); return BLI_exists( - getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_DENSITYNOISE, extension, framenr) + getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_FILENAME_DENSITYNOISE, extension, framenr) .c_str()); } @@ -3106,21 +3378,20 @@ bool MANTA::hasMesh(FluidModifierData *mmd, int framenr) { string extension = getCacheFileEnding(mmd->domain->cache_mesh_format); return BLI_exists( - getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_DOMAIN_FILE_MESH, extension, framenr).c_str()); + getFile(mmd, FLUID_DOMAIN_DIR_MESH, FLUID_FILENAME_MESH, extension, framenr).c_str()); } bool MANTA::hasParticles(FluidModifierData *mmd, int framenr) { string extension = getCacheFileEnding(mmd->domain->cache_particle_format); return BLI_exists( - getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_DOMAIN_FILE_PPSND, extension, framenr) - .c_str()); + getFile(mmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_FILENAME_PPSND, extension, framenr).c_str()); } bool MANTA::hasGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain) { string subdirectory = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDE; - string filename = (sourceDomain) ? FLUID_DOMAIN_FILE_VEL : FLUID_DOMAIN_FILE_GUIDEVEL; + string filename = (sourceDomain) ? FLUID_FILENAME_VELOCITY : FLUID_FILENAME_GUIDEVEL; string extension = getCacheFileEnding(mmd->domain->cache_data_format); return BLI_exists(getFile(mmd, subdirectory, filename, extension, framenr).c_str()); } diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h index 9b3fd6aa141..6a8484c75d9 100644 --- a/intern/mantaflow/intern/MANTA_main.h +++ b/intern/mantaflow/intern/MANTA_main.h @@ -60,6 +60,19 @@ struct MANTA { int flags; } Triangle; + // Cache helper typedefs + typedef struct GridItem { + void **pointer; /* Array of pointers for this grid.*/ + int type; + int *res; + string name; + } GridItem; + + typedef struct FileItem { + string filename; + vector<GridItem> grids; + } FileItem; + // Manta step, handling everything void step(struct FluidModifierData *mmd, int startFrame); @@ -72,6 +85,7 @@ struct MANTA { void initLiquid(FluidModifierData *mmd = NULL); void initLiquidMesh(FluidModifierData *mmd = NULL); void initObstacle(FluidModifierData *mmd = NULL); + void initCurvature(FluidModifierData *mmd = NULL); void initGuiding(FluidModifierData *mmd = NULL); void initFractions(FluidModifierData *mmd = NULL); void initInVelocity(FluidModifierData *mmd = NULL); @@ -761,6 +775,7 @@ struct MANTA { bool mUsingOutflow; bool mUsingNoise; bool mUsingMesh; + bool mUsingDiffusion; bool mUsingMVel; bool mUsingLiquid; bool mUsingSmoke; @@ -888,12 +903,12 @@ struct MANTA { bool updateMeshFromObj(string filename); bool updateMeshFromUni(string filename); bool updateParticlesFromUni(string filename, bool isSecondarySys, bool isVelData); - bool updateGridFromUni(string filename, float *grid, bool isNoise); - bool updateGridFromVDB(string filename, float *grid, bool isNoise); - bool updateGridFromRaw(string filename, float *grid, bool isNoise); + bool updateGridsFromUni(string filename, vector<GridItem> grids); + bool updateGridsFromVDB(string filename, vector<GridItem> grids); + bool updateGridsFromRaw(string filename, vector<GridItem> grids); bool updateMeshFromFile(string filename); bool updateParticlesFromFile(string filename, bool isSecondarySys, bool isVelData); - bool updateGridFromFile(string filename, float *grid, bool isNoise); + bool updateGridsFromFile(string filename, vector<GridItem> grids); string getDirectory(struct FluidModifierData *mmd, string subdirectory); string getFile(struct FluidModifierData *mmd, string subdirectory, diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h index 922e591c001..cf99717c102 100644 --- a/intern/mantaflow/intern/strings/fluid_script.h +++ b/intern/mantaflow/intern/strings/fluid_script.h @@ -259,7 +259,7 @@ const std::string fluid_alloc = "\n\ mantaMsg('Fluid alloc data')\n\ flags_s$ID$ = s$ID$.create(FlagGrid)\n\ -vel_s$ID$ = s$ID$.create(MACGrid)\n\ +vel_s$ID$ = s$ID$.create(MACGrid, name='$NAME_VELOCITY$')\n\ velTmp_s$ID$ = s$ID$.create(MACGrid)\n\ x_vel_s$ID$ = s$ID$.create(RealGrid)\n\ y_vel_s$ID$ = s$ID$.create(RealGrid)\n\ diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h index cdacea16953..e9777eb9cda 100644 --- a/intern/mantaflow/intern/strings/liquid_script.h +++ b/intern/mantaflow/intern/strings/liquid_script.h @@ -80,11 +80,11 @@ mantaMsg('Liquid alloc')\n\ phiParts_s$ID$ = s$ID$.create(LevelsetGrid)\n\ phi_s$ID$ = s$ID$.create(LevelsetGrid)\n\ phiTmp_s$ID$ = s$ID$.create(LevelsetGrid)\n\ -curvature_s$ID$ = s$ID$.create(RealGrid)\n\ velOld_s$ID$ = s$ID$.create(MACGrid)\n\ velParts_s$ID$ = s$ID$.create(MACGrid)\n\ mapWeights_s$ID$ = s$ID$.create(MACGrid)\n\ fractions_s$ID$ = None # allocated dynamically\n\ +curvature_s$ID$ = None\n\ \n\ pp_s$ID$ = s$ID$.create(BasicParticleSystem)\n\ pVel_pp$ID$ = pp_s$ID$.create(PdataVec3)\n\ @@ -124,6 +124,11 @@ liquid_mesh_dict_s$ID$ = dict(lMesh=mesh_sm$ID$)\n\ if using_speedvectors_s$ID$:\n\ liquid_meshvel_dict_s$ID$ = dict(lVelMesh=mVel_mesh$ID$)\n"; +const std::string liquid_alloc_curvature = + "\n\ +mantaMsg('Liquid alloc curvature')\n\ +curvature_s$ID$ = s$ID$.create(RealGrid)\n"; + const std::string liquid_alloc_particles = "\n\ ppSnd_sp$ID$ = sp$ID$.create(BasicParticleSystem)\n\ @@ -227,7 +232,7 @@ def liquid_step_$ID$():\n\ mantaMsg('Liquid step')\n\ \n\ mantaMsg('Advecting particles')\n\ - pp_s$ID$.advectInGrid(flags=flags_s$ID$, vel=vel_s$ID$, integrationMode=IntRK4, deleteInObstacle=deleteInObstacle_s$ID$, stopInObstacle=False)\n\ + pp_s$ID$.advectInGrid(flags=flags_s$ID$, vel=vel_s$ID$, integrationMode=IntRK4, deleteInObstacle=deleteInObstacle_s$ID$, stopInObstacle=False, skipNew=True)\n\ \n\ mantaMsg('Pushing particles out of obstacles')\n\ pushOutofObs(parts=pp_s$ID$, flags=flags_s$ID$, phiObs=phiObs_s$ID$)\n\ @@ -284,12 +289,13 @@ def liquid_step_$ID$():\n\ alphaV = viscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ cgSolveDiffusion(flags_s$ID$, vel_s$ID$, alphaV)\n\ + \n\ + mantaMsg('Curvature')\n\ + getLaplacian(laplacian=curvature_s$ID$, grid=phi_s$ID$)\n\ + curvature_s$ID$.clamp(-1.0, 1.0)\n\ \n\ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ \n\ - mantaMsg('Calculating curvature')\n\ - getLaplacian(laplacian=curvature_s$ID$, grid=phi_s$ID$)\n\ - \n\ if using_guiding_s$ID$:\n\ mantaMsg('Guiding and pressure')\n\ PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, zeroPressureFixing=not doOpen_s$ID$)\n\ @@ -343,7 +349,10 @@ def liquid_step_mesh_$ID$():\n\ interpolateMACGrid(target=vel_sm$ID$, source=vel_s$ID$)\n\ mVel_mesh$ID$.setSource(vel_sm$ID$, isMAC=True)\n\ \n\ - phi_sm$ID$.setBound(0.5,int(((upres_sm$ID$)*2)-2) )\n\ + # Set 0.5 boundary at walls + account for extra wall thickness in fractions mode + account for grid scaling:\n\ + # E.g. at upres=1 we expect 1 cell border (or 2 with fractions), at upres=2 we expect 2 cell border (or 4 with fractions), etc.\n\ + # Use -1 since setBound() starts counting at 0 (and additional -1 for fractions to account for solid/fluid interface cells)\n\ + phi_sm$ID$.setBound(value=0.5, boundaryWidth=(upres_sm$ID$*2)-2 if using_fractions_s$ID$ else upres_sm$ID$-1)\n\ phi_sm$ID$.createMesh(mesh_sm$ID$)\n"; const std::string liquid_step_particles = diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h index ea2b1e9d848..72d5e20b58b 100644 --- a/intern/mantaflow/intern/strings/smoke_script.h +++ b/intern/mantaflow/intern/strings/smoke_script.h @@ -81,10 +81,10 @@ using_fire_s$ID$ = True\n"; const std::string smoke_alloc = "\n\ mantaMsg('Smoke alloc')\n\ -shadow_s$ID$ = s$ID$.create(RealGrid)\n\ +shadow_s$ID$ = s$ID$.create(RealGrid, name='$NAME_SHADOW$')\n\ emission_s$ID$ = s$ID$.create(RealGrid)\n\ emissionIn_s$ID$ = s$ID$.create(RealGrid)\n\ -density_s$ID$ = s$ID$.create(RealGrid)\n\ +density_s$ID$ = s$ID$.create(RealGrid, name='$NAME_DENSITY$')\n\ densityIn_s$ID$ = s$ID$.create(RealGrid)\n\ heat_s$ID$ = None # allocated dynamically\n\ heatIn_s$ID$ = None\n\ @@ -108,7 +108,7 @@ const std::string smoke_alloc_noise = "\n\ mantaMsg('Smoke alloc noise')\n\ vel_sn$ID$ = sn$ID$.create(MACGrid)\n\ -density_sn$ID$ = sn$ID$.create(RealGrid)\n\ +density_sn$ID$ = sn$ID$.create(RealGrid, name='$NAME_DENSITYNOISE$')\n\ phiIn_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\ phiOut_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\ phiObs_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\ @@ -157,9 +157,9 @@ if 'color_g_s$ID$' in globals(): del color_g_s$ID$\n\ if 'color_b_s$ID$' in globals(): del color_b_s$ID$\n\ \n\ mantaMsg('Allocating colors')\n\ -color_r_s$ID$ = s$ID$.create(RealGrid)\n\ -color_g_s$ID$ = s$ID$.create(RealGrid)\n\ -color_b_s$ID$ = s$ID$.create(RealGrid)\n\ +color_r_s$ID$ = s$ID$.create(RealGrid, name='$NAME_COLORR$')\n\ +color_g_s$ID$ = s$ID$.create(RealGrid, name='$NAME_COLORG$')\n\ +color_b_s$ID$ = s$ID$.create(RealGrid, name='$NAME_COLORB$')\n\ color_r_in_s$ID$ = s$ID$.create(RealGrid)\n\ color_g_in_s$ID$ = s$ID$.create(RealGrid)\n\ color_b_in_s$ID$ = s$ID$.create(RealGrid)\n\ @@ -178,9 +178,9 @@ if 'color_g_sn$ID$' in globals(): del color_g_sn$ID$\n\ if 'color_b_sn$ID$' in globals(): del color_b_sn$ID$\n\ \n\ mantaMsg('Allocating colors noise')\n\ -color_r_sn$ID$ = sn$ID$.create(RealGrid)\n\ -color_g_sn$ID$ = sn$ID$.create(RealGrid)\n\ -color_b_sn$ID$ = sn$ID$.create(RealGrid)\n\ +color_r_sn$ID$ = sn$ID$.create(RealGrid, name='$NAME_COLORRNOISE$')\n\ +color_g_sn$ID$ = sn$ID$.create(RealGrid, name='$NAME_COLORGNOISE$')\n\ +color_b_sn$ID$ = sn$ID$.create(RealGrid, name='$NAME_COLORBNOISE$')\n\ \n\ # Add objects to dict to load them later on\n\ if 'smoke_noise_dict_final_s$ID$' in globals():\n\ @@ -213,7 +213,7 @@ if 'heat_s$ID$' in globals(): del heat_s$ID$\n\ if 'heatIn_s$ID$' in globals(): del heatIn_s$ID$\n\ \n\ mantaMsg('Allocating heat')\n\ -heat_s$ID$ = s$ID$.create(RealGrid)\n\ +heat_s$ID$ = s$ID$.create(RealGrid, name='$NAME_HEAT$')\n\ heatIn_s$ID$ = s$ID$.create(RealGrid)\n\ \n\ # Add objects to dict to load them later on\n\ @@ -232,9 +232,9 @@ if 'fuelIn_s$ID$' in globals(): del fuelIn_s$ID$\n\ if 'reactIn_s$ID$' in globals(): del reactIn_s$ID$\n\ \n\ mantaMsg('Allocating fire')\n\ -flame_s$ID$ = s$ID$.create(RealGrid)\n\ -fuel_s$ID$ = s$ID$.create(RealGrid)\n\ -react_s$ID$ = s$ID$.create(RealGrid)\n\ +flame_s$ID$ = s$ID$.create(RealGrid, name='$NAME_FLAME$')\n\ +fuel_s$ID$ = s$ID$.create(RealGrid, name='$NAME_FUEL$')\n\ +react_s$ID$ = s$ID$.create(RealGrid, name='$NAME_REACT$')\n\ fuelIn_s$ID$ = s$ID$.create(RealGrid)\n\ reactIn_s$ID$ = s$ID$.create(RealGrid)\n\ \n\ @@ -252,9 +252,9 @@ if 'fuel_sn$ID$' in globals(): del fuel_sn$ID$\n\ if 'react_sn$ID$' in globals(): del react_sn$ID$\n\ \n\ mantaMsg('Allocating fire noise')\n\ -flame_sn$ID$ = sn$ID$.create(RealGrid)\n\ -fuel_sn$ID$ = sn$ID$.create(RealGrid)\n\ -react_sn$ID$ = sn$ID$.create(RealGrid)\n\ +flame_sn$ID$ = sn$ID$.create(RealGrid, name='$NAME_FLAMENOISE$')\n\ +fuel_sn$ID$ = sn$ID$.create(RealGrid, name='$NAME_FUELNOISE$')\n\ +react_sn$ID$ = sn$ID$.create(RealGrid, name='$NAME_REACTNOISE$')\n\ \n\ # Add objects to dict to load them later on\n\ if 'smoke_noise_dict_final_s$ID$' in globals():\n\ diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index e7292872e9c..ea48a387bbd 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -31,7 +31,6 @@ set(SRC opensubdiv_capi_type.h opensubdiv_converter_capi.h opensubdiv_evaluator_capi.h - opensubdiv_gl_mesh_capi.h opensubdiv_topology_refiner_capi.h ) @@ -51,36 +50,41 @@ if(WITH_OPENSUBDIV) ) list(APPEND SRC - internal/opensubdiv.cc - internal/opensubdiv_converter_factory.cc - internal/opensubdiv_converter_internal.cc - internal/opensubdiv_converter_orient.cc - internal/opensubdiv_device_context_cuda.cc - internal/opensubdiv_device_context_opencl.cc - internal/opensubdiv_evaluator.cc - internal/opensubdiv_evaluator_internal.cc - internal/opensubdiv_gl_mesh.cc - internal/opensubdiv_gl_mesh_draw.cc - internal/opensubdiv_gl_mesh_fvar.cc - internal/opensubdiv_gl_mesh_internal.cc - internal/opensubdiv_topology_refiner.cc - internal/opensubdiv_topology_refiner_internal.cc - internal/opensubdiv_util.cc - - internal/opensubdiv_converter_factory.h - internal/opensubdiv_converter_internal.h - internal/opensubdiv_converter_orient.h - internal/opensubdiv_converter_orient_impl.h - internal/opensubdiv_device_context_cuda.h - internal/opensubdiv_device_context_opencl.h - internal/opensubdiv_edge_map.h - internal/opensubdiv_evaluator_internal.h - internal/opensubdiv_gl_mesh_draw.h - internal/opensubdiv_gl_mesh_fvar.h - internal/opensubdiv_gl_mesh_internal.h - internal/opensubdiv_internal.h - internal/opensubdiv_topology_refiner_internal.h - internal/opensubdiv_util.h + # Base. + internal/base/memory.h + internal/base/opensubdiv_capi.cc + internal/base/type.h + internal/base/type_convert.cc + internal/base/type_convert.h + internal/base/util.cc + internal/base/util.h + + # Device. + internal/device/device_context_cuda.cc + internal/device/device_context_cuda.h + internal/device/device_context_glsl_compute.cc + internal/device/device_context_glsl_compute.h + internal/device/device_context_glsl_transform_feedback.cc + internal/device/device_context_glsl_transform_feedback.h + internal/device/device_context_opencl.cc + internal/device/device_context_opencl.h + internal/device/device_context_openmp.cc + internal/device/device_context_openmp.h + + # Evaluator. + internal/evaluator/evaluator_capi.cc + internal/evaluator/evaluator_impl.cc + internal/evaluator/evaluator_impl.h + + # Topology. + internal/topology/mesh_topology.cc + internal/topology/mesh_topology_compare.cc + internal/topology/mesh_topology.h + internal/topology/topology_refiner_capi.cc + internal/topology/topology_refiner_factory.cc + internal/topology/topology_refiner_impl.cc + internal/topology/topology_refiner_impl_compare.cc + internal/topology/topology_refiner_impl.h ) list(APPEND LIB @@ -94,46 +98,36 @@ if(WITH_OPENSUBDIV) endif() OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENMP) - # TODO(sergey): OpenCL is not tested and totally unstable atm. - # OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENCL) - # TODO(sergey): CUDA stays disabled for util it's ported to drievr API. - # OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_CUDA) + OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_OPENCL) + OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_CUDA) OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK) OPENSUBDIV_DEFINE_COMPONENT(OPENSUBDIV_HAS_GLSL_COMPUTE) - data_to_c_simple(shader/gpu_shader_opensubdiv_vertex.glsl SRC) - data_to_c_simple(shader/gpu_shader_opensubdiv_geometry.glsl SRC) - data_to_c_simple(shader/gpu_shader_opensubdiv_fragment.glsl SRC) - - add_definitions(-DGLEW_STATIC) + add_definitions(${GL_DEFINITIONS}) add_definitions(-DOSD_USES_GLEW) if(WIN32) add_definitions(-DNOMINMAX) add_definitions(-D_USE_MATH_DEFINES) endif() - - # TODO(sergey): Put CUEW back when CUDA is officially supported by OSD. - # if(OPENSUBDIV_HAS_CUDA) - # list(APPEND INC - # ../../extern/cuew/include - # ) - # add_definitions(-DOPENSUBDIV_HAS_CUEW) - # endif() - - if(OPENSUBDIV_HAS_OPENCL) - list(APPEND INC - ../../extern/clew/include - ) - add_definitions(-DOPENSUBDIV_HAS_CLEW) - endif() else() list(APPEND SRC stub/opensubdiv_stub.cc stub/opensubdiv_evaluator_stub.cc - stub/opensubdiv_gl_mesh_stub.cc stub/opensubdiv_topology_refiner_stub.cc ) endif() blender_add_lib(bf_intern_opensubdiv "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# Tests. + +if(WITH_GTESTS AND WITH_OPENSUBDIV) + include(GTestTesting) + + add_definitions(${GFLAGS_DEFINES}) + add_definitions(${GLOG_DEFINES}) + add_definitions(-DBLENDER_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE}) + + BLENDER_SRC_GTEST(opensubdiv_mesh_topology_test "internal/topology/mesh_topology_test.cc" "${LIB};bf_intern_opensubdiv") +endif() diff --git a/intern/opensubdiv/internal/base/memory.h b/intern/opensubdiv/internal/base/memory.h new file mode 100644 index 00000000000..176d9c14694 --- /dev/null +++ b/intern/opensubdiv/internal/base/memory.h @@ -0,0 +1,28 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef OPENSUBDIV_BASE_MEMORY_H_ +#define OPENSUBDIV_BASE_MEMORY_H_ + +#include "MEM_guardedalloc.h" + +namespace blender { +namespace opensubdiv { + +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_BASE_MEMORY_H_ diff --git a/intern/opensubdiv/internal/opensubdiv.cc b/intern/opensubdiv/internal/base/opensubdiv_capi.cc index 74b81b13351..430acfd4497 100644 --- a/intern/opensubdiv/internal/opensubdiv.cc +++ b/intern/opensubdiv/internal/base/opensubdiv_capi.cc @@ -20,11 +20,18 @@ # include <iso646.h> #endif -#include <GL/glew.h> +#include "internal/base/util.h" +#include "internal/device/device_context_cuda.h" +#include "internal/device/device_context_glsl_compute.h" +#include "internal/device/device_context_glsl_transform_feedback.h" +#include "internal/device/device_context_opencl.h" +#include "internal/device/device_context_openmp.h" -#include "opensubdiv_device_context_cuda.h" -#include "opensubdiv_device_context_opencl.h" -#include "opensubdiv_gl_mesh_capi.h" +using blender::opensubdiv::CUDADeviceContext; +using blender::opensubdiv::GLSLComputeDeviceContext; +using blender::opensubdiv::GLSLTransformFeedbackDeviceContext; +using blender::opensubdiv::OpenCLDeviceContext; +using blender::opensubdiv::OpenMPDeviceContext; void openSubdiv_init(void) { @@ -34,40 +41,31 @@ void openSubdiv_init(void) void openSubdiv_cleanup(void) { - openSubdiv_deinitGLMeshDrawingResources(); } int openSubdiv_getAvailableEvaluators(void) { int flags = OPENSUBDIV_EVALUATOR_CPU; -#ifdef OPENSUBDIV_HAS_OPENMP - flags |= OPENSUBDIV_EVALUATOR_OPENMP; -#endif + if (OpenMPDeviceContext::isSupported()) { + flags |= OPENSUBDIV_EVALUATOR_OPENMP; + } -#ifdef OPENSUBDIV_HAS_OPENCL - if (CLDeviceContext::HAS_CL_VERSION_1_1()) { + if (OpenCLDeviceContext::isSupported()) { flags |= OPENSUBDIV_EVALUATOR_OPENCL; } -#endif -#ifdef OPENSUBDIV_HAS_CUDA - if (CudaDeviceContext::HAS_CUDA_VERSION_4_0()) { + if (CUDADeviceContext::isSupported()) { flags |= OPENSUBDIV_EVALUATOR_CUDA; } -#endif -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK - if (GLEW_VERSION_4_1) { + if (GLSLTransformFeedbackDeviceContext::isSupported()) { flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK; } -#endif -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE - if (GLEW_VERSION_4_3 || GLEW_ARB_compute_shader) { + if (GLSLComputeDeviceContext::isSupported()) { flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE; } -#endif return flags; } @@ -86,7 +84,7 @@ int openSubdiv_getVersionHex(void) } int major = 0, minor = 0, patch = 0; vector<string> tokens; - opensubdiv_capi::stringSplit(&tokens, version, "_", true); + blender::opensubdiv::stringSplit(&tokens, version, "_", true); if (tokens.size() == 3) { major = atoi(tokens[0].c_str()); minor = atoi(tokens[1].c_str()); diff --git a/intern/opensubdiv/internal/opensubdiv_util.h b/intern/opensubdiv/internal/base/type.h index e515859b42f..17e941a171d 100644 --- a/intern/opensubdiv/internal/opensubdiv_util.h +++ b/intern/opensubdiv/internal/base/type.h @@ -14,43 +14,38 @@ // along with this program; if not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -#ifndef OPENSUBDIV_UTIL_H_ -#define OPENSUBDIV_UTIL_H_ +#ifndef OPENSUBDIV_BASE_TYPE_H_ +#define OPENSUBDIV_BASE_TYPE_H_ #include <stdint.h> #include <algorithm> #include <cassert> +#include <map> #include <stack> #include <string> #include <unordered_map> #include <utility> #include <vector> -namespace opensubdiv_capi { +namespace blender { +namespace opensubdiv { -using std::fill; -using std::make_pair; -using std::max; -using std::min; +using std::map; using std::pair; using std::stack; using std::string; -using std::swap; using std::unordered_map; using std::vector; -#define foreach(x, y) for (x : y) - -#define STRINGIFY_ARG(x) "" #x -#define STRINGIFY_APPEND(a, b) "" a #b -#define STRINGIFY(x) STRINGIFY_APPEND("", x) - -void stringSplit(vector<string> *tokens, - const string &str, - const string &separators, - bool skip_empty); +using std::fill; +using std::make_pair; +using std::max; +using std::min; +using std::move; +using std::swap; -} // namespace opensubdiv_capi +} // namespace opensubdiv +} // namespace blender -#endif // OPENSUBDIV_UTIL_H_ +#endif // OPENSUBDIV_BASE_TYPE_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.cc b/intern/opensubdiv/internal/base/type_convert.cc index 0335219d6b9..08778ab3877 100644 --- a/intern/opensubdiv/internal/opensubdiv_converter_internal.cc +++ b/intern/opensubdiv/internal/base/type_convert.cc @@ -20,12 +20,13 @@ # include <iso646.h> #endif -#include "internal/opensubdiv_converter_internal.h" +#include "internal/base/type_convert.h" #include <cassert> #include <opensubdiv/sdc/crease.h> -namespace opensubdiv_capi { +namespace blender { +namespace opensubdiv { OpenSubdiv::Sdc::SchemeType getSchemeTypeFromCAPI(OpenSubdiv_SchemeType type) { @@ -85,4 +86,22 @@ OpenSubdiv_FVarLinearInterpolation getCAPIFVarLinearInterpolationFromOSD( return OSD_FVAR_LINEAR_INTERPOLATION_NONE; } -} // namespace opensubdiv_capi +OpenSubdiv::Sdc::Options::VtxBoundaryInterpolation getVtxBoundaryInterpolationFromCAPI( + OpenSubdiv_VtxBoundaryInterpolation boundary_interpolation) +{ + using OpenSubdiv::Sdc::Options; + + switch (boundary_interpolation) { + case OSD_VTX_BOUNDARY_NONE: + return Options::VTX_BOUNDARY_NONE; + case OSD_VTX_BOUNDARY_EDGE_ONLY: + return Options::VTX_BOUNDARY_EDGE_ONLY; + case OSD_VTX_BOUNDARY_EDGE_AND_CORNER: + return Options::VTX_BOUNDARY_EDGE_AND_CORNER; + } + assert(!"Unknown veretx boundary interpolation."); + return Options::VTX_BOUNDARY_EDGE_ONLY; +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.h b/intern/opensubdiv/internal/base/type_convert.h index 11c6bdd7f3b..b0de0d8fc54 100644 --- a/intern/opensubdiv/internal/opensubdiv_converter_internal.h +++ b/intern/opensubdiv/internal/base/type_convert.h @@ -16,8 +16,8 @@ // // Author: Sergey Sharybin -#ifndef OPENSUBDIV_CONVERTER_INTERNAL_H_ -#define OPENSUBDIV_CONVERTER_INTERNAL_H_ +#ifndef OPENSUBDIV_BASE_TYPE_CONVERT_H_ +#define OPENSUBDIV_BASE_TYPE_CONVERT_H_ #ifdef _MSC_VER # include <iso646.h> @@ -26,11 +26,12 @@ #include <opensubdiv/sdc/options.h> #include <opensubdiv/sdc/types.h> -#include "opensubdiv_converter_capi.h" +#include "opensubdiv_capi_type.h" struct OpenSubdiv_Converter; -namespace opensubdiv_capi { +namespace blender { +namespace opensubdiv { // Convert scheme type from C-API enum to an OpenSubdiv native enum. OpenSubdiv::Sdc::SchemeType getSchemeTypeFromCAPI(OpenSubdiv_SchemeType type); @@ -44,6 +45,10 @@ OpenSubdiv::Sdc::Options::FVarLinearInterpolation getFVarLinearInterpolationFrom OpenSubdiv_FVarLinearInterpolation getCAPIFVarLinearInterpolationFromOSD( OpenSubdiv::Sdc::Options::FVarLinearInterpolation linear_interpolation); -} // namespace opensubdiv_capi +OpenSubdiv::Sdc::Options::VtxBoundaryInterpolation getVtxBoundaryInterpolationFromCAPI( + OpenSubdiv_VtxBoundaryInterpolation boundary_interpolation); -#endif // OPENSUBDIV_CONVERTER_INTERNAL_H_ +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_BASE_TYPE_CONVERT_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_util.cc b/intern/opensubdiv/internal/base/util.cc index 6e6f3a0920f..9c858ec3cda 100644 --- a/intern/opensubdiv/internal/opensubdiv_util.cc +++ b/intern/opensubdiv/internal/base/util.cc @@ -14,16 +14,10 @@ // along with this program; if not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -#include "internal/opensubdiv_util.h" +#include "internal/base/util.h" -#include <GL/glew.h> -#include <cstring> - -#ifdef _MSC_VER -# include <iso646.h> -#endif - -namespace opensubdiv_capi { +namespace blender { +namespace opensubdiv { void stringSplit(vector<string> *tokens, const string &str, @@ -43,7 +37,7 @@ void stringSplit(vector<string> *tokens, string token = str.substr(token_start, token_length); tokens->push_back(token); } - // Re-set token pointers, + // Re-set token pointers. token_start = i + 1; token_length = 0; } @@ -56,4 +50,5 @@ void stringSplit(vector<string> *tokens, } } -} // namespace opensubdiv_capi +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/base/util.h b/intern/opensubdiv/internal/base/util.h new file mode 100644 index 00000000000..4035ba7301a --- /dev/null +++ b/intern/opensubdiv/internal/base/util.h @@ -0,0 +1,33 @@ +// Copyright 2013 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef OPENSUBDIV_BASE_UTIL_H_ +#define OPENSUBDIV_BASE_UTIL_H_ + +#include "internal/base/type.h" + +namespace blender { +namespace opensubdiv { + +void stringSplit(vector<string> *tokens, + const string &str, + const string &separators, + bool skip_empty); + +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_BASE_UTIL_H_ diff --git a/intern/opensubdiv/stub/opensubdiv_gl_mesh_stub.cc b/intern/opensubdiv/internal/device/device_context_cuda.cc index 91ac0676dbd..cd4336265a5 100644 --- a/intern/opensubdiv/stub/opensubdiv_gl_mesh_stub.cc +++ b/intern/opensubdiv/internal/device/device_context_cuda.cc @@ -1,4 +1,4 @@ -// Copyright 2018 Blender Foundation. All rights reserved. +// Copyright 2020 Blender Foundation. All rights reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,25 +16,24 @@ // // Author: Sergey Sharybin -#include "opensubdiv_gl_mesh_capi.h" +#include "internal/device/device_context_cuda.h" -#include <cstddef> +namespace blender { +namespace opensubdiv { -struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( - OpenSubdiv_TopologyRefiner * /*topology_refiner*/, eOpenSubdivEvaluator /*evaluator_type*/) +bool CUDADeviceContext::isSupported() { - return NULL; + // TODO(sergey): Add CUDA device support, using CUDA-RT API. + return false; } -void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh * /*gl_mesh*/) +CUDADeviceContext::CUDADeviceContext() { } -bool openSubdiv_initGLMeshDrawingResources(void) +CUDADeviceContext::~CUDADeviceContext() { - return false; } -void openSubdiv_deinitGLMeshDrawingResources(void) -{ -} +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/device/device_context_cuda.h b/intern/opensubdiv/internal/device/device_context_cuda.h new file mode 100644 index 00000000000..d1bfb15fbcb --- /dev/null +++ b/intern/opensubdiv/internal/device/device_context_cuda.h @@ -0,0 +1,38 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ +#define OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ + +namespace blender { +namespace opensubdiv { + +class CUDADeviceContext { + public: + // Stateless check to see whether CUDA functionality is available on this + // platform. + static bool isSupported(); + + CUDADeviceContext(); + ~CUDADeviceContext(); +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // _OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ diff --git a/intern/opensubdiv/internal/device/device_context_glsl_compute.cc b/intern/opensubdiv/internal/device/device_context_glsl_compute.cc new file mode 100644 index 00000000000..7b416976099 --- /dev/null +++ b/intern/opensubdiv/internal/device/device_context_glsl_compute.cc @@ -0,0 +1,40 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/device/device_context_glsl_compute.h" + +#include <GL/glew.h> + +namespace blender { +namespace opensubdiv { + +bool GLSLComputeDeviceContext::isSupported() +{ + return GLEW_VERSION_4_3 || GLEW_ARB_compute_shader; +} + +GLSLComputeDeviceContext::GLSLComputeDeviceContext() +{ +} + +GLSLComputeDeviceContext::~GLSLComputeDeviceContext() +{ +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/device/device_context_glsl_compute.h b/intern/opensubdiv/internal/device/device_context_glsl_compute.h new file mode 100644 index 00000000000..f64c7d1954b --- /dev/null +++ b/intern/opensubdiv/internal/device/device_context_glsl_compute.h @@ -0,0 +1,38 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_DEVICE_CONTEXT_GLSL_COMPUTE_H_ +#define OPENSUBDIV_DEVICE_CONTEXT_GLSL_COMPUTE_H_ + +namespace blender { +namespace opensubdiv { + +class GLSLComputeDeviceContext { + public: + // Stateless check to see whether GLSL compute functionality is + // available on this platform. + static bool isSupported(); + + GLSLComputeDeviceContext(); + ~GLSLComputeDeviceContext(); +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // _OPENSUBDIV_DEVICE_CONTEXT_GLSL_COMPUTE_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_converter_factory.h b/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.cc index a1038474d33..ef897608b6e 100644 --- a/intern/opensubdiv/internal/opensubdiv_converter_factory.h +++ b/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.cc @@ -1,4 +1,4 @@ -// Copyright 2015 Blender Foundation. All rights reserved. +// Copyright 2020 Blender Foundation. All rights reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,22 +16,25 @@ // // Author: Sergey Sharybin -#ifndef OPENSUBDIV_CONVERTER_FACTORY_H_ -#define OPENSUBDIV_CONVERTER_FACTORY_H_ +#include "internal/device/device_context_glsl_transform_feedback.h" -#ifdef _MSC_VER -# include <iso646.h> -#endif +#include <GL/glew.h> -#include <opensubdiv/far/topologyRefiner.h> +namespace blender { +namespace opensubdiv { -struct OpenSubdiv_Converter; +bool GLSLTransformFeedbackDeviceContext::isSupported() +{ + return GLEW_VERSION_4_1; +} -namespace opensubdiv_capi { +GLSLTransformFeedbackDeviceContext::GLSLTransformFeedbackDeviceContext() +{ +} -OpenSubdiv::Far::TopologyRefiner *createOSDTopologyRefinerFromConverter( - struct OpenSubdiv_Converter *converter); +GLSLTransformFeedbackDeviceContext::~GLSLTransformFeedbackDeviceContext() +{ +} -} // namespace opensubdiv_capi - -#endif // OPENSUBDIV_CONVERTER_FACTORY_H_ +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.h b/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.h new file mode 100644 index 00000000000..7bbbba1380f --- /dev/null +++ b/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.h @@ -0,0 +1,38 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_DEVICE_CONTEXT_GLSL_TRANSFORM_FEEDBACK_H_ +#define OPENSUBDIV_DEVICE_CONTEXT_GLSL_TRANSFORM_FEEDBACK_H_ + +namespace blender { +namespace opensubdiv { + +class GLSLTransformFeedbackDeviceContext { + public: + // Stateless check to see whether GLSL transform feedback functionality is + // available on this platform. + static bool isSupported(); + + GLSLTransformFeedbackDeviceContext(); + ~GLSLTransformFeedbackDeviceContext(); +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // _OPENSUBDIV_DEVICE_CONTEXT_GLSL_TRANSFORM_FEEDBACK_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc b/intern/opensubdiv/internal/device/device_context_opencl.cc index 57e56bad3fb..1670ea3c9d0 100644 --- a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.cc +++ b/intern/opensubdiv/internal/device/device_context_opencl.cc @@ -1,4 +1,4 @@ -// Copyright 2018 Blender Foundation. All rights reserved. +// Copyright 2020 Blender Foundation. All rights reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,17 +16,24 @@ // // Author: Sergey Sharybin -#include "internal/opensubdiv_gl_mesh_internal.h" +#include "internal/device/device_context_opencl.h" -#include "internal/opensubdiv_gl_mesh_fvar.h" +namespace blender { +namespace opensubdiv { -OpenSubdiv_GLMeshInternal::OpenSubdiv_GLMeshInternal() - : evaluator_type(OPENSUBDIV_EVALUATOR_CPU), mesh_interface(NULL), fvar_data(NULL) +bool OpenCLDeviceContext::isSupported() { + // TODO(sergey): Add support of OpenCL devices. + return false; } -OpenSubdiv_GLMeshInternal::~OpenSubdiv_GLMeshInternal() +OpenCLDeviceContext::OpenCLDeviceContext() { - delete mesh_interface; - delete fvar_data; } + +OpenCLDeviceContext::~OpenCLDeviceContext() +{ +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/device/device_context_opencl.h b/intern/opensubdiv/internal/device/device_context_opencl.h new file mode 100644 index 00000000000..57ec6ed3bb6 --- /dev/null +++ b/intern/opensubdiv/internal/device/device_context_opencl.h @@ -0,0 +1,38 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ +#define OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ + +namespace blender { +namespace opensubdiv { + +class OpenCLDeviceContext { + public: + // Stateless check to see whether OpenCL functionality is available on this + // platform. + static bool isSupported(); + + OpenCLDeviceContext(); + ~OpenCLDeviceContext(); +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // _OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_internal.h b/intern/opensubdiv/internal/device/device_context_openmp.cc index 1ddf199c013..e01312fefaf 100644 --- a/intern/opensubdiv/internal/opensubdiv_internal.h +++ b/intern/opensubdiv/internal/device/device_context_openmp.cc @@ -1,4 +1,4 @@ -// Copyright 2015 Blender Foundation. All rights reserved. +// Copyright 2020 Blender Foundation. All rights reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,15 +16,27 @@ // // Author: Sergey Sharybin -#ifndef OPENSUBDIV_INTERNAL_H_ -#define OPENSUBDIV_INTERNAL_H_ +#include "internal/device/device_context_openmp.h" -// Perform full topology validation when exporting it to OpenSubdiv. -#ifdef NDEBUG -// Never do for release builds. -# undef OPENSUBDIV_VALIDATE_TOPOLOGY +namespace blender { +namespace opensubdiv { + +bool OpenMPDeviceContext::isSupported() +{ +#ifdef OPENSUBDIV_HAS_OPENMP + return true; #else -# define OPENSUBDIV_VALIDATE_TOPOLOGY + return false; #endif +} + +OpenMPDeviceContext::OpenMPDeviceContext() +{ +} + +OpenMPDeviceContext::~OpenMPDeviceContext() +{ +} -#endif // OPENSUBDIV_INTERNAL_H_ +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/device/device_context_openmp.h b/intern/opensubdiv/internal/device/device_context_openmp.h new file mode 100644 index 00000000000..2bebbdf40bc --- /dev/null +++ b/intern/opensubdiv/internal/device/device_context_openmp.h @@ -0,0 +1,38 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_DEVICE_CONTEXT_OPENMP_H_ +#define OPENSUBDIV_DEVICE_CONTEXT_OPENMP_H_ + +namespace blender { +namespace opensubdiv { + +class OpenMPDeviceContext { + public: + // Stateless check to see whether OpenMP functionality is available on this + // platform. + static bool isSupported(); + + OpenMPDeviceContext(); + ~OpenMPDeviceContext(); +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // _OPENSUBDIV_DEVICE_CONTEXT_OPENMP_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc index c599a3c9f68..4b12206e103 100644 --- a/intern/opensubdiv/internal/opensubdiv_evaluator.cc +++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc @@ -21,7 +21,7 @@ #include "MEM_guardedalloc.h" #include <new> -#include "internal/opensubdiv_evaluator_internal.h" +#include "internal/evaluator/evaluator_impl.h" namespace { @@ -30,8 +30,7 @@ void setCoarsePositions(OpenSubdiv_Evaluator *evaluator, const int start_vertex_index, const int num_vertices) { - evaluator->internal->eval_output->setCoarsePositions( - positions, start_vertex_index, num_vertices); + evaluator->impl->eval_output->setCoarsePositions(positions, start_vertex_index, num_vertices); } void setVaryingData(OpenSubdiv_Evaluator *evaluator, @@ -39,7 +38,7 @@ void setVaryingData(OpenSubdiv_Evaluator *evaluator, const int start_vertex_index, const int num_vertices) { - evaluator->internal->eval_output->setVaryingData(varying_data, start_vertex_index, num_vertices); + evaluator->impl->eval_output->setVaryingData(varying_data, start_vertex_index, num_vertices); } void setFaceVaryingData(OpenSubdiv_Evaluator *evaluator, @@ -48,7 +47,7 @@ void setFaceVaryingData(OpenSubdiv_Evaluator *evaluator, const int start_vertex_index, const int num_vertices) { - evaluator->internal->eval_output->setFaceVaryingData( + evaluator->impl->eval_output->setFaceVaryingData( face_varying_channel, face_varying_data, start_vertex_index, num_vertices); } @@ -59,7 +58,7 @@ void setCoarsePositionsFromBuffer(OpenSubdiv_Evaluator *evaluator, const int start_vertex_index, const int num_vertices) { - evaluator->internal->eval_output->setCoarsePositionsFromBuffer( + evaluator->impl->eval_output->setCoarsePositionsFromBuffer( buffer, start_offset, stride, start_vertex_index, num_vertices); } @@ -70,7 +69,7 @@ void setVaryingDataFromBuffer(OpenSubdiv_Evaluator *evaluator, const int start_vertex_index, const int num_vertices) { - evaluator->internal->eval_output->setVaryingDataFromBuffer( + evaluator->impl->eval_output->setVaryingDataFromBuffer( buffer, start_offset, stride, start_vertex_index, num_vertices); } @@ -82,13 +81,13 @@ void setFaceVaryingDataFromBuffer(OpenSubdiv_Evaluator *evaluator, const int start_vertex_index, const int num_vertices) { - evaluator->internal->eval_output->setFaceVaryingDataFromBuffer( + evaluator->impl->eval_output->setFaceVaryingDataFromBuffer( face_varying_channel, buffer, start_offset, stride, start_vertex_index, num_vertices); } void refine(OpenSubdiv_Evaluator *evaluator) { - evaluator->internal->eval_output->refine(); + evaluator->impl->eval_output->refine(); } void evaluateLimit(OpenSubdiv_Evaluator *evaluator, @@ -99,7 +98,7 @@ void evaluateLimit(OpenSubdiv_Evaluator *evaluator, float dPdu[3], float dPdv[3]) { - evaluator->internal->eval_output->evaluateLimit(ptex_face_index, face_u, face_v, P, dPdu, dPdv); + evaluator->impl->eval_output->evaluateLimit(ptex_face_index, face_u, face_v, P, dPdu, dPdv); } void evaluatePatchesLimit(OpenSubdiv_Evaluator *evaluator, @@ -109,7 +108,7 @@ void evaluatePatchesLimit(OpenSubdiv_Evaluator *evaluator, float *dPdu, float *dPdv) { - evaluator->internal->eval_output->evaluatePatchesLimit( + evaluator->impl->eval_output->evaluatePatchesLimit( patch_coords, num_patch_coords, P, dPdu, dPdv); } @@ -119,7 +118,7 @@ void evaluateVarying(OpenSubdiv_Evaluator *evaluator, float face_v, float varying[3]) { - evaluator->internal->eval_output->evaluateVarying(ptex_face_index, face_u, face_v, varying); + evaluator->impl->eval_output->evaluateVarying(ptex_face_index, face_u, face_v, varying); } void evaluateFaceVarying(OpenSubdiv_Evaluator *evaluator, @@ -129,7 +128,7 @@ void evaluateFaceVarying(OpenSubdiv_Evaluator *evaluator, float face_v, float face_varying[2]) { - evaluator->internal->eval_output->evaluateFaceVarying( + evaluator->impl->eval_output->evaluateFaceVarying( face_varying_channel, ptex_face_index, face_u, face_v, face_varying); } @@ -159,12 +158,12 @@ OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( { OpenSubdiv_Evaluator *evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator); assignFunctionPointers(evaluator); - evaluator->internal = openSubdiv_createEvaluatorInternal(topology_refiner); + evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner); return evaluator; } void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator) { - openSubdiv_deleteEvaluatorInternal(evaluator->internal); + openSubdiv_deleteEvaluatorInternal(evaluator->impl); OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator); } diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc index c35909a045b..341e8dbc233 100644 --- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc @@ -16,7 +16,7 @@ // // Author: Sergey Sharybin -#include "internal/opensubdiv_evaluator_internal.h" +#include "internal/evaluator/evaluator_impl.h" #include <cassert> #include <cstdio> @@ -37,8 +37,8 @@ #include "MEM_guardedalloc.h" -#include "internal/opensubdiv_topology_refiner_internal.h" -#include "internal/opensubdiv_util.h" +#include "internal/base/type.h" +#include "internal/topology/topology_refiner_impl.h" #include "opensubdiv_topology_refiner_capi.h" using OpenSubdiv::Far::PatchMap; @@ -53,7 +53,8 @@ using OpenSubdiv::Osd::CpuPatchTable; using OpenSubdiv::Osd::CpuVertexBuffer; using OpenSubdiv::Osd::PatchCoord; -namespace opensubdiv_capi { +namespace blender { +namespace opensubdiv { namespace { @@ -326,7 +327,7 @@ class VolatileEvalOutput { // Create evaluators for every face varying channel. face_varying_evaluators.reserve(all_face_varying_stencils.size()); int face_varying_channel = 0; - foreach (const StencilTable *face_varying_stencils, all_face_varying_stencils) { + for (const StencilTable *face_varying_stencils : all_face_varying_stencils) { face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel, face_varying_stencils, face_varying_width, @@ -344,7 +345,7 @@ class VolatileEvalOutput { delete patch_table_; delete vertex_stencils_; delete varying_stencils_; - foreach (FaceVaryingEval *face_varying_evaluator, face_varying_evaluators) { + for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) { delete face_varying_evaluator; } } @@ -413,7 +414,7 @@ class VolatileEvalOutput { } // Evaluate face-varying data. if (hasFaceVaryingData()) { - foreach (FaceVaryingEval *face_varying_evaluator, face_varying_evaluators) { + for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) { face_varying_evaluator->refine(); } } @@ -731,25 +732,26 @@ void CpuEvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_c } } -} // namespace opensubdiv_capi +} // namespace opensubdiv +} // namespace blender -OpenSubdiv_EvaluatorInternal::OpenSubdiv_EvaluatorInternal() +OpenSubdiv_EvaluatorImpl::OpenSubdiv_EvaluatorImpl() : eval_output(NULL), patch_map(NULL), patch_table(NULL) { } -OpenSubdiv_EvaluatorInternal::~OpenSubdiv_EvaluatorInternal() +OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl() { delete eval_output; delete patch_map; delete patch_table; } -OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal( +OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( OpenSubdiv_TopologyRefiner *topology_refiner) { - using opensubdiv_capi::vector; - TopologyRefiner *refiner = topology_refiner->internal->osd_topology_refiner; + using blender::opensubdiv::vector; + TopologyRefiner *refiner = topology_refiner->impl->topology_refiner; if (refiner == NULL) { // Happens on bad topology. return NULL; @@ -851,25 +853,25 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal( } // Create OpenSubdiv's CPU side evaluator. // TODO(sergey): Make it possible to use different evaluators. - opensubdiv_capi::CpuEvalOutput *eval_output = new opensubdiv_capi::CpuEvalOutput( + blender::opensubdiv::CpuEvalOutput *eval_output = new blender::opensubdiv::CpuEvalOutput( vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table); OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table); // Wrap everything we need into an object which we control from our side. - OpenSubdiv_EvaluatorInternal *evaluator_descr; - evaluator_descr = OBJECT_GUARDED_NEW(OpenSubdiv_EvaluatorInternal); - evaluator_descr->eval_output = new opensubdiv_capi::CpuEvalOutputAPI(eval_output, patch_map); + OpenSubdiv_EvaluatorImpl *evaluator_descr; + evaluator_descr = new OpenSubdiv_EvaluatorImpl(); + evaluator_descr->eval_output = new blender::opensubdiv::CpuEvalOutputAPI(eval_output, patch_map); evaluator_descr->patch_map = patch_map; evaluator_descr->patch_table = patch_table; // TOOD(sergey): Look into whether we've got duplicated stencils arrays. delete vertex_stencils; delete varying_stencils; - foreach (const StencilTable *table, all_face_varying_stencils) { + for (const StencilTable *table : all_face_varying_stencils) { delete table; } return evaluator_descr; } -void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorInternal *evaluator) +void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator) { - OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_EvaluatorInternal); + delete evaluator; } diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h index 392633944c6..6a3682efa62 100644 --- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h @@ -16,8 +16,8 @@ // // Author: Sergey Sharybin -#ifndef OPENSUBDIV_EVALUATOR_INTERNAL_H_ -#define OPENSUBDIV_EVALUATOR_INTERNAL_H_ +#ifndef OPENSUBDIV_EVALUATOR_IMPL_H_ +#define OPENSUBDIV_EVALUATOR_IMPL_H_ #ifdef _MSC_VER # include <iso646.h> @@ -26,10 +26,13 @@ #include <opensubdiv/far/patchMap.h> #include <opensubdiv/far/patchTable.h> +#include "internal/base/memory.h" + struct OpenSubdiv_PatchCoord; struct OpenSubdiv_TopologyRefiner; -namespace opensubdiv_capi { +namespace blender { +namespace opensubdiv { // Anonymous forward declaration of actual evaluator implementation. class CpuEvalOutput; @@ -132,21 +135,24 @@ class CpuEvalOutputAPI { OpenSubdiv::Far::PatchMap *patch_map_; }; -} // namespace opensubdiv_capi +} // namespace opensubdiv +} // namespace blender -struct OpenSubdiv_EvaluatorInternal { +struct OpenSubdiv_EvaluatorImpl { public: - OpenSubdiv_EvaluatorInternal(); - ~OpenSubdiv_EvaluatorInternal(); + OpenSubdiv_EvaluatorImpl(); + ~OpenSubdiv_EvaluatorImpl(); - opensubdiv_capi::CpuEvalOutputAPI *eval_output; + blender::opensubdiv::CpuEvalOutputAPI *eval_output; const OpenSubdiv::Far::PatchMap *patch_map; const OpenSubdiv::Far::PatchTable *patch_table; + + MEM_CXX_CLASS_ALLOC_FUNCS("OpenSubdiv_EvaluatorImpl"); }; -OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal( +OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( struct OpenSubdiv_TopologyRefiner *topology_refiner); -void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorInternal *evaluator); +void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator); -#endif // OPENSUBDIV_EVALUATOR_INTERNAL_H_ +#endif // OPENSUBDIV_EVALUATOR_IMPL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient.cc b/intern/opensubdiv/internal/opensubdiv_converter_orient.cc deleted file mode 100644 index e3367fc6314..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_converter_orient.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#include "internal/opensubdiv_converter_orient.h" - -#include "internal/opensubdiv_internal.h" - -namespace opensubdiv_capi { - -void checkOrientedVertexConnectivity(const int num_vertex_edges, - const int num_vertex_faces, - const int *vertex_edges, - const int *vertex_faces, - const int *dst_vertex_edges, - const int *dst_vertex_faces) -{ -#ifndef NDEBUG - for (int i = 0; i < num_vertex_faces; ++i) { - bool found = false; - for (int j = 0; j < num_vertex_faces; ++j) { - if (vertex_faces[i] == dst_vertex_faces[j]) { - found = true; - break; - } - } - if (!found) { - assert(!"vert-faces connectivity ruined"); - } - } - for (int i = 0; i < num_vertex_edges; ++i) { - bool found = false; - for (int j = 0; j < num_vertex_edges; ++j) { - if (vertex_edges[i] == dst_vertex_edges[j]) { - found = true; - break; - } - } - if (!found) { - assert(!"vert-edges connectivity ruined"); - } - } -#else - (void)num_vertex_edges; - (void)num_vertex_faces; - (void)vertex_edges; - (void)vertex_faces; - (void)dst_vertex_edges; - (void)dst_vertex_faces; -#endif -} - -} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient.h b/intern/opensubdiv/internal/opensubdiv_converter_orient.h deleted file mode 100644 index 967871845cb..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_converter_orient.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2018 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_CONVERTER_ORIENT_H_ -# define OPENSUBDIV_CONVERTER_ORIENT_H_ - -# include <opensubdiv/far/types.h> - -// Set of utility functions which are needed to bring topology to an orientation -// (or, winding, if you wish) which OpenSubdiv expects. - -namespace opensubdiv_capi { - -inline void reverseFaceVertices(int *face_vertices, const int num_vertices); - -// TODO(sergey): Document which value corresponds to which winding. -inline int getLoopWinding(int vert0_of_face, int vert1_of_face); - -inline void reverseFaceLoops(OpenSubdiv::Far::IndexArray *face_vertices, - OpenSubdiv::Far::IndexArray *face_edges); - -// Used for debugging, checks whether orientation happened correct. -void checkOrientedVertexConnectivity(const int num_vertex_edges, - const int num_vertex_faces, - const int *vertex_edges, - const int *vertex_faces, - const int *dst_vertex_edges, - const int *dst_vertex_faces); - -} // namespace opensubdiv_capi - -#endif // OPENSUBDIV_CONVERTER_ORIENT_H_ - -#include "internal/opensubdiv_converter_orient_impl.h" diff --git a/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h b/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h deleted file mode 100644 index aa717f5d99d..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_converter_orient_impl.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_ -#define OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_ - -#include "internal/opensubdiv_converter_orient.h" - -#include <cmath> - -#include "internal/opensubdiv_util.h" - -namespace opensubdiv_capi { - -inline void reverseFaceVertices(int *face_vertices, const int num_vertices) -{ - int last_vert = face_vertices[num_vertices - 1]; - for (int i = num_vertices - 1; i > 0; --i) { - face_vertices[i] = face_vertices[i - 1]; - } - face_vertices[0] = last_vert; -} - -inline int getLoopWinding(int vert0_of_face, int vert1_of_face) -{ - int delta_face = vert1_of_face - vert0_of_face; - if (abs(delta_face) != 1) { - if (delta_face > 0) { - delta_face = -1; - } - else { - delta_face = 1; - } - } - return delta_face; -} - -inline void reverseFaceLoops(OpenSubdiv::Far::IndexArray *face_vertices, - OpenSubdiv::Far::IndexArray *face_edges) -{ - const int num_face_vertices = face_vertices->size(); - for (int i = 0; i < num_face_vertices / 2; ++i) { - const int j = num_face_vertices - i - 1; - if (i != j) { - swap((*face_vertices)[i], (*face_vertices)[j]); - swap((*face_edges)[i], (*face_edges)[j]); - } - } - reverseFaceVertices(&(*face_vertices)[0], num_face_vertices); -} - -} // namespace opensubdiv_capi - -#endif // OPENSUBDIV_CONVERTER_ORIENT_IMPL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc deleted file mode 100644 index c0355ab24a8..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.cc +++ /dev/null @@ -1,234 +0,0 @@ -// Adopted from OpenSubdiv with the following license: -// -// Copyright 2015 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. - -#ifdef OPENSUBDIV_HAS_CUDA - -# ifdef _MSC_VER -# include <iso646.h> -# endif - -# include "opensubdiv_device_context_cuda.h" - -# if defined(_WIN32) -# include <windows.h> -# elif defined(__APPLE__) -# include <OpenGL/OpenGL.h> -# else -# include <GL/glx.h> -# include <X11/Xlib.h> -# endif - -# include <cstdio> -# include <cuda.h> -# include <cuda_gl_interop.h> -# include <cuda_runtime_api.h> - -# include "internal/opensubdiv_util.h" - -# define message(fmt, ...) -// #define message(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) -# define error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) - -namespace { - -int getCudaDeviceForCurrentGLContext() -{ - // Find and use the CUDA device for the current GL context - unsigned int interop_device_count = 0; - int interopDevices[1]; - cudaError_t status = cudaGLGetDevices( - &interop_device_count, interopDevices, 1, cudaGLDeviceListCurrentFrame); - if (status == cudaErrorNoDevice || interop_device_count != 1) { - message("CUDA no interop devices found.\n"); - return 0; - } - int device = interopDevices[0]; -# if defined(_WIN32) - return device; -# elif defined(__APPLE__) - return device; -# else // X11 - Display *display = glXGetCurrentDisplay(); - int screen = DefaultScreen(display); - if (device != screen) { - error( - "The CUDA interop device (%d) does not match " - "the screen used by the current GL context (%d), " - "which may cause slow performance on systems " - "with multiple GPU devices.", - device, - screen); - } - message("CUDA init using device for current GL context: %d\n", device); - return device; -# endif -} - -// Beginning of GPU Architecture definitions. -int convertSMVer2Cores_local(int major, int minor) -{ - // Defines for GPU Architecture types (using the SM version to determine - // the # of cores per SM - typedef struct { - int SM; // 0xMm (hexidecimal notation), - // M = SM Major version, - // and m = SM minor version - int Cores; - } sSMtoCores; - - sSMtoCores nGpuArchCoresPerSM[] = {{0x10, 8}, // Tesla Generation (SM 1.0) G80 class. - {0x11, 8}, // Tesla Generation (SM 1.1) G8x class. - {0x12, 8}, // Tesla Generation (SM 1.2) G9x class. - {0x13, 8}, // Tesla Generation (SM 1.3) GT200 class. - {0x20, 32}, // Fermi Generation (SM 2.0) GF100 class. - {0x21, 48}, // Fermi Generation (SM 2.1) GF10x class. - {0x30, 192}, // Fermi Generation (SM 3.0) GK10x class. - {-1, -1}}; - int index = 0; - while (nGpuArchCoresPerSM[index].SM != -1) { - if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor)) { - return nGpuArchCoresPerSM[index].Cores; - } - index++; - } - printf("MapSMtoCores undefined SMversion %d.%d!\n", major, minor); - return -1; -} - -// This function returns the best GPU (with maximum GFLOPS). -int cutGetMaxGflopsDeviceId() -{ - int current_device = 0, sm_per_multiproc = 0; - int max_compute_perf = 0, max_perf_device = -1; - int device_count = 0, best_SM_arch = 0; - int compat_major, compat_minor; - cuDeviceGetCount(&device_count); - // Find the best major SM Architecture GPU device. - while (current_device < device_count) { - cuDeviceComputeCapability(&compat_major, &compat_minor, current_device); - if (compat_major > 0 && compat_major < 9999) { - best_SM_arch = max(best_SM_arch, compat_major); - } - current_device++; - } - // Find the best CUDA capable GPU device. - current_device = 0; - while (current_device < device_count) { - cuDeviceComputeCapability(&compat_major, &compat_minor, current_device); - if (compat_major == 9999 && compat_minor == 9999) { - sm_per_multiproc = 1; - } - else { - sm_per_multiproc = convertSMVer2Cores_local(compat_major, compat_minor); - } - int multi_processor_count; - cuDeviceGetAttribute( - &multi_processor_count, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, current_device); - int clock_rate; - cuDeviceGetAttribute(&clock_rate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, current_device); - int compute_perf = multi_processor_count * sm_per_multiproc * clock_rate; - if (compute_perf > max_compute_perf) { - /* If we find GPU with SM major > 2, search only these */ - if (best_SM_arch > 2) { - /* If our device==dest_SM_arch, choose this, or else pass. */ - if (compat_major == best_SM_arch) { - max_compute_perf = compute_perf; - max_perf_device = current_device; - } - } - else { - max_compute_perf = compute_perf; - max_perf_device = current_device; - } - } - ++current_device; - } - return max_perf_device; -} - -} // namespace - -bool CudaDeviceContext::HAS_CUDA_VERSION_4_0() -{ -# ifdef OPENSUBDIV_HAS_CUDA - static bool cuda_initialized = false; - static bool cuda_load_success = true; - if (!cuda_initialized) { - cuda_initialized = true; - -# ifdef OPENSUBDIV_HAS_CUEW - cuda_load_success = cuewInit(CUEW_INIT_CUDA) == CUEW_SUCCESS; - if (!cuda_load_success) { - fprintf(stderr, "Loading CUDA failed.\n"); - } -# endif - // Need to initialize CUDA here so getting device - // with the maximum FPLOS works fine. - if (cuInit(0) == CUDA_SUCCESS) { - // This is to deal with cases like NVidia Optimus, - // when there might be CUDA library installed but - // NVidia card is not being active. - if (cutGetMaxGflopsDeviceId() < 0) { - cuda_load_success = false; - } - } - else { - cuda_load_success = false; - } - } - return cuda_load_success; -# else - return false; -# endif -} - -CudaDeviceContext::CudaDeviceContext() : initialized_(false) -{ -} - -CudaDeviceContext::~CudaDeviceContext() -{ - cudaDeviceReset(); -} - -bool CudaDeviceContext::Initialize() -{ - // See if any cuda device is available. - int device_count = 0; - cudaGetDeviceCount(&device_count); - message("CUDA device count: %d\n", device_count); - if (device_count <= 0) { - return false; - } - cudaGLSetGLDevice(getCudaDeviceForCurrentGLContext()); - initialized_ = true; - return true; -} - -bool CudaDeviceContext::IsInitialized() const -{ - return initialized_; -} - -#endif // OPENSUBDIV_HAS_CUDA diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h b/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h deleted file mode 100644 index 10164e0cfc5..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_device_context_cuda.h +++ /dev/null @@ -1,54 +0,0 @@ -// Adopted from OpenSubdiv with the following license: -// -// Copyright 2013 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http: //www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. - -#ifndef OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ -#define OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ - -#ifdef OPENSUBDIV_HAS_CUDA - -struct ID3D11Device; - -class CudaDeviceContext { - public: - CudaDeviceContext(); - ~CudaDeviceContext(); - - static bool HAS_CUDA_VERSION_4_0(); - - // Initialze cuda device from the current GL context. - bool Initialize(); - - // Initialze cuda device from the ID3D11Device. - bool Initialize(ID3D11Device *device); - - // Returns true if the cuda device has already been initialized. - bool IsInitialized() const; - - private: - bool initialized_; -}; - -#endif // OPENSUBDIV_HAS_CUDA - -#endif // _OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc deleted file mode 100644 index 72285930889..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.cc +++ /dev/null @@ -1,258 +0,0 @@ -// Adopted from OpenSubdiv with the following license: -// -// Copyright 2015 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. - -#include "opensubdiv_device_context_opencl.h" - -#ifdef OPENSUBDIV_HAS_OPENCL - -# if defined(_WIN32) -# include <windows.h> -# elif defined(__APPLE__) -# include <OpenGL/OpenGL.h> -# else -# include <GL/glx.h> -# endif - -# include <cstdio> -# include <cstring> - -# include "internal/opensubdiv_util.h" - -# define message(...) // fprintf(stderr, __VA_ARGS__) -# define error(...) fprintf(stderr, __VA_ARGS__) - -namespace { - -// Returns the first found platform. -cl_platform_id findPlatform() -{ - cl_uint num_platforms; - cl_int ci_error_number = clGetPlatformIDs(0, NULL, &num_platforms); - if (ci_error_number != CL_SUCCESS) { - error("Error %d in clGetPlatformIDs call.\n", ci_error_number); - return NULL; - } - if (num_platforms == 0) { - error("No OpenCL platform found.\n"); - return NULL; - } - vector<cl_platform_id> cl_platform_ids(num_platforms); - ci_error_number = clGetPlatformIDs(num_platforms, &cl_platform_ids[0], NULL); - char ch_buffer[1024]; - for (cl_uint i = 0; i < num_platforms; ++i) { - ci_error_number = clGetPlatformInfo( - cl_platform_ids[i], CL_PLATFORM_NAME, sizeof(ch_buffer), ch_buffer, NULL); - if (ci_error_number == CL_SUCCESS) { - cl_platform_id platform_id = cl_platform_ids[i]; - return platform_id; - } - } - return NULL; -} - -// Return the device in cl_devices which supports the extension. -int findExtensionSupportedDevice(cl_device_id *cl_devices, - int num_devices, - const char *extension_name) -{ - // Find a device that supports sharing with GL/D3D11 - // (SLI / X-fire configurations) - cl_int cl_error_number; - for (int i = 0; i < num_devices; ++i) { - // Get extensions string size. - size_t extensions_size; - cl_error_number = clGetDeviceInfo( - cl_devices[i], CL_DEVICE_EXTENSIONS, 0, NULL, &extensions_size); - if (cl_error_number != CL_SUCCESS) { - error("Error %d in clGetDeviceInfo\n", cl_error_number); - return -1; - } - if (extensions_size > 0) { - // Get extensions string. - string extensions('\0', extensions_size); - cl_error_number = clGetDeviceInfo( - cl_devices[i], CL_DEVICE_EXTENSIONS, extensions_size, &extensions[0], &extensions_size); - if (cl_error_number != CL_SUCCESS) { - error("Error %d in clGetDeviceInfo\n", cl_error_number); - continue; - } - // Parse string. This is bit deficient since the extentions - // is space separated. - // - // The actual string would be "cl_khr_d3d11_sharing" - // or "cl_nv_d3d11_sharing" - if (extensions.find(extension_name) != string::npos) { - return i; - } - } - } - return -1; -} - -} // namespace - -CLDeviceContext::CLDeviceContext() : cl_context_(NULL), cl_command_queue_(NULL) -{ -} - -CLDeviceContext::~CLDeviceContext() -{ - if (cl_command_queue_) { - clReleaseCommandQueue(cl_command_queue_); - } - if (cl_context_) { - clReleaseContext(cl_context_); - } -} - -bool CLDeviceContext::HAS_CL_VERSION_1_1() -{ -# ifdef OPENSUBDIV_HAS_CLEW - static bool clew_initialized = false; - static bool clew_load_success; - if (!clew_initialized) { - clew_initialized = true; - clew_load_success = clewInit() == CLEW_SUCCESS; - if (!clew_load_success) { - error("Loading OpenCL failed.\n"); - } - } - return clew_load_success; -# endif - return true; -} - -bool CLDeviceContext::Initialize() -{ -# ifdef OPENSUBDIV_HAS_CLEW - if (!clGetPlatformIDs) { - error("Error clGetPlatformIDs function not bound.\n"); - return false; - } -# endif - cl_int cl_error_number; - cl_platform_id cp_platform = findPlatform(); - -# if defined(_WIN32) - cl_context_properties props[] = { - CL_GL_CONTEXT_KHR, - (cl_context_properties)wglGetCurrentContext(), - CL_WGL_HDC_KHR, - (cl_context_properties)wglGetCurrentDC(), - CL_CONTEXT_PLATFORM, - (cl_context_properties)cp_platform, - 0, - }; -# elif defined(__APPLE__) - CGLContextObj kCGLContext = CGLGetCurrentContext(); - CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext); - cl_context_properties props[] = { - CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup, 0}; -# else - cl_context_properties props[] = { - CL_GL_CONTEXT_KHR, - (cl_context_properties)glXGetCurrentContext(), - CL_GLX_DISPLAY_KHR, - (cl_context_properties)glXGetCurrentDisplay(), - CL_CONTEXT_PLATFORM, - (cl_context_properties)cp_platform, - 0, - }; -# endif - -# if defined(__APPLE__) - _clContext = clCreateContext(props, 0, NULL, clLogMessagesToStdoutAPPLE, NULL, &cl_error_number); - if (cl_error_number != CL_SUCCESS) { - error("Error %d in clCreateContext\n", cl_error_number); - return false; - } - size_t devices_size = 0; - clGetGLContextInfoAPPLE(_clContext, - kCGLContext, - CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE, - 0, - NULL, - &devices_size); - const int num_devices = devices_size / sizeof(cl_device_id); - if (num_devices == 0) { - error("No sharable devices.\n"); - return false; - } - vector<cl_device_id> cl_devices(num_devices); - clGetGLContextInfoAPPLE(_clContext, - kCGLContext, - CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE, - num_devices * sizeof(cl_device_id), - &cl_devices[0], - NULL); - int cl_device_used = 0; -# else // not __APPLE__ - // Get the number of GPU devices available to the platform. - cl_uint num_devices = 0; - clGetDeviceIDs(cp_platform, CL_DEVICE_TYPE_GPU, 0, NULL, &num_devices); - if (num_devices == 0) { - error("No CL GPU device found.\n"); - return false; - } - // Create the device list. - vector<cl_device_id> cl_devices(num_devices); - clGetDeviceIDs(cp_platform, CL_DEVICE_TYPE_GPU, num_devices, &cl_devices[0], NULL); - const char *extension = "cl_khr_gl_sharing"; - int cl_device_used = findExtensionSupportedDevice(&cl_devices[0], num_devices, extension); - if (cl_device_used < 0) { - error("No device found that supports CL/GL context sharing\n"); - return false; - } - cl_context_ = clCreateContext( - props, 1, &cl_devices[cl_device_used], NULL, NULL, &cl_error_number); -# endif // not __APPLE__ - if (cl_error_number != CL_SUCCESS) { - error("Error %d in clCreateContext\n", cl_error_number); - return false; - } - cl_command_queue_ = clCreateCommandQueue( - cl_context_, cl_devices[cl_device_used], 0, &cl_error_number); - if (cl_error_number != CL_SUCCESS) { - error("Error %d in clCreateCommandQueue\n", cl_error_number); - return false; - } - return true; -} - -bool CLDeviceContext::IsInitialized() const -{ - return (cl_context_ != NULL); -} - -cl_context CLDeviceContext::GetContext() const -{ - return cl_context_; -} - -cl_command_queue CLDeviceContext::GetCommandQueue() const -{ - return cl_command_queue_; -} - -#endif // OPENSUBDIV_HAS_OPENCL diff --git a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h b/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h deleted file mode 100644 index 6baf0774319..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_device_context_opencl.h +++ /dev/null @@ -1,52 +0,0 @@ -// Adopted from OpenSubdiv with the following license: -// -// Copyright 2015 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. - -#ifndef OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ -#define OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ - -#ifdef OPENSUBDIV_HAS_OPENCL -# include <opensubdiv/osd/opencl.h> - -class CLDeviceContext { - public: - static bool HAS_CL_VERSION_1_1(); - - CLDeviceContext(); - ~CLDeviceContext(); - - bool Initialize(); - - bool IsInitialized() const; - - cl_context GetContext() const; - cl_command_queue GetCommandQueue() const; - - protected: - cl_context cl_context_; - cl_command_queue cl_command_queue_; -}; - -#endif // OPENSUBDIV_HAS_OPENCL - -#endif // _OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_edge_map.h b/intern/opensubdiv/internal/opensubdiv_edge_map.h deleted file mode 100644 index e2e6d2328fe..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_edge_map.h +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_EDGE_MAP_H_ -#define OPENSUBDIV_EDGE_MAP_H_ - -#include "internal/opensubdiv_util.h" - -namespace opensubdiv_capi { - -// Helper class to ease dealing with edge indexing. -// Simply takes care of ensuring order of vertices is strictly defined. -class EdgeKey { - public: - inline EdgeKey(); - inline EdgeKey(int v1, int v2); - - inline size_t hash() const; - inline bool operator==(const EdgeKey &other) const; - - // These indices are guaranteed to be so v1 < v2. - int v1; - int v2; -}; - -// Map from an edge defined by its vertices index to a custom tag value. -template<typename T> class EdgeTagMap { - public: - typedef EdgeKey key_type; - typedef T value_type; - - inline EdgeTagMap(); - - // Modifiers. - inline void clear(); - inline void insert(const key_type &key, const value_type &value); - inline void insert(int v1, int v2, const value_type &value); - - // Lookup. - value_type &at(const key_type &key); - value_type &at(key_type &&key); - value_type &at(int v1, int v2); - - value_type &operator[](const key_type &key); - value_type &operator[](key_type &&key); - - protected: - unordered_map<key_type, value_type> edge_tags_; -}; - -//////////////////////////////////////////////////////////////////////////////// -// Implementation. - -// EdgeKey. - -EdgeKey::EdgeKey() : v1(-1), v2(-1) -{ -} - -EdgeKey::EdgeKey(int v1, int v2) -{ - assert(v1 >= 0); - assert(v2 >= 0); - assert(v1 != v2); - if (v1 < v2) { - this->v1 = v1; - this->v2 = v2; - } - else { - this->v1 = v2; - this->v2 = v1; - } -} - -size_t EdgeKey::hash() const -{ - return (static_cast<uint64_t>(v1) << 32) | v2; -} - -bool EdgeKey::operator==(const EdgeKey &other) const -{ - return v1 == other.v1 && v2 == other.v2; -} - -// EdgeTagMap. - -template<typename T> EdgeTagMap<T>::EdgeTagMap() -{ -} - -template<typename T> void EdgeTagMap<T>::clear() -{ - edge_tags_.clear(); -} - -template<typename T> void EdgeTagMap<T>::insert(const key_type &key, const value_type &value) -{ - edge_tags_.insert(make_pair(key, value)); -} - -template<typename T> void EdgeTagMap<T>::insert(int v1, int v2, const value_type &value) -{ - insert(EdgeKey(v1, v2), value); -} - -template<typename T> typename EdgeTagMap<T>::value_type &EdgeTagMap<T>::at(const key_type &key) -{ - return edge_tags_.at[key]; -} - -template<typename T> typename EdgeTagMap<T>::value_type &EdgeTagMap<T>::at(key_type &&key) -{ - return edge_tags_.at[key]; -} - -template<typename T> typename EdgeTagMap<T>::value_type &EdgeTagMap<T>::at(int v1, int v2) -{ - return edge_tags_.at(EdgeKey(v1, v2)); -} - -template<typename T> -typename EdgeTagMap<T>::value_type &EdgeTagMap<T>::operator[](const key_type &key) -{ - return edge_tags_[key]; -} - -template<typename T> typename EdgeTagMap<T>::value_type &EdgeTagMap<T>::operator[](key_type &&key) -{ - return edge_tags_[key]; -} - -} // namespace opensubdiv_capi - -namespace std { - -template<> struct hash<opensubdiv_capi::EdgeKey> { - std::size_t operator()(const opensubdiv_capi::EdgeKey &key) const - { - return key.hash(); - } -}; - -} // namespace std - -#endif // OPENSUBDIV_EDGE_MAP_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc deleted file mode 100644 index 6afd763a63e..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2013 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -#include "opensubdiv_gl_mesh_capi.h" - -#ifdef _MSC_VER -# include <iso646.h> -#endif - -#include <opensubdiv/far/stencilTable.h> -#include <opensubdiv/osd/glMesh.h> -#include <opensubdiv/osd/glPatchTable.h> - -using OpenSubdiv::Far::StencilTable; -using OpenSubdiv::Osd::GLMeshInterface; -using OpenSubdiv::Osd::GLPatchTable; -using OpenSubdiv::Osd::Mesh; -using OpenSubdiv::Osd::MeshBitset; - -// CPU backend. -#include <opensubdiv/osd/cpuEvaluator.h> -#include <opensubdiv/osd/cpuGLVertexBuffer.h> -using OpenSubdiv::Osd::CpuEvaluator; -using OpenSubdiv::Osd::CpuGLVertexBuffer; -typedef Mesh<CpuGLVertexBuffer, StencilTable, CpuEvaluator, GLPatchTable> OsdCpuMesh; -// OpenMP backend. -#ifdef OPENSUBDIV_HAS_OPENMP -# include <opensubdiv/osd/ompEvaluator.h> -using OpenSubdiv::Osd::OmpEvaluator; -typedef Mesh<CpuGLVertexBuffer, StencilTable, OmpEvaluator, GLPatchTable> OsdOmpMesh; -#endif -// OpenCL backend. -#ifdef OPENSUBDIV_HAS_OPENCL -# include "opensubdiv_device_context_opencl.h" -# include <opensubdiv/osd/clEvaluator.h> -# include <opensubdiv/osd/clGLVertexBuffer.h> -using OpenSubdiv::Osd::CLEvaluator; -using OpenSubdiv::Osd::CLGLVertexBuffer; -using OpenSubdiv::Osd::CLStencilTable; -/* TODO(sergey): Use CLDeviceContext similar to OSD examples? */ -typedef Mesh<CLGLVertexBuffer, CLStencilTable, CLEvaluator, GLPatchTable, CLDeviceContext> - OsdCLMesh; -static CLDeviceContext g_cl_device_context; -#endif -// CUDA backend. -#ifdef OPENSUBDIV_HAS_CUDA -# include "opensubdiv_device_context_cuda.h" -# include <opensubdiv/osd/cudaEvaluator.h> -# include <opensubdiv/osd/cudaGLVertexBuffer.h> -using OpenSubdiv::Osd::CudaEvaluator; -using OpenSubdiv::Osd::CudaGLVertexBuffer; -using OpenSubdiv::Osd::CudaStencilTable; -typedef Mesh<CudaGLVertexBuffer, CudaStencilTable, CudaEvaluator, GLPatchTable> OsdCudaMesh; -static CudaDeviceContext g_cuda_device_context; -#endif -// Transform feedback backend. -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK -# include <opensubdiv/osd/glVertexBuffer.h> -# include <opensubdiv/osd/glXFBEvaluator.h> -using OpenSubdiv::Osd::GLStencilTableTBO; -using OpenSubdiv::Osd::GLVertexBuffer; -using OpenSubdiv::Osd::GLXFBEvaluator; -typedef Mesh<GLVertexBuffer, GLStencilTableTBO, GLXFBEvaluator, GLPatchTable> - OsdGLSLTransformFeedbackMesh; -#endif -// GLSL compute backend. -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE -# include <opensubdiv/osd/glComputeEvaluator.h> -# include <opensubdiv/osd/glVertexBuffer.h> -using OpenSubdiv::Osd::GLComputeEvaluator; -using OpenSubdiv::Osd::GLStencilTableSSBO; -using OpenSubdiv::Osd::GLVertexBuffer; -typedef Mesh<GLVertexBuffer, GLStencilTableSSBO, GLComputeEvaluator, GLPatchTable> - OsdGLSLComputeMesh; -#endif - -#include "MEM_guardedalloc.h" - -#include "internal/opensubdiv_gl_mesh_draw.h" -#include "internal/opensubdiv_gl_mesh_fvar.h" -#include "internal/opensubdiv_gl_mesh_internal.h" -#include "internal/opensubdiv_topology_refiner_internal.h" -#include "internal/opensubdiv_util.h" -#include "opensubdiv_topology_refiner_capi.h" - -using opensubdiv_capi::vector; - -namespace { - -GLMeshInterface *createGLMeshInterface(OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const MeshBitset &bits, - const int num_vertex_elements, - const int num_varying_elements, - const int level, - eOpenSubdivEvaluator evaluator_type) -{ - GLMeshInterface *mesh = NULL; - switch (evaluator_type) { -#define CHECK_EVALUATOR_TYPE(type, class) \ - case OPENSUBDIV_EVALUATOR_##type: \ - mesh = new class(topology_refiner, num_vertex_elements, num_varying_elements, level, bits); \ - break; - -#define CHECK_EVALUATOR_TYPE_STUB(type) \ - case OPENSUBDIV_EVALUATOR_##type: \ - mesh = NULL; \ - break; - - CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh) -#ifdef OPENSUBDIV_HAS_OPENMP - CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh) -#else - CHECK_EVALUATOR_TYPE_STUB(OPENMP) -#endif -#ifdef OPENSUBDIV_HAS_OPENCL - CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh) -#else - CHECK_EVALUATOR_TYPE_STUB(OPENCL) -#endif -#ifdef OPENSUBDIV_HAS_CUDA - CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh) -#else - CHECK_EVALUATOR_TYPE_STUB(CUDA) -#endif -#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK - CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK, OsdGLSLTransformFeedbackMesh) -#else - CHECK_EVALUATOR_TYPE_STUB(GLSL_TRANSFORM_FEEDBACK) -#endif -#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE - CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh) -#else - CHECK_EVALUATOR_TYPE_STUB(GLSL_COMPUTE) -#endif - -#undef CHECK_EVALUATOR_TYPE -#undef CHECK_EVALUATOR_TYPE_STUB - } - return mesh; -} - -//////////////////////////////////////////////////////////////////////////////// -// GLMesh structure "methods". - -opensubdiv_capi::GLMeshFVarData *createFVarData(OpenSubdiv::Far::TopologyRefiner *topology_refiner, - GLMeshInterface *mesh, - const float *fvar_src_buffer) -{ - using opensubdiv_capi::GLMeshFVarData; - GLMeshFVarData *fvar_data = new GLMeshFVarData(); - fvar_data->create(topology_refiner, mesh->GetFarPatchTable(), 2, fvar_src_buffer); - return fvar_data; -} - -unsigned int getPatchIndexBuffer(OpenSubdiv_GLMesh *gl_mesh) -{ - return gl_mesh->internal->mesh_interface->GetPatchTable()->GetPatchIndexBuffer(); -} - -void bindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh) -{ - gl_mesh->internal->mesh_interface->BindVertexBuffer(); -} - -void setCoarsePositions(OpenSubdiv_GLMesh *gl_mesh, - const float *positions, - const int start_vertex, - const int num_vertices) -{ - gl_mesh->internal->mesh_interface->UpdateVertexBuffer(positions, start_vertex, num_vertices); -} - -void refine(OpenSubdiv_GLMesh *gl_mesh) -{ - gl_mesh->internal->mesh_interface->Refine(); -} - -void synchronize(struct OpenSubdiv_GLMesh *gl_mesh) -{ - gl_mesh->internal->mesh_interface->Synchronize(); -} - -void assignFunctionPointers(OpenSubdiv_GLMesh *gl_mesh) -{ - gl_mesh->getPatchIndexBuffer = getPatchIndexBuffer; - gl_mesh->bindVertexBuffer = bindVertexBuffer; - gl_mesh->setCoarsePositions = setCoarsePositions; - gl_mesh->refine = refine; - gl_mesh->synchronize = synchronize; - - gl_mesh->prepareDraw = opensubdiv_capi::GLMeshDisplayPrepare; - gl_mesh->drawPatches = opensubdiv_capi::GLMeshDisplayDrawPatches; -} - -} // namespace - -struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( - OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type) -{ - using OpenSubdiv::Far::TopologyRefiner; - TopologyRefiner *osd_topology_refiner = topology_refiner->internal->osd_topology_refiner; - // TODO(sergey): Query this from refiner. - const bool is_adaptive = false; - MeshBitset bits; - bits.set(OpenSubdiv::Osd::MeshAdaptive, is_adaptive); - bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0); - bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1); - bits.set(OpenSubdiv::Osd::MeshFVarData, 1); - bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1); - const int num_vertex_elements = 3; - const int num_varying_elements = 3; - GLMeshInterface *mesh = createGLMeshInterface(osd_topology_refiner, - bits, - num_vertex_elements, - num_varying_elements, - osd_topology_refiner->GetMaxLevel(), - evaluator_type); - if (mesh == NULL) { - return NULL; - } - OpenSubdiv_GLMesh *gl_mesh = OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh); - assignFunctionPointers(gl_mesh); - gl_mesh->internal = new OpenSubdiv_GLMeshInternal(); - gl_mesh->internal->evaluator_type = evaluator_type; - gl_mesh->internal->mesh_interface = mesh; - // Face-varying support. - // TODO(sergey): This part needs to be re-done. - if (osd_topology_refiner->GetNumFVarChannels() > 0) { - // TODO(sergey): This is a temporary stub to get things compiled. Need - // to store base level UVs somewhere else. - vector<float> uvs; - vector<float> fvar_data_buffer; - opensubdiv_capi::interpolateFVarData(*osd_topology_refiner, uvs, &fvar_data_buffer); - gl_mesh->internal->fvar_data = createFVarData( - osd_topology_refiner, mesh, &fvar_data_buffer[0]); - } - else { - gl_mesh->internal->fvar_data = NULL; - } - return gl_mesh; -} - -void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh) -{ - delete gl_mesh->internal; - OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh); -} diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc deleted file mode 100644 index cbccf69e02d..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.cc +++ /dev/null @@ -1,577 +0,0 @@ -// Copyright 2013 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#include "internal/opensubdiv_gl_mesh_draw.h" - -#ifdef _MSC_VER -# include <iso646.h> -#endif - -#include <GL/glew.h> -#include <cmath> -#include <cstdio> - -#include <opensubdiv/osd/glMesh.h> - -#ifdef OPENSUBDIV_HAS_CUDA -# include <opensubdiv/osd/cudaGLVertexBuffer.h> -#endif // OPENSUBDIV_HAS_CUDA - -#include <opensubdiv/osd/cpuEvaluator.h> -#include <opensubdiv/osd/cpuGLVertexBuffer.h> - -#include "internal/opensubdiv_gl_mesh_fvar.h" -#include "internal/opensubdiv_gl_mesh_internal.h" -#include "internal/opensubdiv_util.h" -#include "opensubdiv_capi.h" -#include "opensubdiv_gl_mesh_capi.h" - -using OpenSubdiv::Osd::GLMeshInterface; - -extern "C" char datatoc_gpu_shader_opensubdiv_vertex_glsl[]; -extern "C" char datatoc_gpu_shader_opensubdiv_geometry_glsl[]; -extern "C" char datatoc_gpu_shader_opensubdiv_fragment_glsl[]; - -// TODO(sergey): Those are a bit of bad level calls :S -extern "C" { -void copy_m3_m3(float m1[3][3], float m2[3][3]); -void copy_m3_m4(float m1[3][3], float m2[4][4]); -void adjoint_m3_m3(float m1[3][3], float m[3][3]); -float determinant_m3_array(float m[3][3]); -bool invert_m3_m3(float m1[3][3], float m2[3][3]); -bool invert_m3(float m[3][3]); -void transpose_m3(float mat[3][3]); -} - -#define MAX_LIGHTS 8 -#define SUPPORT_COLOR_MATERIAL - -typedef struct Light { - float position[4]; - float ambient[4]; - float diffuse[4]; - float specular[4]; - float spot_direction[4]; -#ifdef SUPPORT_COLOR_MATERIAL - float constant_attenuation; - float linear_attenuation; - float quadratic_attenuation; - float spot_cutoff; - float spot_exponent; - float spot_cos_cutoff; - float pad, pad2; -#endif -} Light; - -typedef struct Lighting { - Light lights[MAX_LIGHTS]; - int num_enabled; -} Lighting; - -typedef struct Transform { - float projection_matrix[16]; - float model_view_matrix[16]; - float normal_matrix[9]; -} Transform; - -static bool g_use_osd_glsl = false; -static int g_active_uv_index = 0; - -static GLuint g_flat_fill_solid_program = 0; -static GLuint g_flat_fill_texture2d_program = 0; -static GLuint g_smooth_fill_solid_program = 0; -static GLuint g_smooth_fill_texture2d_program = 0; - -static GLuint g_flat_fill_solid_shadeless_program = 0; -static GLuint g_flat_fill_texture2d_shadeless_program = 0; -static GLuint g_smooth_fill_solid_shadeless_program = 0; -static GLuint g_smooth_fill_texture2d_shadeless_program = 0; - -static GLuint g_wireframe_program = 0; - -static GLuint g_lighting_ub = 0; -static Lighting g_lighting_data; -static Transform g_transform; - -namespace { - -GLuint compileShader(GLenum shaderType, - const char *version, - const char *define, - const char *source) -{ - const char *sources[] = { - version, - define, -#ifdef SUPPORT_COLOR_MATERIAL - "#define SUPPORT_COLOR_MATERIAL\n", -#else - "", -#endif - source, - }; - - GLuint shader = glCreateShader(shaderType); - glShaderSource(shader, 4, sources, NULL); - glCompileShader(shader); - - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLchar emsg[1024]; - glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg); - fprintf(stderr, "Error compiling GLSL: %s\n", emsg); - fprintf(stderr, "Version: %s\n", version); - fprintf(stderr, "Defines: %s\n", define); - fprintf(stderr, "Source: %s\n", source); - return 0; - } - - return shader; -} - -GLuint linkProgram(const char *version, const char *define) -{ - GLuint vertexShader = compileShader( - GL_VERTEX_SHADER, version, define, datatoc_gpu_shader_opensubdiv_vertex_glsl); - if (vertexShader == 0) { - return 0; - } - GLuint geometryShader = compileShader( - GL_GEOMETRY_SHADER, version, define, datatoc_gpu_shader_opensubdiv_geometry_glsl); - if (geometryShader == 0) { - return 0; - } - GLuint fragmentShader = compileShader( - GL_FRAGMENT_SHADER, version, define, datatoc_gpu_shader_opensubdiv_fragment_glsl); - if (fragmentShader == 0) { - return 0; - } - - GLuint program = glCreateProgram(); - - glAttachShader(program, vertexShader); - glAttachShader(program, geometryShader); - glAttachShader(program, fragmentShader); - - glBindAttribLocation(program, 0, "position"); - glBindAttribLocation(program, 1, "normal"); - - glLinkProgram(program); - - glDeleteShader(vertexShader); - glDeleteShader(geometryShader); - glDeleteShader(fragmentShader); - - GLint status; - glGetProgramiv(program, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - GLchar emsg[1024]; - glGetProgramInfoLog(program, sizeof(emsg), 0, emsg); - fprintf(stderr, "Error linking GLSL program : %s\n", emsg); - fprintf(stderr, "Defines: %s\n", define); - glDeleteProgram(program); - return 0; - } - - glUniformBlockBinding(program, glGetUniformBlockIndex(program, "Lighting"), 0); - - if (GLEW_VERSION_4_1) { - glProgramUniform1i(program, glGetUniformLocation(program, "texture_buffer"), 0); - glProgramUniform1i(program, glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30); - glProgramUniform1i(program, glGetUniformLocation(program, "FVarDataBuffer"), 31); - } - else { - glUseProgram(program); - glUniform1i(glGetUniformLocation(program, "texture_buffer"), 0); - glUniform1i(glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30); - glUniform1i(glGetUniformLocation(program, "FVarDataBuffer"), 31); - glUseProgram(0); - } - - return program; -} - -void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) -{ - glUseProgram(program); - // Matrices - glUniformMatrix4fv( - glGetUniformLocation(program, "modelViewMatrix"), 1, false, g_transform.model_view_matrix); - glUniformMatrix4fv( - glGetUniformLocation(program, "projectionMatrix"), 1, false, g_transform.projection_matrix); - glUniformMatrix3fv( - glGetUniformLocation(program, "normalMatrix"), 1, false, g_transform.normal_matrix); - // Lighting. - glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(g_lighting_data), &g_lighting_data); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub); - // Color. - { - // TODO(sergey): Stop using glGetMaterial. - float color[4]; - glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color); - glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); - glGetMaterialfv(GL_FRONT, GL_SPECULAR, color); - glUniform4fv(glGetUniformLocation(program, "specular"), 1, color); - glGetMaterialfv(GL_FRONT, GL_SHININESS, color); - glUniform1f(glGetUniformLocation(program, "shininess"), color[0]); - } - // Face-vertex data. - opensubdiv_capi::GLMeshFVarData *fvar_data = gl_mesh->internal->fvar_data; - if (fvar_data != NULL) { - if (fvar_data->texture_buffer) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer); - glActiveTexture(GL_TEXTURE0); - } - if (fvar_data->offset_buffer) { - glActiveTexture(GL_TEXTURE30); - glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer); - glActiveTexture(GL_TEXTURE0); - } - glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), fvar_data->fvar_width); - if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) { - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), - fvar_data->channel_offsets[g_active_uv_index]); - } - else { - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); - } - } - else { - glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); - } -} - -} // namespace - -bool openSubdiv_initGLMeshDrawingResources(void) -{ - static bool need_init = true; - static bool init_success = false; - if (!need_init) { - return init_success; - } - // TODO(sergey): Update OSD drawing to OpenGL 3.3 core, - // then remove following line. - return false; - const char *version = ""; - if (GLEW_VERSION_3_2) { - version = "#version 150 compatibility\n"; - } - else if (GLEW_VERSION_3_1) { - version = - "#version 140\n" - "#extension GL_ARB_compatibility: enable\n"; - } - else { - version = "#version 130\n"; - // Minimum supported for OpenSubdiv. - } - g_flat_fill_solid_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define USE_LIGHTING\n" - "#define FLAT_SHADING\n"); - g_flat_fill_texture2d_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define USE_LIGHTING\n" - "#define USE_TEXTURE_2D\n" - "#define FLAT_SHADING\n"); - g_smooth_fill_solid_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define USE_LIGHTING\n" - "#define SMOOTH_SHADING\n"); - g_smooth_fill_texture2d_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define USE_LIGHTING\n" - "#define USE_TEXTURE_2D\n" - "#define SMOOTH_SHADING\n"); - - g_flat_fill_solid_shadeless_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define FLAT_SHADING\n"); - g_flat_fill_texture2d_shadeless_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define USE_TEXTURE_2D\n" - "#define FLAT_SHADING\n"); - g_smooth_fill_solid_shadeless_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define SMOOTH_SHADING\n"); - g_smooth_fill_texture2d_shadeless_program = linkProgram(version, - "#define USE_COLOR_MATERIAL\n" - "#define USE_TEXTURE_2D\n" - "#define SMOOTH_SHADING\n"); - g_wireframe_program = linkProgram(version, "#define WIREFRAME\n"); - - glGenBuffers(1, &g_lighting_ub); - glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); - glBufferData(GL_UNIFORM_BUFFER, sizeof(g_lighting_data), NULL, GL_STATIC_DRAW); - need_init = false; - init_success = g_flat_fill_solid_program != 0 && g_flat_fill_texture2d_program != 0 && - g_smooth_fill_solid_program != 0 && g_smooth_fill_texture2d_program != 0 && - g_wireframe_program; - return init_success; -} - -void openSubdiv_deinitGLMeshDrawingResources(void) -{ - if (g_lighting_ub != 0) { - glDeleteBuffers(1, &g_lighting_ub); - } -#define SAFE_DELETE_PROGRAM(program) \ - do { \ - if (program) { \ - glDeleteProgram(program); \ - } \ - } while (false) - - SAFE_DELETE_PROGRAM(g_flat_fill_solid_program); - SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program); - SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program); - SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program); - SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program); - SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program); - SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program); - SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program); - SAFE_DELETE_PROGRAM(g_wireframe_program); - -#undef SAFE_DELETE_PROGRAM -} - -namespace opensubdiv_capi { - -namespace { - -GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, bool fill_quads) -{ - GLint program = 0; - if (!g_use_osd_glsl) { - glGetIntegerv(GL_CURRENT_PROGRAM, &program); - if (program) { - GLint model; - glGetIntegerv(GL_SHADE_MODEL, &model); - GLint location = glGetUniformLocation(program, "osd_flat_shading"); - if (location != -1) { - glUniform1i(location, model == GL_FLAT); - } - // Face-vertex data. - opensubdiv_capi::GLMeshFVarData *fvar_data = gl_mesh->internal->fvar_data; - if (fvar_data != NULL) { - if (fvar_data->texture_buffer) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer); - glActiveTexture(GL_TEXTURE0); - } - if (fvar_data->offset_buffer) { - glActiveTexture(GL_TEXTURE30); - glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer); - glActiveTexture(GL_TEXTURE0); - } - GLint location = glGetUniformLocation(program, "osd_fvar_count"); - if (location != -1) { - glUniform1i(location, fvar_data->fvar_width); - } - location = glGetUniformLocation(program, "osd_active_uv_offset"); - if (location != -1) { - if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) { - glUniform1i(location, fvar_data->channel_offsets[g_active_uv_index]); - } - else { - glUniform1i(location, 0); - } - } - } - else { - glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); - } - } - return program; - } - if (fill_quads) { - int model; - GLboolean use_texture_2d; - glGetIntegerv(GL_SHADE_MODEL, &model); - glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d); - if (model == GL_FLAT) { - if (use_texture_2d) { - program = g_flat_fill_texture2d_program; - } - else { - program = g_flat_fill_solid_program; - } - } - else { - if (use_texture_2d) { - program = g_smooth_fill_texture2d_program; - } - else { - program = g_smooth_fill_solid_program; - } - } - } - else { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - program = g_wireframe_program; - } - bindProgram(gl_mesh, program); - return program; -} - -void perform_drawElements(GLuint program, int patch_index, int num_elements, int start_element) -{ - if (program) { - glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"), patch_index); - } - glDrawElements(GL_LINES_ADJACENCY, - num_elements, - GL_UNSIGNED_INT, - reinterpret_cast<void *>(start_element * sizeof(unsigned int))); -} - -void finishPatchDraw(bool fill_quads) -{ - // TODO(sergey): Some of the stuff could be done once after the whole - // mesh is displayed. - /// Restore state. - if (!fill_quads) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - glBindVertexArray(0); - if (g_use_osd_glsl) { - // TODO(sergey): Store previously used program and roll back to it? - glUseProgram(0); - } -} - -void drawPartitionPatchesRange(GLMeshInterface *mesh, - GLuint program, - int start_patch, - int num_patches) -{ - int traversed_patches = 0, num_remained_patches = num_patches; - const OpenSubdiv::Osd::PatchArrayVector &patches = mesh->GetPatchTable()->GetPatchArrays(); - for (int i = 0; i < patches.size(); ++i) { - const OpenSubdiv::Osd::PatchArray &patch = patches[i]; - OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); - OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType(); - if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) { - const int num_block_patches = patch.GetNumPatches(); - if (start_patch >= traversed_patches && - start_patch < traversed_patches + num_block_patches) { - const int num_control_verts = desc.GetNumControlVertices(); - const int start_draw_patch = start_patch - traversed_patches; - const int num_draw_patches = min(num_remained_patches, - num_block_patches - start_draw_patch); - perform_drawElements(program, - i + start_draw_patch, - num_draw_patches * num_control_verts, - patch.GetIndexBase() + start_draw_patch * num_control_verts); - num_remained_patches -= num_draw_patches; - } - if (num_remained_patches == 0) { - break; - } - traversed_patches += num_block_patches; - } - } -} - -static void drawAllPatches(GLMeshInterface *mesh, GLuint program) -{ - const OpenSubdiv::Osd::PatchArrayVector &patches = mesh->GetPatchTable()->GetPatchArrays(); - for (int i = 0; i < patches.size(); ++i) { - const OpenSubdiv::Osd::PatchArray &patch = patches[i]; - OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); - OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType(); - - if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) { - perform_drawElements( - program, i, patch.GetNumPatches() * desc.GetNumControlVertices(), patch.GetIndexBase()); - } - } -} - -} // namespace - -void GLMeshDisplayPrepare(struct OpenSubdiv_GLMesh * /*gl_mesh*/, - const bool use_osd_glsl, - const int active_uv_index) -{ - g_active_uv_index = active_uv_index; - g_use_osd_glsl = (use_osd_glsl != 0); - // Update transformation matrices. - glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix); - glGetFloatv(GL_MODELVIEW_MATRIX, g_transform.model_view_matrix); - copy_m3_m4((float(*)[3])g_transform.normal_matrix, (float(*)[4])g_transform.model_view_matrix); - invert_m3((float(*)[3])g_transform.normal_matrix); - transpose_m3((float(*)[3])g_transform.normal_matrix); - // Update OpenGL lights positions, colors etc. - g_lighting_data.num_enabled = 0; - for (int i = 0; i < MAX_LIGHTS; ++i) { - GLboolean enabled; - glGetBooleanv(GL_LIGHT0 + i, &enabled); - if (enabled) { - g_lighting_data.num_enabled++; - } - // TODO(sergey): Stop using glGetLight. - glGetLightfv(GL_LIGHT0 + i, GL_POSITION, g_lighting_data.lights[i].position); - glGetLightfv(GL_LIGHT0 + i, GL_AMBIENT, g_lighting_data.lights[i].ambient); - glGetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, g_lighting_data.lights[i].diffuse); - glGetLightfv(GL_LIGHT0 + i, GL_SPECULAR, g_lighting_data.lights[i].specular); - glGetLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, g_lighting_data.lights[i].spot_direction); -#ifdef SUPPORT_COLOR_MATERIAL - glGetLightfv( - GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &g_lighting_data.lights[i].constant_attenuation); - glGetLightfv( - GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &g_lighting_data.lights[i].linear_attenuation); - glGetLightfv( - GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &g_lighting_data.lights[i].quadratic_attenuation); - glGetLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &g_lighting_data.lights[i].spot_cutoff); - glGetLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &g_lighting_data.lights[i].spot_exponent); - g_lighting_data.lights[i].spot_cos_cutoff = cos(g_lighting_data.lights[i].spot_cutoff); -#endif - } -} - -void GLMeshDisplayDrawPatches(OpenSubdiv_GLMesh *gl_mesh, - const bool fill_quads, - const int start_patch, - const int num_patches) -{ - GLMeshInterface *mesh = gl_mesh->internal->mesh_interface; - // Make sure all global invariants are initialized. - if (!openSubdiv_initGLMeshDrawingResources()) { - return; - } - /// Setup GLSL/OpenGL to draw patches in current context. - GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0); - if (start_patch != -1) { - drawPartitionPatchesRange(mesh, program, start_patch, num_patches); - } - else { - drawAllPatches(mesh, program); - } - // Finish patch drawing by restoring all changes to the OpenGL context. - finishPatchDraw(fill_quads != 0); -} - -} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h deleted file mode 100644 index 599ab9550e7..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_gl_mesh_draw.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2013 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_GL_MESH_DRAW_H_ -#define OPENSUBDIV_GL_MESH_DRAW_H_ - -#include <stdint.h> // for bool - -struct OpenSubdiv_GLMesh; - -namespace opensubdiv_capi { - -void GLMeshDisplayPrepare(struct OpenSubdiv_GLMesh *gl_mesh, - const bool use_osd_glsl, - const int active_uv_index); - -void GLMeshDisplayDrawPatches(OpenSubdiv_GLMesh *gl_mesh, - const bool fill_quads, - const int start_patch, - const int num_patches); - -} // namespace opensubdiv_capi - -#endif // OPENSUBDIV_GL_MESH_DRAW_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc deleted file mode 100644 index 6efbe93d2d8..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.cc +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2013 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#include "internal/opensubdiv_gl_mesh_fvar.h" - -#include <GL/glew.h> -#include <opensubdiv/far/primvarRefiner.h> - -#include "internal/opensubdiv_util.h" - -namespace opensubdiv_capi { - -//////////////////////////////////////////////////////////////////////////////// -// GLMeshFVarData - -GLMeshFVarData::GLMeshFVarData() : texture_buffer(0), offset_buffer(0) -{ -} - -GLMeshFVarData::~GLMeshFVarData() -{ - release(); -} - -void GLMeshFVarData::release() -{ - if (texture_buffer) { - glDeleteTextures(1, &texture_buffer); - } - if (offset_buffer) { - glDeleteTextures(1, &offset_buffer); - } - texture_buffer = 0; - offset_buffer = 0; - fvar_width = 0; - channel_offsets.clear(); -} - -void GLMeshFVarData::create(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv::Far::PatchTable *patch_table, - int fvar_width, - const float *fvar_src_data) -{ - release(); - this->fvar_width = fvar_width; - /// Expand fvar data to per-patch array. - const int max_level = topology_refiner->GetMaxLevel(); - const int num_channels = patch_table->GetNumFVarChannels(); - vector<float> data; - int fvar_data_offset = 0; - channel_offsets.resize(num_channels); - for (int channel = 0; channel < num_channels; ++channel) { - OpenSubdiv::Far::ConstIndexArray indices = patch_table->GetFVarValues(channel); - channel_offsets[channel] = data.size(); - data.reserve(data.size() + indices.size() * fvar_width); - for (int fvert = 0; fvert < indices.size(); ++fvert) { - int index = indices[fvert] * fvar_width; - for (int i = 0; i < fvar_width; ++i) { - data.push_back(fvar_src_data[fvar_data_offset + index++]); - } - } - if (topology_refiner->IsUniform()) { - const int num_values_max = topology_refiner->GetLevel(max_level).GetNumFVarValues(channel); - fvar_data_offset += num_values_max * fvar_width; - } - else { - const int num_values_total = topology_refiner->GetNumFVarValuesTotal(channel); - fvar_data_offset += num_values_total * fvar_width; - } - } - GLuint buffer; - glGenBuffers(1, &buffer); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW); - glGenTextures(1, &texture_buffer); - glBindTexture(GL_TEXTURE_BUFFER, texture_buffer); - glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer); - glDeleteBuffers(1, &buffer); - glGenBuffers(1, &buffer); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData( - GL_ARRAY_BUFFER, channel_offsets.size() * sizeof(int), &channel_offsets[0], GL_STATIC_DRAW); - glGenTextures(1, &offset_buffer); - glBindTexture(GL_TEXTURE_BUFFER, offset_buffer); - glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer); - glBindTexture(GL_TEXTURE_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -//////////////////////////////////////////////////////////////////////////////// -// Helper functions. - -struct FVarVertex { - float u, v; - - void Clear() - { - u = v = 0.0f; - } - - void AddWithWeight(FVarVertex const &src, float weight) - { - u += weight * src.u; - v += weight * src.v; - } -}; - -void interpolateFVarData(const OpenSubdiv::Far::TopologyRefiner &refiner, - const vector<float> &uvs, - vector<float> *fvar_data) -{ - const int fvar_width = 2; - const int max_level = refiner.GetMaxLevel(); - size_t fvar_data_offset = 0, values_offset = 0; - for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) { - const int num_values = refiner.GetLevel(0).GetNumFVarValues(channel) * 2; - const int num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel); - const int num_values_total = refiner.GetNumFVarValuesTotal(channel); - if (num_values_total <= 0) { - continue; - } - OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner); - if (refiner.IsUniform()) { - // For uniform we only keep the highest level of refinement. - fvar_data->resize(fvar_data->size() + num_values_max * fvar_width); - vector<FVarVertex> buffer(num_values_total - num_values_max); - FVarVertex *src = &buffer[0]; - memcpy(src, &uvs[values_offset], num_values * sizeof(float)); - // Defer the last level to treat separately with its alternate - // destination. - for (int level = 1; level < max_level; ++level) { - FVarVertex *dst = src + refiner.GetLevel(level - 1).GetNumFVarValues(channel); - primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); - src = dst; - } - FVarVertex *dst = reinterpret_cast<FVarVertex *>(&(*fvar_data)[fvar_data_offset]); - primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel); - fvar_data_offset += num_values_max * fvar_width; - } - else { - // For adaptive we keep all levels. - fvar_data->resize(fvar_data->size() + num_values_total * fvar_width); - FVarVertex *src = reinterpret_cast<FVarVertex *>(&(*fvar_data)[fvar_data_offset]); - memcpy(src, &uvs[values_offset], num_values * sizeof(float)); - for (int level = 1; level <= max_level; ++level) { - FVarVertex *dst = src + refiner.GetLevel(level - 1).GetNumFVarValues(channel); - primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); - src = dst; - } - fvar_data_offset += num_values_total * fvar_width; - } - values_offset += num_values; - } -} - -} // namespace opensubdiv_capi diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h deleted file mode 100644 index 73a1af05605..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_gl_mesh_fvar.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2013 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_GL_MESH_FVAR_H_ -#define OPENSUBDIV_GL_MESH_FVAR_H_ - -// NOTE: This is a [sane(er)] port of previous ground work for getting UVs to -// work. Still needs a lot of work to make it easy, correct and have proper -// data ownership. - -#include <opensubdiv/far/patchTable.h> -#include <opensubdiv/far/topologyRefiner.h> - -#include "internal/opensubdiv_util.h" - -namespace opensubdiv_capi { - -// The buffer which holds GPU resources for face-varying elements. -class GLMeshFVarData { - public: - GLMeshFVarData(); - ~GLMeshFVarData(); - - void release(); - void create(const OpenSubdiv::Far::TopologyRefiner *refiner, - const OpenSubdiv::Far::PatchTable *patch_table, - int fvar_width, - const float *fvar_src_data); - - unsigned int texture_buffer; - unsigned int offset_buffer; - vector<int> channel_offsets; - int fvar_width; -}; - -void interpolateFVarData(const OpenSubdiv::Far::TopologyRefiner &refiner, - const vector<float> &uvs, - vector<float> *fvar_data); - -} // namespace opensubdiv_capi - -#endif // OPENSUBDIV_GL_MESH_FVAR_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h b/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h deleted file mode 100644 index cb92fb18362..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_gl_mesh_internal.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_GL_MESH_INTERNAL_H_ -#define OPENSUBDIV_GL_MESH_INTERNAL_H_ - -#ifdef _MSC_VER -# include <iso646.h> -#endif - -#include <opensubdiv/osd/glMesh.h> - -#include "opensubdiv_capi_type.h" - -namespace opensubdiv_capi { -class GLMeshFVarData; -} // namespace opensubdiv_capi - -typedef struct OpenSubdiv_GLMeshInternal { - OpenSubdiv_GLMeshInternal(); - ~OpenSubdiv_GLMeshInternal(); - - eOpenSubdivEvaluator evaluator_type; - OpenSubdiv::Osd::GLMeshInterface *mesh_interface; - opensubdiv_capi::GLMeshFVarData *fvar_data; -} OpenSubdiv_GLMeshInternal; - -#endif // OPENSUBDIV_GL_MESH_INTERNAL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc deleted file mode 100644 index ac27cbdefdc..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc +++ /dev/null @@ -1,672 +0,0 @@ -// Copyright 2018 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#include "opensubdiv_topology_refiner_capi.h" - -#include <vector> - -#include "MEM_guardedalloc.h" -#include "internal/opensubdiv_converter_factory.h" -#include "internal/opensubdiv_converter_internal.h" -#include "internal/opensubdiv_edge_map.h" -#include "internal/opensubdiv_internal.h" -#include "internal/opensubdiv_topology_refiner_internal.h" -#include "internal/opensubdiv_util.h" - -using opensubdiv_capi::vector; - -namespace { - -const OpenSubdiv::Far::TopologyRefiner *getOSDTopologyRefiner( - const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return topology_refiner->internal->osd_topology_refiner; -} - -const OpenSubdiv::Far::TopologyLevel *getOSDTopologyBaseLevel( - const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return &getOSDTopologyRefiner(topology_refiner)->GetLevel(0); -} - -int getSubdivisionLevel(const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return topology_refiner->internal->settings.level; -} - -bool getIsAdaptive(const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return topology_refiner->internal->settings.is_adaptive; -} - -//////////////////////////////////////////////////////////////////////////////// -// Query basic topology information from base level. - -int getNumVertices(const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return getOSDTopologyBaseLevel(topology_refiner)->GetNumVertices(); -} - -int getNumEdges(const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return getOSDTopologyBaseLevel(topology_refiner)->GetNumEdges(); -} - -int getNumFaces(const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return getOSDTopologyBaseLevel(topology_refiner)->GetNumFaces(); -} - -//////////////////////////////////////////////////////////////////////////////// -// PTex face geometry queries. - -static void convertArrayToRaw(const OpenSubdiv::Far::ConstIndexArray &array, int *raw_array) -{ - for (int i = 0; i < array.size(); ++i) { - raw_array[i] = array[i]; - } -} - -int getNumFaceVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - return base_level->GetFaceVertices(face_index).size(); -} - -void getFaceVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, - const int face_index, - int *face_vertices_indices) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - OpenSubdiv::Far::ConstIndexArray array = base_level->GetFaceVertices(face_index); - convertArrayToRaw(array, face_vertices_indices); -} - -int getNumFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - return base_level->GetFaceEdges(face_index).size(); -} - -void getFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, - const int face_index, - int *face_edges_indices) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - OpenSubdiv::Far::ConstIndexArray array = base_level->GetFaceEdges(face_index); - convertArrayToRaw(array, face_edges_indices); -} - -void getEdgeVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, - const int edge_index, - int edge_vertices_indices[2]) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - OpenSubdiv::Far::ConstIndexArray array = base_level->GetEdgeVertices(edge_index); - assert(array.size() == 2); - edge_vertices_indices[0] = array[0]; - edge_vertices_indices[1] = array[1]; -} - -int getNumVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, const int vertex_index) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - return base_level->GetVertexEdges(vertex_index).size(); -} - -void getVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, - const int vertex_index, - int *vertex_edges_indices) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - OpenSubdiv::Far::ConstIndexArray array = base_level->GetVertexEdges(vertex_index); - convertArrayToRaw(array, vertex_edges_indices); -} - -int getNumFacePtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index) -{ - const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index); - if (num_face_vertices == 4) { - return 1; - } - else { - return num_face_vertices; - } -} - -int getNumPtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner) -{ - const int num_faces = topology_refiner->getNumFaces(topology_refiner); - int num_ptex_faces = 0; - for (int face_index = 0; face_index < num_faces; ++face_index) { - num_ptex_faces += topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); - } - return num_ptex_faces; -} - -void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner *topology_refiner, - int *face_ptex_index_offset) -{ - const int num_faces = topology_refiner->getNumFaces(topology_refiner); - int num_ptex_faces = 0; - for (int face_index = 0; face_index < num_faces; ++face_index) { - face_ptex_index_offset[face_index] = num_ptex_faces; - num_ptex_faces += topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Face-varying data. - -int getNumFVarChannels(const struct OpenSubdiv_TopologyRefiner *topology_refiner) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - return base_level->GetNumFVarChannels(); -} - -OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation( - const struct OpenSubdiv_TopologyRefiner *topology_refiner) -{ - return opensubdiv_capi::getCAPIFVarLinearInterpolationFromOSD( - getOSDTopologyRefiner(topology_refiner)->GetFVarLinearInterpolation()); -} - -int getNumFVarValues(const struct OpenSubdiv_TopologyRefiner *topology_refiner, const int channel) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - return base_level->GetNumFVarValues(channel); -} - -const int *getFaceFVarValueIndices(const struct OpenSubdiv_TopologyRefiner *topology_refiner, - const int face_index, - const int channel) -{ - const OpenSubdiv::Far::TopologyLevel *base_level = getOSDTopologyBaseLevel(topology_refiner); - return &base_level->GetFaceFVarValues(face_index, channel)[0]; -} - -//////////////////////////////////////////////////////////////////////////////// -// Internal helpers. - -void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner) -{ - topology_refiner->getSubdivisionLevel = getSubdivisionLevel; - topology_refiner->getIsAdaptive = getIsAdaptive; - // Basic topology information. - topology_refiner->getNumVertices = getNumVertices; - topology_refiner->getNumEdges = getNumEdges; - topology_refiner->getNumFaces = getNumFaces; - topology_refiner->getNumFaceVertices = getNumFaceVertices; - topology_refiner->getFaceVertices = getFaceVertices; - topology_refiner->getNumFaceEdges = getNumFaceEdges; - topology_refiner->getFaceEdges = getFaceEdges; - topology_refiner->getEdgeVertices = getEdgeVertices; - topology_refiner->getNumVertexEdges = getNumVertexEdges; - topology_refiner->getVertexEdges = getVertexEdges; - // PTex face geometry. - topology_refiner->getNumFacePtexFaces = getNumFacePtexFaces; - topology_refiner->getNumPtexFaces = getNumPtexFaces; - topology_refiner->fillFacePtexIndexOffset = fillFacePtexIndexOffset; - // Face-varying data. - topology_refiner->getNumFVarChannels = getNumFVarChannels; - topology_refiner->getFVarLinearInterpolation = getFVarLinearInterpolation; - topology_refiner->getNumFVarValues = getNumFVarValues; - topology_refiner->getFaceFVarValueIndices = getFaceFVarValueIndices; -} - -OpenSubdiv_TopologyRefiner *allocateTopologyRefiner() -{ - OpenSubdiv_TopologyRefiner *topology_refiner = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefiner); - topology_refiner->internal = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerInternal); - assignFunctionPointers(topology_refiner); - return topology_refiner; -} - -} // namespace - -OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter( - OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings) -{ - OpenSubdiv::Far::TopologyRefiner *osd_topology_refiner = - opensubdiv_capi::createOSDTopologyRefinerFromConverter(converter); - if (osd_topology_refiner == NULL) { - // Happens on empty or bad topology. - return NULL; - } - OpenSubdiv_TopologyRefiner *topology_refiner = allocateTopologyRefiner(); - topology_refiner->internal->osd_topology_refiner = osd_topology_refiner; - // Store setting which we want to keep track of and which can not be stored - // in OpenSubdiv's descriptor yet. - topology_refiner->internal->settings = *settings; - return topology_refiner; -} - -void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner) -{ - OBJECT_GUARDED_DELETE(topology_refiner->internal, OpenSubdiv_TopologyRefinerInternal); - OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefiner); -} - -//////////////////////////////////////////////////////////////////////////////// -// Comparison with converter. - -namespace opensubdiv_capi { -namespace { - -/////////////////////////////////////////////////////////// -// Quick preliminary checks. - -bool checkSchemeTypeMatches(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - const OpenSubdiv::Sdc::SchemeType converter_scheme_type = opensubdiv_capi::getSchemeTypeFromCAPI( - converter->getSchemeType(converter)); - return (converter_scheme_type == topology_refiner->GetSchemeType()); -} - -bool checkOptionsMatches(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - typedef OpenSubdiv::Sdc::Options Options; - const Options options = topology_refiner->GetSchemeOptions(); - const Options::FVarLinearInterpolation fvar_interpolation = options.GetFVarLinearInterpolation(); - const Options::FVarLinearInterpolation converter_fvar_interpolation = - opensubdiv_capi::getFVarLinearInterpolationFromCAPI( - converter->getFVarLinearInterpolation(converter)); - if (fvar_interpolation != converter_fvar_interpolation) { - return false; - } - return true; -} - -bool checkGeometryCountersMatches(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::TopologyLevel; - const TopologyLevel &base_level = topology_refiner->GetLevel(0); - return ((converter->getNumVertices(converter) == base_level.GetNumVertices()) && - (converter->getNumEdges(converter) == base_level.GetNumEdges()) && - (converter->getNumFaces(converter) == base_level.GetNumFaces())); -} - -bool checkPreliminaryMatches(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - return checkSchemeTypeMatches(topology_refiner, converter) && - checkOptionsMatches(topology_refiner, converter) && - checkGeometryCountersMatches(topology_refiner, converter); -} - -/////////////////////////////////////////////////////////// -// Geometry comparison. - -// A thin wrapper around index like array which does cyclic access. This means, -// it basically does indices[requested_index % num_indices]. -// -// NOTE: This array does not own the memory. -// -// TODO(sergey): Consider moving this to a more reusable place. -class CyclicArray { - public: - typedef int value_type; - typedef int size_type; - static constexpr size_type npos = -1; - - explicit CyclicArray(const std::vector<int> &data) : data_(data.data()), size_(data.size()) - { - } - - explicit CyclicArray(const OpenSubdiv::Far::ConstIndexArray &data) - : data_(&data[0]), size_(data.size()) - { - } - - inline value_type operator[](int index) const - { - assert(index >= 0); - // TODO(sergey): Check whether doing check for element index exceeding total - // number of indices prior to modulo helps performance. - return data_[index % size()]; - } - - inline size_type size() const - { - return size_; - } - - // Find index of first occurrence of a given value. - inline size_type find(const value_type value) const - { - const int num_indices = size(); - for (size_type i = 0; i < num_indices; ++i) { - if (value == (*this)[i]) { - return i; - } - } - return npos; - } - - protected: - const value_type *data_; - const size_type size_; -}; - -bool compareCyclicForward(const CyclicArray &array_a, - const int start_a, - const CyclicArray &array_b, - const int start_b) -{ - const int num_elements = array_a.size(); - for (int i = 0; i < num_elements; ++i) { - if (array_a[start_a + i] != array_b[start_b + i]) { - return false; - } - } - return true; -} - -bool compareCyclicBackward(const CyclicArray &array_a, - const int start_a, - const CyclicArray &array_b, - const int start_b) -{ - const int num_elements = array_a.size(); - // TODO(sergey): Some optimization might be possible with memcmp trickery. - for (int i = 0; i < num_elements; ++i) { - if (array_a[start_a + (num_elements - i - 1)] != array_b[start_b + (num_elements - i - 1)]) { - return false; - } - } - return true; -} - -// Utility function dedicated for checking whether whether vertices indices -// used by two faces match. -// The tricky part here is that we can't trust 1:1 array match here, since it's -// possible that OpenSubdiv oriented edges of a face to make it compatible with -// an internal representation of non-manifold meshes. -// -// TODO(sergey): Check whether this is needed, ot whether OpenSubdiv is only -// creating edges in a proper orientation without modifying indices of face -// vertices. -bool checkVerticesOfFacesMatch(const CyclicArray &indices_a, const CyclicArray &indices_b) -{ - if (indices_a.size() != indices_b.size()) { - return false; - } - // "Align" the arrays so we know first matched element. - const int start_b = indices_b.find(indices_a[0]); - if (start_b == indices_b.npos) { - return false; - } - // Check match in both directions, for the case OpenSubdiv did orient face in - // a way which made normals more consistent internally. - if (compareCyclicForward(indices_a, 0, indices_b, start_b)) { - return true; - } - if (compareCyclicBackward(indices_a, 0, indices_b, start_b)) { - return true; - } - return false; -} - -bool checkGeometryFacesMatch(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::ConstIndexArray; - using OpenSubdiv::Far::TopologyLevel; - const TopologyLevel &base_level = topology_refiner->GetLevel(0); - const int num_faces = base_level.GetNumFaces(); - // TODO(sergey): Consider using data structure which keeps handful of - // elements on stack before doing heep allocation. - vector<int> conv_face_vertices; - for (int face_index = 0; face_index < num_faces; ++face_index) { - const ConstIndexArray &face_vertices = base_level.GetFaceVertices(face_index); - const int num_face_vertices = face_vertices.size(); - if (num_face_vertices != converter->getNumFaceVertices(converter, face_index)) { - return false; - } - conv_face_vertices.resize(num_face_vertices); - converter->getFaceVertices(converter, face_index, &conv_face_vertices[0]); - if (!checkVerticesOfFacesMatch(CyclicArray(conv_face_vertices), CyclicArray(face_vertices))) { - return false; - } - } - return true; -} - -bool checkGeometryMatches(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - // NOTE: Since OpenSubdiv's topology refiner doesn't contain loose edges, we - // are only checking for faces to be matched. Changes in edges we don't care - // here too much (they'll be checked for creases changes later). - return checkGeometryFacesMatch(topology_refiner, converter); -} - -/////////////////////////////////////////////////////////// -// Compare attributes which affects on topology - -inline bool checkSingleEdgeSharpnessMatch(const OpenSubdiv::Far::TopologyLevel &base_level, - int base_level_edge_index, - const OpenSubdiv_Converter *converter, - int converter_edge_index) -{ - // NOTE: Boundary and non-manifold edges are internally forced to an infinite - // sharpness. So we can not reliably compare those. - // - // TODO(sergey): Watch for NON_MANIFOLD_SHARP option. - if (base_level.IsEdgeBoundary(base_level_edge_index) || - base_level.IsEdgeNonManifold(base_level_edge_index)) { - return true; - } - const float sharpness = base_level.GetEdgeSharpness(base_level_edge_index); - const float converter_sharpness = converter->getEdgeSharpness(converter, converter_edge_index); - if (sharpness != converter_sharpness) { - return false; - } - return true; -} - -inline bool checkSingleEdgeTagMatch(const OpenSubdiv::Far::TopologyLevel &base_level, - int base_level_edge_index, - const OpenSubdiv_Converter *converter, - int converter_edge_index) -{ - return checkSingleEdgeSharpnessMatch( - base_level, base_level_edge_index, converter, converter_edge_index); -} - -// Compares edge tags between topology refiner and converter in a case when -// converter specifies a full topology. -// This is simplest loop, since we know that order of edges matches. -bool checkEdgeTagsMatchFullTopology(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::ConstIndexArray; - using OpenSubdiv::Far::TopologyLevel; - const TopologyLevel &base_level = topology_refiner->GetLevel(0); - const int num_edges = base_level.GetNumEdges(); - for (int edge_index = 0; edge_index < num_edges; ++edge_index) { - if (!checkSingleEdgeTagMatch(base_level, edge_index, converter, edge_index)) { - return false; - } - } - return true; -} - -// Compares tags of edges in the case when orientation of edges is left up to -// OpenSubdiv. In this case we do need to take care of mapping edges from the -// converter to current topology refiner, since the order is not guaranteed. -bool checkEdgeTagsMatchAutoOrient(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::ConstIndexArray; - using OpenSubdiv::Far::TopologyLevel; - const TopologyLevel &base_level = topology_refiner->GetLevel(0); - const int num_edges = base_level.GetNumEdges(); - // Create mapping for quick lookup of edge index from its vertices indices. - // - // TODO(sergey): Consider caching it in some sort of wrapper around topology - // refiner. - EdgeTagMap<int> edge_map; - for (int edge_index = 0; edge_index < num_edges; ++edge_index) { - ConstIndexArray edge_vertices = base_level.GetEdgeVertices(edge_index); - edge_map.insert(edge_vertices[0], edge_vertices[1], edge_index); - } - // Compare all edges. - for (int converter_edge_index = 0; converter_edge_index < num_edges; ++converter_edge_index) { - // Get edge vertices indices, and lookup corresponding edge index in the - // base topology level. - int edge_vertices[2]; - converter->getEdgeVertices(converter, converter_edge_index, edge_vertices); - const int base_level_edge_index = edge_map.at(edge_vertices[0], edge_vertices[1]); - // Perform actual test. - if (!checkSingleEdgeTagMatch( - base_level, base_level_edge_index, converter, converter_edge_index)) { - return false; - } - } - return true; -} - -bool checkEdgeTagsMatch(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - if (converter->specifiesFullTopology(converter)) { - return checkEdgeTagsMatchFullTopology(topology_refiner, converter); - } - else { - return checkEdgeTagsMatchAutoOrient(topology_refiner, converter); - } -} - -bool checkvertexSharpnessMatch(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::ConstIndexArray; - using OpenSubdiv::Far::TopologyLevel; - using OpenSubdiv::Sdc::Crease; - const TopologyLevel &base_level = topology_refiner->GetLevel(0); - // Create mapping for quick lookup of edge index from its vertices indices. - // - // TODO(sergey): Consider caching it in some sort of wrapper around topology - // refiner. - const int num_edges = base_level.GetNumEdges(); - EdgeTagMap<int> edge_map; - for (int edge_index = 0; edge_index < num_edges; ++edge_index) { - int edge_vertices[2]; - converter->getEdgeVertices(converter, edge_index, edge_vertices); - edge_map.insert(edge_vertices[0], edge_vertices[1], edge_index); - } - const int num_vertices = base_level.GetNumVertices(); - for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { - const float current_sharpness = base_level.GetVertexSharpness(vertex_index); - if (converter->isInfiniteSharpVertex(converter, vertex_index)) { - if (current_sharpness != Crease::SHARPNESS_INFINITE) { - return false; - } - } - else { - ConstIndexArray vertex_edges = base_level.GetVertexEdges(vertex_index); - float sharpness = converter->getVertexSharpness(converter, vertex_index); - if (vertex_edges.size() == 2) { - const int edge0 = vertex_edges[0], edge1 = vertex_edges[1]; - // Construct keys for lookup. - ConstIndexArray edge0_vertices = base_level.GetEdgeVertices(edge0); - ConstIndexArray edge1_vertices = base_level.GetEdgeVertices(edge1); - EdgeKey edge0_key(edge0_vertices[0], edge0_vertices[1]); - EdgeKey edge1_key(edge1_vertices[0], edge1_vertices[1]); - // Lookup edge indices in the converter. - const int edge0_converter_index = edge_map[edge0_key]; - const int edge1_converter_index = edge_map[edge1_key]; - // Lookup sharpness. - const float sharpness0 = converter->getEdgeSharpness(converter, edge0_converter_index); - const float sharpness1 = converter->getEdgeSharpness(converter, edge1_converter_index); - // TODO(sergey): Find a better mixing between edge and vertex sharpness. - sharpness += min(sharpness0, sharpness1); - sharpness = min(sharpness, 10.0f); - } - if (sharpness != current_sharpness) { - return false; - } - } - } - return true; -} - -bool checkSingleUVLayerMatch(const OpenSubdiv::Far::TopologyLevel &base_level, - const OpenSubdiv_Converter *converter, - const int layer_index) -{ - converter->precalcUVLayer(converter, layer_index); - const int num_faces = base_level.GetNumFaces(); - // TODO(sergey): Need to check whether converter changed the winding of - // face to match OpenSubdiv's expectations. - for (int face_index = 0; face_index < num_faces; ++face_index) { - OpenSubdiv::Far::ConstIndexArray base_level_face_uvs = base_level.GetFaceFVarValues( - face_index, layer_index); - for (int corner = 0; corner < base_level_face_uvs.size(); ++corner) { - const int uv_index = converter->getFaceCornerUVIndex(converter, face_index, corner); - if (base_level_face_uvs[corner] != uv_index) { - converter->finishUVLayer(converter); - return false; - } - } - } - converter->finishUVLayer(converter); - return true; -} - -bool checkUVLayersMatch(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::TopologyLevel; - const int num_layers = converter->getNumUVLayers(converter); - const TopologyLevel &base_level = topology_refiner->GetLevel(0); - // Number of UV layers should match. - if (base_level.GetNumFVarChannels() != num_layers) { - return false; - } - for (int layer_index = 0; layer_index < num_layers; ++layer_index) { - if (!checkSingleUVLayerMatch(base_level, converter, layer_index)) { - return false; - } - } - return true; -} - -bool checkTopologyAttributesMatch(const OpenSubdiv::Far::TopologyRefiner *topology_refiner, - const OpenSubdiv_Converter *converter) -{ - return checkEdgeTagsMatch(topology_refiner, converter) && - checkvertexSharpnessMatch(topology_refiner, converter) && - checkUVLayersMatch(topology_refiner, converter); -} - -} // namespace -} // namespace opensubdiv_capi - -bool openSubdiv_topologyRefinerCompareWithConverter( - const OpenSubdiv_TopologyRefiner *topology_refiner, const OpenSubdiv_Converter *converter) -{ - const OpenSubdiv::Far::TopologyRefiner *refiner = getOSDTopologyRefiner(topology_refiner); - return (opensubdiv_capi::checkPreliminaryMatches(refiner, converter) && - opensubdiv_capi::checkGeometryMatches(refiner, converter) && - opensubdiv_capi::checkTopologyAttributesMatch(refiner, converter)); -} diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h b/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h deleted file mode 100644 index b0f5d4079ef..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_TOPOLOGY_REFINER_INTERNAL_H_ -#define OPENSUBDIV_TOPOLOGY_REFINER_INTERNAL_H_ - -#ifdef _MSC_VER -# include <iso646.h> -#endif - -#include <opensubdiv/far/topologyRefiner.h> - -#include "opensubdiv_topology_refiner_capi.h" - -struct OpenSubdiv_TopologyRefinerInternal { - public: - OpenSubdiv_TopologyRefinerInternal(); - ~OpenSubdiv_TopologyRefinerInternal(); - - OpenSubdiv::Far::TopologyRefiner *osd_topology_refiner; - - // Subdivision settingsa this refiner is created for. - // - // We store it here since OpenSubdiv's refiner will only know about level and - // "adaptivity" after performing actual "refine" step. - // - // Ideally, we would also support refining topology without re-importing it - // from external world, but that is for later. - OpenSubdiv_TopologyRefinerSettings settings; -}; - -#endif // OPENSUBDIV_TOPOLOGY_REFINER_H_ diff --git a/intern/opensubdiv/internal/topology/mesh_topology.cc b/intern/opensubdiv/internal/topology/mesh_topology.cc new file mode 100644 index 00000000000..9197a5c1b54 --- /dev/null +++ b/intern/opensubdiv/internal/topology/mesh_topology.cc @@ -0,0 +1,273 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/topology/mesh_topology.h" + +#include <cassert> + +namespace blender { +namespace opensubdiv { + +MeshTopology::MeshTopology() : num_vertices_(0), num_edges_(0), num_faces_(0) +{ +} + +MeshTopology::~MeshTopology() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// Vertices. + +void MeshTopology::setNumVertices(int num_vertices) +{ + num_vertices_ = num_vertices; +} + +int MeshTopology::getNumVertices() const +{ + return num_vertices_; +} + +void MeshTopology::setVertexSharpness(int vertex_index, float sharpness) +{ + assert(vertex_index >= 0); + assert(vertex_index < getNumVertices()); + + ensureVertexTagsSize(vertex_index + 1); + + vertex_tags_[vertex_index].sharpness = sharpness; +} + +float MeshTopology::getVertexSharpness(int vertex_index) const +{ + assert(vertex_index >= 0); + assert(vertex_index < getNumVertices()); + + if (vertex_index >= vertex_tags_.size()) { + // Sharpness for the vertex was never provided. + return 0.0f; + } + + return vertex_tags_[vertex_index].sharpness; +} + +void MeshTopology::ensureVertexTagsSize(int num_vertices) +{ + if (vertex_tags_.size() < num_vertices) { + vertex_tags_.resize(num_vertices); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Edges. + +void MeshTopology::setNumEdges(int num_edges) +{ + num_edges_ = num_edges; +} + +int MeshTopology::getNumEdges() const +{ + return num_edges_; +} + +void MeshTopology::setEdgeVertexIndices(int edge_index, int v1, int v2) +{ + assert(edge_index >= 0); + assert(edge_index < getNumEdges()); + + assert(v1 >= 0); + assert(v1 < getNumVertices()); + + assert(v2 >= 0); + assert(v2 < getNumVertices()); + + ensureNumEdgesAtLeast(edge_index + 1); + + Edge &edge = edges_[edge_index]; + edge.v1 = v1; + edge.v2 = v2; +} + +void MeshTopology::getEdgeVertexIndices(int edge_index, int *v1, int *v2) const +{ + assert(edge_index >= 0); + assert(edge_index < getNumEdges()); + + if (edge_index >= edges_.size()) { + *v1 = -1; + *v1 = -1; + return; + } + + const Edge &edge = edges_[edge_index]; + *v1 = edge.v1; + *v2 = edge.v2; +} + +bool MeshTopology::isEdgeEqual(int edge_index, int expected_v1, int expected_v2) const +{ + assert(edge_index >= 0); + assert(edge_index < getNumEdges()); + + if (edge_index >= edges_.size()) { + return false; + } + + const Edge &edge = edges_[edge_index]; + return edge.v1 == expected_v1 && edge.v2 == expected_v2; +} + +void MeshTopology::setEdgeSharpness(int edge_index, float sharpness) +{ + assert(edge_index >= 0); + assert(edge_index < getNumEdges()); + + if (sharpness < 1e-6f) { + return; + } + + ensureEdgeTagsSize(edge_index + 1); + + edge_tags_[edge_index].sharpness = sharpness; +} + +float MeshTopology::getEdgeSharpness(int edge_index) const +{ + assert(edge_index >= 0); + + if (edge_index >= edge_tags_.size()) { + // NOTE: It's possible that full topology is not known and that there was + // never sharpness assigned to any of the edges. + return 0.0f; + } + + return edge_tags_[edge_index].sharpness; +} + +void MeshTopology::ensureNumEdgesAtLeast(int num_edges) +{ + if (edges_.size() < num_edges) { + edges_.resize(num_edges); + } +} + +void MeshTopology::ensureEdgeTagsSize(int num_edges) +{ + if (edge_tags_.size() < num_edges) { + edge_tags_.resize(num_edges); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Faces. + +void MeshTopology::setNumFaces(int num_faces) +{ + num_faces_ = num_faces; + + // NOTE: Extra element to store fake face past the last real one to make it + // possible to calculate number of verticies in the last face. + faces_first_vertex_index_.resize(num_faces + 1, 0); +} + +int MeshTopology::getNumFaces() const +{ + return num_faces_; +} + +void MeshTopology::setNumFaceVertices(int face_index, int num_face_vertices) +{ + assert(face_index >= 0); + assert(face_index < getNumFaces()); + + faces_first_vertex_index_[face_index + 1] = faces_first_vertex_index_[face_index] + + num_face_vertices; +} + +int MeshTopology::getNumFaceVertices(int face_index) const +{ + assert(face_index >= 0); + assert(face_index < getNumFaces()); + + return faces_first_vertex_index_[face_index + 1] - faces_first_vertex_index_[face_index]; +} + +void MeshTopology::setFaceVertexIndices(int face_index, + int num_face_vertex_indices, + const int *face_vertex_indices) +{ + assert(face_index >= 0); + assert(face_index < getNumFaces()); + assert(num_face_vertex_indices == getNumFaceVertices(face_index)); + + int *face_vertex_indices_storage = getFaceVertexIndicesStorage(face_index); + memcpy(face_vertex_indices_storage, face_vertex_indices, sizeof(int) * num_face_vertex_indices); +} + +bool MeshTopology::isFaceVertexIndicesEqual(int face_index, + int num_expected_face_vertex_indices, + const int *expected_face_vertex_indices) const +{ + assert(face_index >= 0); + assert(face_index < getNumFaces()); + + if (getNumFaceVertices(face_index) != num_expected_face_vertex_indices) { + return false; + } + + const int *face_vertex_indices_storage = getFaceVertexIndicesStorage(face_index); + return memcmp(face_vertex_indices_storage, + expected_face_vertex_indices, + sizeof(int) * num_expected_face_vertex_indices) == 0; +} + +bool MeshTopology::isFaceVertexIndicesEqual(int face_index, + const vector<int> &expected_face_vertex_indices) const +{ + return isFaceVertexIndicesEqual( + face_index, expected_face_vertex_indices.size(), expected_face_vertex_indices.data()); +} + +int *MeshTopology::getFaceVertexIndicesStorage(int face_index) +{ + const MeshTopology *const_this = this; + return const_cast<int *>(const_this->getFaceVertexIndicesStorage(face_index)); +} +const int *MeshTopology::getFaceVertexIndicesStorage(int face_index) const +{ + assert(face_index >= 0); + assert(face_index < getNumFaces()); + + const int offset = faces_first_vertex_index_[face_index]; + return face_vertex_indices_.data() + offset; +} + +//////////////////////////////////////////////////////////////////////////////// +// Pipeline related. + +void MeshTopology::finishResizeTopology() +{ + if (!faces_first_vertex_index_.empty()) { + face_vertex_indices_.resize(faces_first_vertex_index_.back()); + } +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/topology/mesh_topology.h b/intern/opensubdiv/internal/topology/mesh_topology.h new file mode 100644 index 00000000000..861614482ef --- /dev/null +++ b/intern/opensubdiv/internal/topology/mesh_topology.h @@ -0,0 +1,179 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_MESH_TOPOLOGY_H_ +#define OPENSUBDIV_MESH_TOPOLOGY_H_ + +#include <cstring> + +#include "internal/base/memory.h" +#include "internal/base/type.h" + +struct OpenSubdiv_Converter; + +namespace blender { +namespace opensubdiv { + +// Simplified representation of mesh topology. +// Only includes parts of actual mesh topology which is needed to perform +// comparison between Application side and OpenSubddiv side. +// +// NOTE: It is an optimized storage which requires special order of topology +// specification. Basically, counters is to be set prior to anything else, in +// the following manner: +// +// MeshTopology mesh_topology; +// +// mesh_topology.setNumVertices(...); +// mesh_topology.setNumEdges(...); +// mesh_topology.setNumFaces(...); +// +// for (...) { +// mesh_topology.setNumFaceVertices(...); +// } +// +// mesh_topology.finishResizeTopology(); +// +// /* it is now possible to set vertices of edge, vertices of face, and +// * sharpness. */ +class MeshTopology { + public: + MeshTopology(); + MeshTopology(const MeshTopology &other) = default; + MeshTopology(MeshTopology &&other) noexcept = default; + ~MeshTopology(); + + MeshTopology &operator=(const MeshTopology &other) = default; + MeshTopology &operator=(MeshTopology &&other) = default; + + ////////////////////////////////////////////////////////////////////////////// + // Vertices. + + void setNumVertices(int num_vertices); + int getNumVertices() const; + + void setVertexSharpness(int vertex_index, float sharpness); + float getVertexSharpness(int vertex_index) const; + + ////////////////////////////////////////////////////////////////////////////// + // Edges. + + void setNumEdges(int num_edges); + + // NOTE: Unless full topology was specified will return number of edges based + // on last edge index for which topology tag was specified. + int getNumEdges() const; + + void setEdgeVertexIndices(int edge_index, int v1, int v2); + void getEdgeVertexIndices(int edge_index, int *v1, int *v2) const; + + bool isEdgeEqual(int edge_index, int expected_v1, int expected_v2) const; + + void setEdgeSharpness(int edge_index, float sharpness); + float getEdgeSharpness(int edge_index) const; + + ////////////////////////////////////////////////////////////////////////////// + // Faces. + + void setNumFaces(int num_faces); + + int getNumFaces() const; + + void setNumFaceVertices(int face_index, int num_face_vertices); + int getNumFaceVertices(int face_index) const; + + void setFaceVertexIndices(int face_index, + int num_face_vertex_indices, + const int *face_vertex_indices); + + bool isFaceVertexIndicesEqual(int face_index, + int num_expected_face_vertex_indices, + const int *expected_face_vertex_indices) const; + bool isFaceVertexIndicesEqual(int face_index, + const vector<int> &expected_face_vertex_indices) const; + + ////////////////////////////////////////////////////////////////////////////// + // Pipeline related. + + // This function is to be called when number of vertices, edges, faces, and + // face-verticies are known. + // + // Usually is called from the end of topology refiner factory's + // resizeComponentTopology(). + void finishResizeTopology(); + + ////////////////////////////////////////////////////////////////////////////// + // Comparison. + + // Check whether this topology refiner defines same topology as the given + // converter. + bool isEqualToConverter(const OpenSubdiv_Converter *converter) const; + + protected: + // Edges are allowed to be stored sparsly, to save memory used by + // non-semi-sharp edges. + void ensureNumEdgesAtLeast(int num_edges); + + // Geometry tags are stored sparsly. + // + // These functions ensures that the storage can be addressed by an index which + // corresponds to the given size. + void ensureVertexTagsSize(int num_vertices); + void ensureEdgeTagsSize(int num_edges); + + // Get pointer to the memory where face vertex indices are stored. + int *getFaceVertexIndicesStorage(int face_index); + const int *getFaceVertexIndicesStorage(int face_index) const; + + struct VertexTag { + float sharpness = 0.0f; + }; + + struct Edge { + int v1 = -1; + int v2 = -1; + }; + + struct EdgeTag { + float sharpness = 0.0f; + }; + + int num_vertices_; + vector<VertexTag> vertex_tags_; + + int num_edges_; + vector<Edge> edges_; + vector<EdgeTag> edge_tags_; + + int num_faces_; + + // Continuous array of all verticies of all faces: + // [vertex indices of face 0][vertex indices of face 1] .. [vertex indices of face n]. + vector<int> face_vertex_indices_; + + // Indexed by face contains index within face_vertex_indices_ which corresponds + // to the element which contains first vertex of the face. + vector<int> faces_first_vertex_index_; + + MEM_CXX_CLASS_ALLOC_FUNCS("MeshTopology"); +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_MESH_TOPOLOGY_H_ diff --git a/intern/opensubdiv/internal/topology/mesh_topology_compare.cc b/intern/opensubdiv/internal/topology/mesh_topology_compare.cc new file mode 100644 index 00000000000..fd291e72cab --- /dev/null +++ b/intern/opensubdiv/internal/topology/mesh_topology_compare.cc @@ -0,0 +1,240 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/topology/mesh_topology.h" + +#include <cassert> +#include <cstring> +#include <opensubdiv/sdc/crease.h> + +#include "internal/base/type.h" + +#include "opensubdiv_converter_capi.h" + +namespace blender { +namespace opensubdiv { + +namespace { + +//////////////////////////////////////////////////////////////////////////////// +// Quick preliminary checks. + +int getEffectiveNumEdges(const OpenSubdiv_Converter *converter) +{ + if (converter->getNumEdges == nullptr) { + return 0; + } + + return converter->getNumEdges(converter); +} + +bool isEqualGeometryCounters(const MeshTopology &mesh_topology, + const OpenSubdiv_Converter *converter) +{ + if (converter->getNumVertices(converter) != mesh_topology.getNumVertices()) { + return false; + } + if (converter->getNumFaces(converter) != mesh_topology.getNumFaces()) { + return false; + } + if (getEffectiveNumEdges(converter) != mesh_topology.getNumEdges()) { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Geometry. + +// Edges. + +bool isEqualGeometryEdge(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter) +{ + const int num_requested_edges = getEffectiveNumEdges(converter); + if (num_requested_edges != mesh_topology.getNumEdges()) { + return false; + } + + // NOTE: Ignoring the sharpness we don't really care of the content of the + // edges, they should be in the consistent state with faces and face-vertices. + // If that's not the case the mesh is invalid and comparison can not happen + // reliably. + // + // For sharpness it is important to know that edges are connecting same pair + // of vertices. But since sharpness is stored sparesly the connectivity will + // be checked when comparing edge sharpness. + + return true; +} + +// Faces. + +bool isEqualGeometryFace(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter) +{ + const int num_requested_faces = converter->getNumFaces(converter); + if (num_requested_faces != mesh_topology.getNumFaces()) { + return false; + } + + vector<int> vertices_of_face; + for (int face_index = 0; face_index < num_requested_faces; ++face_index) { + int num_face_vertices = converter->getNumFaceVertices(converter, face_index); + if (mesh_topology.getNumFaceVertices(face_index) != num_face_vertices) { + return false; + } + + vertices_of_face.resize(num_face_vertices); + converter->getFaceVertices(converter, face_index, vertices_of_face.data()); + + if (!mesh_topology.isFaceVertexIndicesEqual(face_index, vertices_of_face)) { + return false; + } + } + + return true; +} + +// Geometry comparison entry point. + +bool isEqualGeometry(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter) +{ + if (!isEqualGeometryEdge(mesh_topology, converter)) { + return false; + } + if (!isEqualGeometryFace(mesh_topology, converter)) { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Geometry tags. + +// Vertices. + +// TODO(sergey): Make this function usable by factory as well. +float getEffectiveVertexSharpness(const OpenSubdiv_Converter *converter, const int vertex_index) +{ + if (converter->isInfiniteSharpVertex != nullptr && + converter->isInfiniteSharpVertex(converter, vertex_index)) { + return OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE; + } + + if (converter->getVertexSharpness != nullptr) { + return converter->getVertexSharpness(converter, vertex_index); + } + + return 0.0f; +} + +bool isEqualVertexTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter) +{ + const int num_vertices = mesh_topology.getNumVertices(); + for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { + const float current_sharpness = mesh_topology.getVertexSharpness(vertex_index); + const float requested_sharpness = getEffectiveVertexSharpness(converter, vertex_index); + + if (current_sharpness != requested_sharpness) { + return false; + } + } + + return true; +} + +// Edges. + +// TODO(sergey): Make this function usable by factory as well. +float getEffectiveEdgeSharpness(const OpenSubdiv_Converter *converter, const int edge_index) +{ + if (converter->getEdgeSharpness != nullptr) { + return converter->getEdgeSharpness(converter, edge_index); + } + + return 0.0f; +} + +bool isEqualEdgeTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter) +{ + const int num_edges = mesh_topology.getNumEdges(); + for (int edge_index = 0; edge_index < num_edges; ++edge_index) { + const float current_sharpness = mesh_topology.getEdgeSharpness(edge_index); + const float requested_sharpness = getEffectiveEdgeSharpness(converter, edge_index); + + if (current_sharpness != requested_sharpness) { + return false; + } + + if (current_sharpness < 1e-6f) { + continue; + } + + int requested_edge_vertices[2]; + converter->getEdgeVertices(converter, edge_index, requested_edge_vertices); + if (!mesh_topology.isEdgeEqual( + edge_index, requested_edge_vertices[0], requested_edge_vertices[1])) { + return false; + } + } + + return true; +} + +// Tags comparison entry point. + +bool isEqualTags(const MeshTopology &mesh_topology, const OpenSubdiv_Converter *converter) +{ + if (!isEqualVertexTags(mesh_topology, converter)) { + return false; + } + if (!isEqualEdgeTags(mesh_topology, converter)) { + return false; + } + + return true; +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// Entry point. + +bool MeshTopology::isEqualToConverter(const OpenSubdiv_Converter *converter) const +{ + // Preliminary checks. + if (!isEqualGeometryCounters(*this, converter)) { + return false; + } + + // Geometry. + if (!isEqualGeometry(*this, converter)) { + return false; + } + + // Tags. + if (!isEqualTags(*this, converter)) { + return false; + } + + return true; +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/topology/mesh_topology_test.cc b/intern/opensubdiv/internal/topology/mesh_topology_test.cc new file mode 100644 index 00000000000..5fb58c37add --- /dev/null +++ b/intern/opensubdiv/internal/topology/mesh_topology_test.cc @@ -0,0 +1,98 @@ +// Copyright 2020 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/topology/mesh_topology.h" +#include "testing/testing.h" + +namespace blender { +namespace opensubdiv { + +TEST(MeshTopology, TrivialVertexSharpness) +{ + MeshTopology mesh_topology; + + mesh_topology.setNumVertices(3); + mesh_topology.finishResizeTopology(); + + mesh_topology.setVertexSharpness(0, 0.1f); + mesh_topology.setVertexSharpness(1, 0.2f); + + EXPECT_EQ(mesh_topology.getVertexSharpness(0), 0.1f); + EXPECT_EQ(mesh_topology.getVertexSharpness(1), 0.2f); + EXPECT_EQ(mesh_topology.getVertexSharpness(2), 0.0f); +} + +TEST(MeshTopology, TrivialEdgeSharpness) +{ + MeshTopology mesh_topology; + + mesh_topology.setNumVertices(8); + mesh_topology.setNumEdges(3); + mesh_topology.finishResizeTopology(); + + mesh_topology.setEdgeVertexIndices(0, 0, 1); + mesh_topology.setEdgeVertexIndices(1, 1, 2); + mesh_topology.setEdgeVertexIndices(2, 2, 3); + + mesh_topology.setEdgeSharpness(0, 0.1f); + mesh_topology.setEdgeSharpness(2, 0.2f); + + EXPECT_EQ(mesh_topology.getEdgeSharpness(0), 0.1f); + EXPECT_EQ(mesh_topology.getEdgeSharpness(1), 0.0f); + EXPECT_EQ(mesh_topology.getEdgeSharpness(2), 0.2f); +} + +TEST(MeshTopology, TrivialFaceTopology) +{ + MeshTopology mesh_topology; + + mesh_topology.setNumFaces(3); + mesh_topology.setNumFaceVertices(0, 4); + mesh_topology.setNumFaceVertices(1, 3); + mesh_topology.setNumFaceVertices(2, 5); + mesh_topology.finishResizeTopology(); + + EXPECT_EQ(mesh_topology.getNumFaceVertices(0), 4); + EXPECT_EQ(mesh_topology.getNumFaceVertices(1), 3); + EXPECT_EQ(mesh_topology.getNumFaceVertices(2), 5); + + { + int vertex_indices[] = {0, 1, 2, 3}; + mesh_topology.setFaceVertexIndices(0, 4, vertex_indices); + } + + { + int vertex_indices[] = {4, 5, 6}; + mesh_topology.setFaceVertexIndices(1, 3, vertex_indices); + } + + { + int vertex_indices[] = {7, 8, 9, 10, 11}; + mesh_topology.setFaceVertexIndices(2, 5, vertex_indices); + } + + EXPECT_TRUE(mesh_topology.isFaceVertexIndicesEqual(0, {{0, 1, 2, 3}})); + EXPECT_FALSE(mesh_topology.isFaceVertexIndicesEqual(0, {{10, 1, 2, 3}})); + EXPECT_FALSE(mesh_topology.isFaceVertexIndicesEqual(0, {{0, 1, 2}})); + + EXPECT_TRUE(mesh_topology.isFaceVertexIndicesEqual(1, {{4, 5, 6}})); + EXPECT_TRUE(mesh_topology.isFaceVertexIndicesEqual(2, {{7, 8, 9, 10, 11}})); +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/topology/topology_refiner_capi.cc b/intern/opensubdiv/internal/topology/topology_refiner_capi.cc new file mode 100644 index 00000000000..b30d509be20 --- /dev/null +++ b/intern/opensubdiv/internal/topology/topology_refiner_capi.cc @@ -0,0 +1,262 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "opensubdiv_topology_refiner_capi.h" + +#include "MEM_guardedalloc.h" +#include "internal/base/type_convert.h" +#include "internal/topology/topology_refiner_impl.h" + +using blender::opensubdiv::vector; + +namespace { + +const OpenSubdiv::Far::TopologyRefiner *getOSDTopologyRefiner( + const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return topology_refiner->impl->topology_refiner; +} + +const OpenSubdiv::Far::TopologyLevel &getOSDTopologyBaseLevel( + const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return getOSDTopologyRefiner(topology_refiner)->GetLevel(0); +} + +int getSubdivisionLevel(const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return topology_refiner->impl->settings.level; +} + +bool getIsAdaptive(const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return topology_refiner->impl->settings.is_adaptive; +} + +//////////////////////////////////////////////////////////////////////////////// +// Query basic topology information from base level. + +int getNumVertices(const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return getOSDTopologyBaseLevel(topology_refiner).GetNumVertices(); +} + +int getNumEdges(const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return getOSDTopologyBaseLevel(topology_refiner).GetNumEdges(); +} + +int getNumFaces(const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return getOSDTopologyBaseLevel(topology_refiner).GetNumFaces(); +} + +//////////////////////////////////////////////////////////////////////////////// +// PTex face geometry queries. + +static void convertArrayToRaw(const OpenSubdiv::Far::ConstIndexArray &array, int *raw_array) +{ + for (int i = 0; i < array.size(); ++i) { + raw_array[i] = array[i]; + } +} + +int getNumFaceVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + return base_level.GetFaceVertices(face_index).size(); +} + +void getFaceVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, + const int face_index, + int *face_vertices_indices) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceVertices(face_index); + convertArrayToRaw(array, face_vertices_indices); +} + +int getNumFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + return base_level.GetFaceEdges(face_index).size(); +} + +void getFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, + const int face_index, + int *face_edges_indices) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceEdges(face_index); + convertArrayToRaw(array, face_edges_indices); +} + +void getEdgeVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, + const int edge_index, + int edge_vertices_indices[2]) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + OpenSubdiv::Far::ConstIndexArray array = base_level.GetEdgeVertices(edge_index); + assert(array.size() == 2); + edge_vertices_indices[0] = array[0]; + edge_vertices_indices[1] = array[1]; +} + +int getNumVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, const int vertex_index) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + return base_level.GetVertexEdges(vertex_index).size(); +} + +void getVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, + const int vertex_index, + int *vertex_edges_indices) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + OpenSubdiv::Far::ConstIndexArray array = base_level.GetVertexEdges(vertex_index); + convertArrayToRaw(array, vertex_edges_indices); +} + +int getNumFacePtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index) +{ + const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index); + if (num_face_vertices == 4) { + return 1; + } + else { + return num_face_vertices; + } +} + +int getNumPtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner) +{ + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + int num_ptex_faces = 0; + for (int face_index = 0; face_index < num_faces; ++face_index) { + num_ptex_faces += topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); + } + return num_ptex_faces; +} + +void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner *topology_refiner, + int *face_ptex_index_offset) +{ + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + int num_ptex_faces = 0; + for (int face_index = 0; face_index < num_faces; ++face_index) { + face_ptex_index_offset[face_index] = num_ptex_faces; + num_ptex_faces += topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Face-varying data. + +int getNumFVarChannels(const struct OpenSubdiv_TopologyRefiner *topology_refiner) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + return base_level.GetNumFVarChannels(); +} + +OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation( + const struct OpenSubdiv_TopologyRefiner *topology_refiner) +{ + return blender::opensubdiv::getCAPIFVarLinearInterpolationFromOSD( + getOSDTopologyRefiner(topology_refiner)->GetFVarLinearInterpolation()); +} + +int getNumFVarValues(const struct OpenSubdiv_TopologyRefiner *topology_refiner, const int channel) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + return base_level.GetNumFVarValues(channel); +} + +const int *getFaceFVarValueIndices(const struct OpenSubdiv_TopologyRefiner *topology_refiner, + const int face_index, + const int channel) +{ + const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); + return &base_level.GetFaceFVarValues(face_index, channel)[0]; +} + +//////////////////////////////////////////////////////////////////////////////// +// Internal helpers. + +void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner) +{ + topology_refiner->getSubdivisionLevel = getSubdivisionLevel; + topology_refiner->getIsAdaptive = getIsAdaptive; + // Basic topology information. + topology_refiner->getNumVertices = getNumVertices; + topology_refiner->getNumEdges = getNumEdges; + topology_refiner->getNumFaces = getNumFaces; + topology_refiner->getNumFaceVertices = getNumFaceVertices; + topology_refiner->getFaceVertices = getFaceVertices; + topology_refiner->getNumFaceEdges = getNumFaceEdges; + topology_refiner->getFaceEdges = getFaceEdges; + topology_refiner->getEdgeVertices = getEdgeVertices; + topology_refiner->getNumVertexEdges = getNumVertexEdges; + topology_refiner->getVertexEdges = getVertexEdges; + // PTex face geometry. + topology_refiner->getNumFacePtexFaces = getNumFacePtexFaces; + topology_refiner->getNumPtexFaces = getNumPtexFaces; + topology_refiner->fillFacePtexIndexOffset = fillFacePtexIndexOffset; + // Face-varying data. + topology_refiner->getNumFVarChannels = getNumFVarChannels; + topology_refiner->getFVarLinearInterpolation = getFVarLinearInterpolation; + topology_refiner->getNumFVarValues = getNumFVarValues; + topology_refiner->getFaceFVarValueIndices = getFaceFVarValueIndices; +} + +OpenSubdiv_TopologyRefiner *allocateTopologyRefiner() +{ + OpenSubdiv_TopologyRefiner *topology_refiner = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefiner); + assignFunctionPointers(topology_refiner); + return topology_refiner; +} + +} // namespace + +OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter( + OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings) +{ + using blender::opensubdiv::TopologyRefinerImpl; + + TopologyRefinerImpl *topology_refiner_impl = TopologyRefinerImpl::createFromConverter(converter, + *settings); + if (topology_refiner_impl == nullptr) { + return nullptr; + } + + OpenSubdiv_TopologyRefiner *topology_refiner = allocateTopologyRefiner(); + topology_refiner->impl = static_cast<OpenSubdiv_TopologyRefinerImpl *>(topology_refiner_impl); + + return topology_refiner; +} + +void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner) +{ + delete topology_refiner->impl; + OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefiner); +} + +bool openSubdiv_topologyRefinerCompareWithConverter( + const OpenSubdiv_TopologyRefiner *topology_refiner, const OpenSubdiv_Converter *converter) +{ + return topology_refiner->impl->isEqualToConverter(converter); +} diff --git a/intern/opensubdiv/internal/opensubdiv_converter_factory.cc b/intern/opensubdiv/internal/topology/topology_refiner_factory.cc index ab93b5ce952..9688bc9eb0f 100644 --- a/intern/opensubdiv/internal/opensubdiv_converter_factory.cc +++ b/intern/opensubdiv/internal/topology/topology_refiner_factory.cc @@ -20,27 +20,30 @@ # include <iso646.h> #endif -#include "internal/opensubdiv_converter_factory.h" +#include "internal/topology/topology_refiner_impl.h" #include <cassert> #include <cstdio> #include <opensubdiv/far/topologyRefinerFactory.h> -#include "internal/opensubdiv_converter_internal.h" -#include "internal/opensubdiv_converter_orient.h" -#include "internal/opensubdiv_internal.h" -#include "internal/opensubdiv_util.h" +#include "internal/base/type.h" +#include "internal/base/type_convert.h" +#include "internal/topology/mesh_topology.h" + #include "opensubdiv_converter_capi.h" -using opensubdiv_capi::min; -using opensubdiv_capi::stack; -using opensubdiv_capi::vector; +using blender::opensubdiv::min; +using blender::opensubdiv::stack; +using blender::opensubdiv::vector; struct TopologyRefinerData { const OpenSubdiv_Converter *converter; + blender::opensubdiv::MeshTopology *base_mesh_topology; }; +typedef OpenSubdiv::Far::TopologyRefinerFactory<TopologyRefinerData> TopologyRefinerFactoryType; + namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Far { @@ -49,21 +52,52 @@ template<> inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology( TopologyRefiner &refiner, const TopologyRefinerData &cb_data) { + using blender::opensubdiv::MeshTopology; + const OpenSubdiv_Converter *converter = cb_data.converter; + MeshTopology *base_mesh_topology = cb_data.base_mesh_topology; + + // Vertices. + const int num_vertices = converter->getNumVertices(converter); + base_mesh_topology->setNumVertices(num_vertices); + setNumBaseVertices(refiner, num_vertices); + + // Edges. + // + // NOTE: Always store edges in the base mesh topology so then comparison can + // happen, but only provide edges to TopologyRefiner if full topology is + // specified (if full topology is not specified then topology refiner must + // not see any edges, which will indicate to it that winding and edges are to + // be reconstructed). + // + // NOTE: it is a possible usecase when user code does not need crease at all + // (which is the only real reason why converter would want to provide edges in + // the case of partial topology specification). So it might be so getNumEdges + // callback is nullptr. + if (converter->getNumEdges != nullptr) { + const int num_edges = converter->getNumEdges(converter); + base_mesh_topology->setNumEdges(num_edges); + } + // Faces and face-vertices. const int num_faces = converter->getNumFaces(converter); + base_mesh_topology->setNumFaces(num_faces); setNumBaseFaces(refiner, num_faces); for (int face_index = 0; face_index < num_faces; ++face_index) { const int num_face_vertices = converter->getNumFaceVertices(converter, face_index); + base_mesh_topology->setNumFaceVertices(face_index, num_face_vertices); setNumBaseFaceVertices(refiner, face_index, num_face_vertices); } - // Vertices. - const int num_vertices = converter->getNumVertices(converter); - setNumBaseVertices(refiner, num_vertices); + // If converter does not provide full topology, we are done. + // + // The rest is needed to define relations between faces-of-edge and + // edges-of-vertex, which is not available for partially specified mesh. if (!converter->specifiesFullTopology(converter)) { + base_mesh_topology->finishResizeTopology(); return true; } + // Edges and edge-faces. const int num_edges = converter->getNumEdges(converter); setNumBaseEdges(refiner, num_edges); @@ -71,6 +105,7 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology const int num_edge_faces = converter->getNumEdgeFaces(converter, edge_index); setNumBaseEdgeFaces(refiner, edge_index, num_edge_faces); } + // Vertex-faces and vertex-edges. for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { const int num_vert_edges = converter->getNumVertexEdges(converter, vertex_index); @@ -78,6 +113,8 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology setNumBaseVertexEdges(refiner, vertex_index, num_vert_edges); setNumBaseVertexFaces(refiner, vertex_index, num_vert_faces); } + + base_mesh_topology->finishResizeTopology(); return true; } @@ -85,33 +122,32 @@ template<> inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology( TopologyRefiner &refiner, const TopologyRefinerData &cb_data) { + using blender::opensubdiv::MeshTopology; using Far::IndexArray; + const OpenSubdiv_Converter *converter = cb_data.converter; + MeshTopology *base_mesh_topology = cb_data.base_mesh_topology; + const bool full_topology_specified = converter->specifiesFullTopology(converter); - // Face relations. + + // Vertices of face. const int num_faces = converter->getNumFaces(converter); for (int face_index = 0; face_index < num_faces; ++face_index) { IndexArray dst_face_verts = getBaseFaceVertices(refiner, face_index); converter->getFaceVertices(converter, face_index, &dst_face_verts[0]); - if (full_topology_specified) { - IndexArray dst_face_edges = getBaseFaceEdges(refiner, face_index); - converter->getFaceEdges(converter, face_index, &dst_face_edges[0]); - } + + base_mesh_topology->setFaceVertexIndices( + face_index, dst_face_verts.size(), &dst_face_verts[0]); } + // If converter does not provide full topology, we are done. + // + // The rest is needed to define relations between faces-of-edge and + // edges-of-vertex, which is not available for partially specified mesh. if (!full_topology_specified) { return true; } - // Edge relations. - const int num_edges = converter->getNumEdges(converter); - for (int edge_index = 0; edge_index < num_edges; ++edge_index) { - // Edge-vertices. - IndexArray dst_edge_vertices = getBaseEdgeVertices(refiner, edge_index); - converter->getEdgeVertices(converter, edge_index, &dst_edge_vertices[0]); - // Edge-faces. - IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge_index); - converter->getEdgeFaces(converter, edge_index, &dst_edge_faces[0]); - } + // Vertex relations. const int num_vertices = converter->getNumVertices(converter); vector<int> vertex_faces, vertex_edges; @@ -121,6 +157,7 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology const int num_vertex_faces = converter->getNumVertexFaces(converter, vertex_index); vertex_faces.resize(num_vertex_faces); converter->getVertexFaces(converter, vertex_index, &vertex_faces[0]); + // Vertex-edges. IndexArray dst_vertex_edges = getBaseVertexEdges(refiner, vertex_index); const int num_vertex_edges = converter->getNumVertexEdges(converter, vertex_index); @@ -129,7 +166,27 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology memcpy(&dst_vertex_edges[0], &vertex_edges[0], sizeof(int) * num_vertex_edges); memcpy(&dst_vertex_faces[0], &vertex_faces[0], sizeof(int) * num_vertex_faces); } + + // Edge relations. + const int num_edges = converter->getNumEdges(converter); + for (int edge_index = 0; edge_index < num_edges; ++edge_index) { + // Vertices this edge connects. + IndexArray dst_edge_vertices = getBaseEdgeVertices(refiner, edge_index); + converter->getEdgeVertices(converter, edge_index, &dst_edge_vertices[0]); + + // Faces adjacent to this edge. + IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge_index); + converter->getEdgeFaces(converter, edge_index, &dst_edge_faces[0]); + } + + // Face relations. + for (int face_index = 0; face_index < num_faces; ++face_index) { + IndexArray dst_face_edges = getBaseFaceEdges(refiner, face_index); + converter->getFaceEdges(converter, face_index, &dst_face_edges[0]); + } + populateBaseLocalIndices(refiner); + return true; } @@ -137,8 +194,12 @@ template<> inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( TopologyRefiner &refiner, const TopologyRefinerData &cb_data) { + using blender::opensubdiv::MeshTopology; using OpenSubdiv::Sdc::Crease; + const OpenSubdiv_Converter *converter = cb_data.converter; + MeshTopology *base_mesh_topology = cb_data.base_mesh_topology; + const bool full_topology_specified = converter->specifiesFullTopology(converter); if (full_topology_specified || converter->getEdgeVertices != NULL) { const int num_edges = converter->getNumEdges(converter); @@ -147,12 +208,18 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( if (sharpness < 1e-6f) { continue; } + + int edge_vertices[2]; + converter->getEdgeVertices(converter, edge_index, edge_vertices); + base_mesh_topology->setEdgeVertexIndices(edge_index, edge_vertices[0], edge_vertices[1]); + base_mesh_topology->setEdgeSharpness(edge_index, sharpness); + if (full_topology_specified) { setBaseEdgeSharpness(refiner, edge_index, sharpness); } else { - int edge_vertices[2]; - converter->getEdgeVertices(converter, edge_index, edge_vertices); + // TODO(sergey): Should be a faster way to find reconstructed edge to + // specify sharpness for (assuming, findBaseEdge has linear complexity). const int base_edge_index = findBaseEdge(refiner, edge_vertices[0], edge_vertices[1]); if (base_edge_index == OpenSubdiv::Far::INDEX_INVALID) { printf("OpenSubdiv Error: failed to find reconstructed edge\n"); @@ -162,6 +229,7 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( } } } + // OpenSubdiv expects non-manifold vertices to be sharp but at the time it // handles correct cases when vertex is a corner of plane. Currently mark // vertices which are adjacent to a loose edge as sharp, but this decision @@ -170,6 +238,7 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { ConstIndexArray vertex_edges = getBaseVertexEdges(refiner, vertex_index); if (converter->isInfiniteSharpVertex(converter, vertex_index)) { + base_mesh_topology->setVertexSharpness(vertex_index, Crease::SHARPNESS_INFINITE); setBaseVertexSharpness(refiner, vertex_index, Crease::SHARPNESS_INFINITE); continue; } @@ -178,6 +247,7 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( float sharpness = 0.0f; if (converter->getVertexSharpness != NULL) { sharpness = converter->getVertexSharpness(converter, vertex_index); + base_mesh_topology->setVertexSharpness(vertex_index, sharpness); } // If it's vertex where 2 non-manifold edges meet adjust vertex sharpness to @@ -246,50 +316,74 @@ inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology( } /* namespace OPENSUBDIV_VERSION */ } /* namespace OpenSubdiv */ -namespace opensubdiv_capi { +namespace blender { +namespace opensubdiv { namespace { -OpenSubdiv::Sdc::Options::VtxBoundaryInterpolation getVtxBoundaryInterpolationFromCAPI( - OpenSubdiv_VtxBoundaryInterpolation boundary_interpolation) +OpenSubdiv::Sdc::Options getSDCOptions(OpenSubdiv_Converter *converter) { using OpenSubdiv::Sdc::Options; - switch (boundary_interpolation) { - case OSD_VTX_BOUNDARY_NONE: - return Options::VTX_BOUNDARY_NONE; - case OSD_VTX_BOUNDARY_EDGE_ONLY: - return Options::VTX_BOUNDARY_EDGE_ONLY; - case OSD_VTX_BOUNDARY_EDGE_AND_CORNER: - return Options::VTX_BOUNDARY_EDGE_AND_CORNER; - } - assert(!"Unknown veretx boundary interpolation."); - return Options::VTX_BOUNDARY_EDGE_ONLY; -} - -} // namespace -OpenSubdiv::Far::TopologyRefiner *createOSDTopologyRefinerFromConverter( - OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::TopologyRefinerFactory; - using OpenSubdiv::Sdc::Options; - const OpenSubdiv::Sdc::SchemeType scheme_type = getSchemeTypeFromCAPI( - converter->getSchemeType(converter)); const Options::FVarLinearInterpolation linear_interpolation = getFVarLinearInterpolationFromCAPI( converter->getFVarLinearInterpolation(converter)); + Options options; options.SetVtxBoundaryInterpolation( getVtxBoundaryInterpolationFromCAPI(converter->getVtxBoundaryInterpolation(converter))); options.SetCreasingMethod(Options::CREASE_UNIFORM); options.SetFVarLinearInterpolation(linear_interpolation); - TopologyRefinerFactory<TopologyRefinerData>::Options topology_options(scheme_type, options); -#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY - topology_options.validateFullTopology = true; -#endif + return options; +} + +TopologyRefinerFactoryType::Options getTopologyRefinerOptions(OpenSubdiv_Converter *converter) +{ + using OpenSubdiv::Sdc::SchemeType; + + OpenSubdiv::Sdc::Options sdc_options = getSDCOptions(converter); + + const SchemeType scheme_type = getSchemeTypeFromCAPI(converter->getSchemeType(converter)); + TopologyRefinerFactoryType::Options topology_options(scheme_type, sdc_options); + + // NOTE: When debugging topology conversion related functionality it is helpful to set this + // to truth. In all other cases leave it at false. so debugging of other areas is not affected + // by performance penalty happening in this module. + topology_options.validateFullTopology = false; + + return topology_options; +} + +} // namespace + +TopologyRefinerImpl *TopologyRefinerImpl::createFromConverter( + OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings &settings) +{ + using OpenSubdiv::Far::TopologyRefiner; + + blender::opensubdiv::MeshTopology base_mesh_topology; + TopologyRefinerData cb_data; cb_data.converter = converter; - return TopologyRefinerFactory<TopologyRefinerData>::Create(cb_data, topology_options); + cb_data.base_mesh_topology = &base_mesh_topology; + + // Create OpenSubdiv descriptor for the topology refiner. + TopologyRefinerFactoryType::Options topology_refiner_options = getTopologyRefinerOptions( + converter); + TopologyRefiner *topology_refiner = TopologyRefinerFactoryType::Create(cb_data, + topology_refiner_options); + if (topology_refiner == nullptr) { + return nullptr; + } + + // Create Blender-side object holding all necessary data for the topology refiner. + TopologyRefinerImpl *topology_refiner_impl = new TopologyRefinerImpl(); + topology_refiner_impl->topology_refiner = topology_refiner; + topology_refiner_impl->settings = settings; + topology_refiner_impl->base_mesh_topology = move(base_mesh_topology); + + return topology_refiner_impl; } -} // namespace opensubdiv_capi +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc b/intern/opensubdiv/internal/topology/topology_refiner_impl.cc index f3054a17da2..fe14d42ac33 100644 --- a/intern/opensubdiv/internal/opensubdiv_topology_refiner_internal.cc +++ b/intern/opensubdiv/internal/topology/topology_refiner_impl.cc @@ -16,14 +16,19 @@ // // Author: Sergey Sharybin -#include "internal/opensubdiv_topology_refiner_internal.h" +#include "internal/topology/topology_refiner_impl.h" -OpenSubdiv_TopologyRefinerInternal::OpenSubdiv_TopologyRefinerInternal() - : osd_topology_refiner(NULL) +namespace blender { +namespace opensubdiv { + +TopologyRefinerImpl::TopologyRefinerImpl() : topology_refiner(nullptr) { } -OpenSubdiv_TopologyRefinerInternal::~OpenSubdiv_TopologyRefinerInternal() +TopologyRefinerImpl::~TopologyRefinerImpl() { - delete osd_topology_refiner; + delete topology_refiner; } + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/topology/topology_refiner_impl.h b/intern/opensubdiv/internal/topology/topology_refiner_impl.h new file mode 100644 index 00000000000..a9750166b35 --- /dev/null +++ b/intern/opensubdiv/internal/topology/topology_refiner_impl.h @@ -0,0 +1,82 @@ +// Copyright 2016 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_TOPOLOGY_REFINER_IMPL_H_ +#define OPENSUBDIV_TOPOLOGY_REFINER_IMPL_H_ + +#ifdef _MSC_VER +# include <iso646.h> +#endif + +#include <opensubdiv/far/topologyRefiner.h> + +#include "internal/base/memory.h" +#include "internal/topology/mesh_topology.h" +#include "opensubdiv_topology_refiner_capi.h" + +struct OpenSubdiv_Converter; + +namespace blender { +namespace opensubdiv { + +class TopologyRefinerImpl { + public: + // NOTE: Will return nullptr if topology refiner can not be created (for + // example, when topology is detected to be corrupted or invalid). + static TopologyRefinerImpl *createFromConverter( + OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings &settings); + + TopologyRefinerImpl(); + ~TopologyRefinerImpl(); + + // Check whether this topology refiner defines same topology as the given + // converter. + // Covers options, geometry, and geometry tags. + bool isEqualToConverter(const OpenSubdiv_Converter *converter) const; + + OpenSubdiv::Far::TopologyRefiner *topology_refiner; + + // Subdivision settingsa this refiner is created for. + OpenSubdiv_TopologyRefinerSettings settings; + + // Topology of the mesh which corresponds to the base level. + // + // All the indices and values are kept exactly the same as user-defined + // converter provided them. This allows to easily compare values which might + // be touched by the refinement process. + // + // On a more technical note this allows to easier/faster to compare following + // things: + // + // - Face vertices, where OpenSubdiv could re-arrange them to keep winding + // uniform. + // + // - Vertex crease where OpenSubdiv will force crease for non-manifold or + // corner vertices. + MeshTopology base_mesh_topology; + + MEM_CXX_CLASS_ALLOC_FUNCS("TopologyRefinerImpl"); +}; + +} // namespace opensubdiv +} // namespace blender + +struct OpenSubdiv_TopologyRefinerImpl : public blender::opensubdiv::TopologyRefinerImpl { +}; + +#endif // OPENSUBDIV_TOPOLOGY_REFINER_IMPL_H_ diff --git a/intern/opensubdiv/internal/topology/topology_refiner_impl_compare.cc b/intern/opensubdiv/internal/topology/topology_refiner_impl_compare.cc new file mode 100644 index 00000000000..d8f52e5bbb5 --- /dev/null +++ b/intern/opensubdiv/internal/topology/topology_refiner_impl_compare.cc @@ -0,0 +1,153 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/topology/topology_refiner_impl.h" + +#include "internal/base/type.h" +#include "internal/base/type_convert.h" +#include "internal/topology/mesh_topology.h" +#include "internal/topology/topology_refiner_impl.h" + +#include "opensubdiv_converter_capi.h" + +namespace blender { +namespace opensubdiv { +namespace { + +const OpenSubdiv::Far::TopologyRefiner *getOSDTopologyRefiner( + const TopologyRefinerImpl *topology_refiner_impl) +{ + return topology_refiner_impl->topology_refiner; +} + +const OpenSubdiv::Far::TopologyLevel &getOSDTopologyBaseLevel( + const TopologyRefinerImpl *topology_refiner_impl) +{ + return getOSDTopologyRefiner(topology_refiner_impl)->GetLevel(0); +} + +//////////////////////////////////////////////////////////////////////////////// +// Quick preliminary checks. + +bool checkSchemeTypeMatches(const TopologyRefinerImpl *topology_refiner_impl, + const OpenSubdiv_Converter *converter) +{ + const OpenSubdiv::Sdc::SchemeType converter_scheme_type = + blender::opensubdiv::getSchemeTypeFromCAPI(converter->getSchemeType(converter)); + return (converter_scheme_type == getOSDTopologyRefiner(topology_refiner_impl)->GetSchemeType()); +} + +bool checkOptionsMatches(const TopologyRefinerImpl *topology_refiner_impl, + const OpenSubdiv_Converter *converter) +{ + typedef OpenSubdiv::Sdc::Options Options; + const Options options = getOSDTopologyRefiner(topology_refiner_impl)->GetSchemeOptions(); + const Options::FVarLinearInterpolation fvar_interpolation = options.GetFVarLinearInterpolation(); + const Options::FVarLinearInterpolation converter_fvar_interpolation = + blender::opensubdiv::getFVarLinearInterpolationFromCAPI( + converter->getFVarLinearInterpolation(converter)); + if (fvar_interpolation != converter_fvar_interpolation) { + return false; + } + return true; +} + +bool checkPreliminaryMatches(const TopologyRefinerImpl *topology_refiner_impl, + const OpenSubdiv_Converter *converter) +{ + return checkSchemeTypeMatches(topology_refiner_impl, converter) && + checkOptionsMatches(topology_refiner_impl, converter); +} + +//////////////////////////////////////////////////////////////////////////////// +// Compare attributes which affects on topology. +// +// TODO(sergey): Need to look into how auto-winding affects on face-varying +// indexing and, possibly, move to mesh topology as well if winding affects +// face-varyign as well. + +bool checkSingleUVLayerMatch(const OpenSubdiv::Far::TopologyLevel &base_level, + const OpenSubdiv_Converter *converter, + const int layer_index) +{ + converter->precalcUVLayer(converter, layer_index); + const int num_faces = base_level.GetNumFaces(); + // TODO(sergey): Need to check whether converter changed the winding of + // face to match OpenSubdiv's expectations. + for (int face_index = 0; face_index < num_faces; ++face_index) { + OpenSubdiv::Far::ConstIndexArray base_level_face_uvs = base_level.GetFaceFVarValues( + face_index, layer_index); + for (int corner = 0; corner < base_level_face_uvs.size(); ++corner) { + const int uv_index = converter->getFaceCornerUVIndex(converter, face_index, corner); + if (base_level_face_uvs[corner] != uv_index) { + converter->finishUVLayer(converter); + return false; + } + } + } + converter->finishUVLayer(converter); + return true; +} + +bool checkUVLayersMatch(const TopologyRefinerImpl *topology_refiner_impl, + const OpenSubdiv_Converter *converter) +{ + using OpenSubdiv::Far::TopologyLevel; + const int num_layers = converter->getNumUVLayers(converter); + const TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner_impl); + // Number of UV layers should match. + if (base_level.GetNumFVarChannels() != num_layers) { + return false; + } + for (int layer_index = 0; layer_index < num_layers; ++layer_index) { + if (!checkSingleUVLayerMatch(base_level, converter, layer_index)) { + return false; + } + } + return true; +} + +bool checkTopologyAttributesMatch(const TopologyRefinerImpl *topology_refiner_impl, + const OpenSubdiv_Converter *converter) +{ + return checkUVLayersMatch(topology_refiner_impl, converter); +} + +} // namespace + +bool TopologyRefinerImpl::isEqualToConverter(const OpenSubdiv_Converter *converter) const +{ + if (!blender::opensubdiv::checkPreliminaryMatches(this, converter)) { + return false; + } + + if (!base_mesh_topology.isEqualToConverter(converter)) { + return false; + } + + // NOTE: Do after geometry check, to be sure topology does match and all + // indexing will go fine. + if (!blender::opensubdiv::checkTopologyAttributesMatch(this, converter)) { + return false; + } + + return true; +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h index 1572d01b851..b860ae8db2e 100644 --- a/intern/opensubdiv/opensubdiv_evaluator_capi.h +++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h @@ -122,10 +122,8 @@ typedef struct OpenSubdiv_Evaluator { float *dPdu, float *dPdv); - // Internal storage for the use in this module only. - // - // This is where actual OpenSubdiv's evaluator is living. - struct OpenSubdiv_EvaluatorInternal *internal; + // Implementation of the evaluator. + struct OpenSubdiv_EvaluatorImpl *impl; } OpenSubdiv_Evaluator; OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( diff --git a/intern/opensubdiv/opensubdiv_gl_mesh_capi.h b/intern/opensubdiv/opensubdiv_gl_mesh_capi.h deleted file mode 100644 index f7dd6f83434..00000000000 --- a/intern/opensubdiv/opensubdiv_gl_mesh_capi.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2013 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_CAPI_GL_MESH_CAPI_H_ -#define OPENSUBDIV_CAPI_GL_MESH_CAPI_H_ - -#include <stdint.h> // for bool - -#include "opensubdiv_capi_type.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct OpenSubdiv_GLMeshInternal; - -// Mesh which is displayable in OpenGL context. -typedef struct OpenSubdiv_GLMesh { - ////////////////////////////////////////////////////////////////////////////// - // Subdivision/topology part. - - // Returns the GL index buffer containing the patch control vertices. - unsigned int (*getPatchIndexBuffer)(struct OpenSubdiv_GLMesh *gl_mesh); - - // Bind GL buffer which contains vertices (VBO). - // TODO(sergey): Is this a coarse vertices? - void (*bindVertexBuffer)(struct OpenSubdiv_GLMesh *gl_mesh); - - // Set coarse positions from a continuous array of coordinates. - void (*setCoarsePositions)(struct OpenSubdiv_GLMesh *gl_mesh, - const float *positions, - const int start_vertex, - const int num_vertices); - // TODO(sergey): setCoarsePositionsFromBuffer(). - - // Refine after coarse positions update. - void (*refine)(struct OpenSubdiv_GLMesh *gl_mesh); - - // Synchronize after coarse positions update and refine. - void (*synchronize)(struct OpenSubdiv_GLMesh *gl_mesh); - - ////////////////////////////////////////////////////////////////////////////// - // Drawing part. - - // Prepare mesh for display. - void (*prepareDraw)(struct OpenSubdiv_GLMesh *gl_mesh, - const bool use_osd_glsl, - const int active_uv_index); - - // Draw given range of patches. - // - // If fill_quads is false, then patches are drawn in wireframe. - void (*drawPatches)(struct OpenSubdiv_GLMesh *gl_mesh, - const bool fill_quads, - const int start_patch, - const int num_patches); - - // Internal storage for the use in this module only. - // - // Tease: This contains an actual OpenSubdiv's Mesh object. - struct OpenSubdiv_GLMeshInternal *internal; -} OpenSubdiv_GLMesh; - -OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( - struct OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type); - -void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh); - -// Global resources needed for GL mesh drawing. -bool openSubdiv_initGLMeshDrawingResources(void); -void openSubdiv_deinitGLMeshDrawingResources(void); - -#ifdef __cplusplus -} -#endif - -#endif // OPENSUBDIV_CAPI_GL_MESH_CAPI_H_ diff --git a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h index 38d722ab572..fe2f3f3ce2d 100644 --- a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h +++ b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h @@ -28,7 +28,7 @@ extern "C" { #endif struct OpenSubdiv_Converter; -struct OpenSubdiv_TopologyRefinerInternal; +struct OpenSubdiv_TopologyRefinerImpl; // Those settings don't really belong to OpenSubdiv's topology refiner, but // we are keeping track of them on our side of topology refiner. This is to @@ -40,6 +40,10 @@ typedef struct OpenSubdiv_TopologyRefinerSettings { int level; } OpenSubdiv_TopologyRefinerSettings; +// C-style wrapper around actual topology refiner. +// +// The only purpose is to allow C-only code to access C++ implementation of the +// topology refiner. typedef struct OpenSubdiv_TopologyRefiner { // Query subdivision level the refiner is created for. int (*getSubdivisionLevel)(const struct OpenSubdiv_TopologyRefiner *topology_refiner); @@ -125,11 +129,8 @@ typedef struct OpenSubdiv_TopologyRefiner { ////////////////////////////////////////////////////////////////////////////// // Internal use. - // Internal storage for the use in this module only. - // - // Tease: Contains actual OpenSubdiv's refiner and (optionally) some other - // data and state needed for an internbal use. - struct OpenSubdiv_TopologyRefinerInternal *internal; + // Implementation of the topology refiner. + struct OpenSubdiv_TopologyRefinerImpl *impl; } OpenSubdiv_TopologyRefiner; // NOTE: Will return NULL in cases of bad topology. diff --git a/intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl deleted file mode 100644 index 7f08182d78a..00000000000 --- a/intern/opensubdiv/shader/gpu_shader_opensubdiv_fragment.glsl +++ /dev/null @@ -1,163 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2014 Blender Foundation. - * All rights reserved. - */ - -struct VertexData { - vec4 position; - vec3 normal; - vec2 uv; -}; - -#define MAX_LIGHTS 8 -#define NUM_SOLID_LIGHTS 3 - -struct LightSource { - vec4 position; - vec4 ambient; - vec4 diffuse; - vec4 specular; - vec4 spotDirection; -#ifdef SUPPORT_COLOR_MATERIAL - float constantAttenuation; - float linearAttenuation; - float quadraticAttenuation; - float spotCutoff; - float spotExponent; - float spotCosCutoff; - float pad, pad2; -#endif -}; - -layout(std140) uniform Lighting -{ - LightSource lightSource[MAX_LIGHTS]; - int num_enabled_lights; -}; - -uniform vec4 diffuse; -uniform vec4 specular; -uniform float shininess; - -uniform sampler2D texture_buffer; - -in block -{ - VertexData v; -} -inpt; - -void main() -{ -#ifdef WIREFRAME - gl_FragColor = diffuse; -#else - vec3 N = inpt.v.normal; - - if (!gl_FrontFacing) - N = -N; - - /* Compute diffuse and specular lighting. */ - vec3 L_diffuse = vec3(0.0); - vec3 L_specular = vec3(0.0); - -# ifdef USE_LIGHTING -# ifndef USE_COLOR_MATERIAL - /* Assume NUM_SOLID_LIGHTS directional lights. */ - for (int i = 0; i < NUM_SOLID_LIGHTS; i++) { - vec4 Plight = lightSource[i].position; -# ifdef USE_DIRECTIONAL_LIGHT - vec3 l = (Plight.w == 0.0) ? normalize(Plight.xyz) : normalize(inpt.v.position.xyz); -# else /* USE_DIRECTIONAL_LIGHT */ - /* TODO(sergey): We can normalize it outside of the shader. */ - vec3 l = normalize(Plight.xyz); -# endif /* USE_DIRECTIONAL_LIGHT */ - vec3 h = normalize(l + vec3(0, 0, 1)); - float d = max(0.0, dot(N, l)); - float s = pow(max(0.0, dot(N, h)), shininess); - L_diffuse += d * lightSource[i].diffuse.rgb; - L_specular += s * lightSource[i].specular.rgb; - } -# else /* USE_COLOR_MATERIAL */ - vec3 varying_position = inpt.v.position.xyz; - vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position) : vec3(0.0, 0.0, -1.0); - for (int i = 0; i < num_enabled_lights; i++) { - /* todo: this is a slow check for disabled lights */ - if (lightSource[i].specular.a == 0.0) - continue; - - float intensity = 1.0; - vec3 light_direction; - - if (lightSource[i].position.w == 0.0) { - /* directional light */ - light_direction = lightSource[i].position.xyz; - } - else { - /* point light */ - vec3 d = lightSource[i].position.xyz - varying_position; - light_direction = normalize(d); - - /* spot light cone */ - if (lightSource[i].spotCutoff < 90.0) { - float cosine = max(dot(light_direction, -lightSource[i].spotDirection.xyz), 0.0); - intensity = pow(cosine, lightSource[i].spotExponent); - intensity *= step(lightSource[i].spotCosCutoff, cosine); - } - - /* falloff */ - float distance = length(d); - - intensity /= lightSource[i].constantAttenuation + - lightSource[i].linearAttenuation * distance + - lightSource[i].quadraticAttenuation * distance * distance; - } - - /* diffuse light */ - vec3 light_diffuse = lightSource[i].diffuse.rgb; - float diffuse_bsdf = max(dot(N, light_direction), 0.0); - L_diffuse += light_diffuse * diffuse_bsdf * intensity; - - /* specular light */ - vec3 light_specular = lightSource[i].specular.rgb; - vec3 H = normalize(light_direction - V); - - float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess); - L_specular += light_specular * specular_bsdf * intensity; - } -# endif /* USE_COLOR_MATERIAL */ -# else /* USE_LIGHTING */ - L_diffuse = vec3(1.0); -# endif - - /* Compute diffuse color. */ -# ifdef USE_TEXTURE_2D - L_diffuse *= texture2D(texture_buffer, inpt.v.uv).rgb; -# else - L_diffuse *= diffuse.rgb; -# endif - - /* Sum lighting. */ - vec3 L = L_diffuse; - if (shininess != 0) { - L += L_specular * specular.rgb; - } - - /* Write out fragment color. */ - gl_FragColor = vec4(L, diffuse.a); -#endif -} diff --git a/intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl deleted file mode 100644 index 37bc0720113..00000000000 --- a/intern/opensubdiv/shader/gpu_shader_opensubdiv_geometry.glsl +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2014 Blender Foundation. - * All rights reserved. - */ - -struct VertexData { - vec4 position; - vec3 normal; - vec2 uv; -}; - -layout(lines_adjacency) in; -#ifdef WIREFRAME -layout(line_strip, max_vertices = 8) out; -#else -layout(triangle_strip, max_vertices = 4) out; -#endif - -uniform mat4 modelViewMatrix; -uniform mat4 projectionMatrix; -uniform int PrimitiveIdBase; -uniform int osd_fvar_count; -uniform int osd_active_uv_offset; - -in block -{ - VertexData v; -} -inpt[]; - -#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \ - { \ - vec2 v[4]; \ - int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \ - for (int i = 0; i < 4; ++i) { \ - int index = (primOffset + i) * osd_fvar_count + fvarOffset; \ - v[i] = vec2(texelFetch(FVarDataBuffer, index).s, texelFetch(FVarDataBuffer, index + 1).s); \ - } \ - result = mix(mix(v[0], v[1], tessCoord.s), mix(v[3], v[2], tessCoord.s), tessCoord.t); \ - } - -uniform samplerBuffer FVarDataBuffer; -uniform isamplerBuffer FVarDataOffsetBuffer; - -out block -{ - VertexData v; -} -outpt; - -#ifdef FLAT_SHADING -void emit(int index, vec3 normal) -{ - outpt.v.position = inpt[index].v.position; - outpt.v.normal = normal; - - /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); - vec2 st = quadst[index]; - - INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); - - gl_Position = projectionMatrix * inpt[index].v.position; - EmitVertex(); -} - -# ifdef WIREFRAME -void emit_edge(int v0, int v1, vec3 normal) -{ - emit(v0, normal); - emit(v1, normal); -} -# endif - -#else -void emit(int index) -{ - outpt.v.position = inpt[index].v.position; - outpt.v.normal = inpt[index].v.normal; - - /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); - vec2 st = quadst[index]; - - INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); - - gl_Position = projectionMatrix * inpt[index].v.position; - EmitVertex(); -} - -# ifdef WIREFRAME -void emit_edge(int v0, int v1) -{ - emit(v0); - emit(v1); -} -# endif - -#endif - -void main() -{ - gl_PrimitiveID = gl_PrimitiveIDIn; - -#ifdef FLAT_SHADING - vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz; - vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz; - vec3 flat_normal = normalize(cross(B, A)); -# ifndef WIREFRAME - emit(0, flat_normal); - emit(1, flat_normal); - emit(3, flat_normal); - emit(2, flat_normal); -# else - emit_edge(0, 1, flat_normal); - emit_edge(1, 2, flat_normal); - emit_edge(2, 3, flat_normal); - emit_edge(3, 0, flat_normal); -# endif -#else -# ifndef WIREFRAME - emit(0); - emit(1); - emit(3); - emit(2); -# else - emit_edge(0, 1); - emit_edge(1, 2); - emit_edge(2, 3); - emit_edge(3, 0); -# endif -#endif - - EndPrimitive(); -} diff --git a/intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl b/intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl deleted file mode 100644 index 474a716e927..00000000000 --- a/intern/opensubdiv/shader/gpu_shader_opensubdiv_vertex.glsl +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2014 Blender Foundation. - * All rights reserved. - */ - -struct VertexData { - vec4 position; - vec3 normal; - vec2 uv; -}; - -in vec3 normal; -in vec4 position; - -uniform mat4 modelViewMatrix; -uniform mat3 normalMatrix; - -out block -{ - VertexData v; -} -outpt; - -void main() -{ - outpt.v.position = modelViewMatrix * position; - outpt.v.normal = normalize(normalMatrix * normal); -} diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index aee532f1c2d..31d0eb8e923 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -31,8 +31,8 @@ #include "BLO_readfile.h" /* own include */ const UserDef U_default = { - .versionfile = BLENDER_VERSION, - .subversionfile = BLENDER_SUBVERSION, + .versionfile = BLENDER_FILE_VERSION, + .subversionfile = BLENDER_FILE_SUBVERSION, .flag = (USER_AUTOSAVE | USER_TOOLTIPS | USER_SAVE_PREVIEWS | USER_RELPATHS | USER_RELEASECONFIRM | USER_SCRIPT_AUTOEXEC_DISABLE | USER_NONEGFRAMES), .dupflag = USER_DUP_MESH | USER_DUP_CURVE | USER_DUP_SURF | USER_DUP_FONT | USER_DUP_MBALL | diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 540bc75cece..5b7f26ff89c 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -256,15 +256,15 @@ def world_to_camera_view(scene, obj, coord): z = -co_local.z camera = obj.data - frame = [-v for v in camera.view_frame(scene=scene)[:3]] + frame = [v for v in camera.view_frame(scene=scene)[:3]] if camera.type != 'ORTHO': if z == 0.0: return Vector((0.5, 0.5, 0.0)) else: - frame = [(v / (v.z / z)) for v in frame] + frame = [-(v / (v.z / z)) for v in frame] - min_x, max_x = frame[1].x, frame[2].x - min_y, max_y = frame[0].y, frame[1].y + min_x, max_x = frame[2].x, frame[1].x + min_y, max_y = frame[1].y, frame[0].y x = (co_local.x - min_x) / (max_x - min_x) y = (co_local.y - min_y) / (max_y - min_y) diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index a30f9d1dd1d..bf14d34ed20 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -25,12 +25,7 @@ StructRNA = bpy_types.bpy_struct StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop # StructRNA = bpy_types.Struct -bpy_types.BlendDataLibraries.load = _bpy._library_load -bpy_types.BlendDataLibraries.write = _bpy._library_write -bpy_types.BlendData.user_map = _bpy._rna_id_collection_user_map -bpy_types.BlendData.batch_remove = _bpy._rna_id_collection_batch_remove -bpy_types.BlendData.orphans_purge = _bpy._rna_id_collection_orphans_purge - +# Note that methods extended in C are defined in: 'bpy_rna_types_capi.c' class Context(StructRNA): __slots__ = () @@ -118,14 +113,19 @@ class Object(bpy_types.ID): @property def children(self): - """All the children of this object. Warning: takes O(len(bpy.data.objects)) time.""" + """All the children of this object. + + .. note:: Takes ``O(len(bpy.data.objects))`` time.""" import bpy return tuple(child for child in bpy.data.objects if child.parent == self) @property def users_collection(self): - """The collections this object is in. Warning: takes O(len(bpy.data.collections) + len(bpy.data.scenes)) time.""" + """ + The collections this object is in. + + .. note:: Takes ``O(len(bpy.data.collections) + len(bpy.data.scenes))`` time.""" import bpy return ( tuple( @@ -139,7 +139,9 @@ class Object(bpy_types.ID): @property def users_scene(self): - """The scenes this object is in. Warning: takes O(len(bpy.data.scenes) * len(bpy.data.objects)) time.""" + """The scenes this object is in. + + .. note:: Takes ``O(len(bpy.data.scenes) * len(bpy.data.objects))`` time.""" import bpy return tuple(scene for scene in bpy.data.scenes if self in scene.objects[:]) @@ -292,12 +294,16 @@ class _GenericBone: @property def children(self): - """A list of all the bones children. Warning: takes O(len(bones)) time.""" + """A list of all the bones children. + + .. note:: Takes ``O(len(bones))`` time.""" return [child for child in self._other_bones if child.parent == self] @property def children_recursive(self): - """A list of all children from this bone. Warning: takes O(len(bones)**2) time.""" + """A list of all children from this bone. + + .. note:: Takes ``O(len(bones)**2)`` time.""" bones_children = [] for bone in self._other_bones: index = bone.parent_index(self) @@ -314,7 +320,9 @@ class _GenericBone: Returns a chain of children with the same base name as this bone. Only direct chains are supported, forks caused by multiple children with matching base names will terminate the function - and not be returned. Warning: takes O(len(bones)**2) time. + and not be returned. + + .. note:: Takes ``O(len(bones)**2)`` time. """ basename = self.basename chain = [] @@ -1008,7 +1016,10 @@ class NodeSocket(StructRNA, metaclass=RNAMetaPropGroup): @property def links(self): - """List of node links from or to this socket. Warning: takes O(len(nodetree.links)) time.""" + """ + List of node links from or to this socket. + + .. note:: Takes ``O(len(nodetree.links))`` time.""" return tuple( link for link in self.id_data.links if (link.from_socket == self or diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py index 71d7ee5a7bc..964eff0e572 100644 --- a/release/scripts/modules/rna_info.py +++ b/release/scripts/modules/rna_info.py @@ -303,7 +303,9 @@ class InfoPropertyRNA: for dim in self.array_dimensions[::-1]: if dim != 0: self.default = tuple(zip(*((iter(self.default),) * dim))) - self.default_str = tuple("(%s)" % ", ".join(s for s in b) for b in zip(*((iter(self.default_str),) * dim))) + self.default_str = tuple( + "(%s)" % ", ".join(s for s in b) for b in zip(*((iter(self.default_str),) * dim)) + ) self.default_str = self.default_str[0] elif self.type == "enum" and self.is_enum_flag: self.default = getattr(rna_prop, "default_flag", set()) @@ -349,7 +351,9 @@ class InfoPropertyRNA: type_str += self.type if self.array_length: if self.array_dimensions[1] != 0: - type_str += " multi-dimensional array of %s items" % (" * ".join(str(d) for d in self.array_dimensions if d != 0)) + type_str += " multi-dimensional array of %s items" % ( + " * ".join(str(d) for d in self.array_dimensions if d != 0) + ) else: type_str += " array of %d items" % (self.array_length) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 614a76c3994..2559a2f1df5 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4945,6 +4945,32 @@ def km_transform_modal_map(_params): return keymap +def km_view3d_interactive_add_tool_modal_map(_params): + items = [] + keymap = ( + "View3D Placement Modal Map", + {"space_type": 'EMPTY', "region_type": 'WINDOW', "modal": True}, + {"items": items}, + ) + + items.extend([ + ("PIVOT_CENTER_ON", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None), + ("PIVOT_CENTER_OFF", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None), + ("PIVOT_CENTER_ON", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None), + ("PIVOT_CENTER_OFF", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None), + ("FIXED_ASPECT_ON", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None), + ("FIXED_ASPECT_OFF", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None), + ("FIXED_ASPECT_ON", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None), + ("FIXED_ASPECT_OFF", {"type": 'RIGHT_SHIFT', "value": 'RELEASE', "any": True}, None), + ("SNAP_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None), + ("SNAP_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None), + ("SNAP_ON", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": True}, None), + ("SNAP_OFF", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": True}, None), + ]) + + return keymap + + def km_view3d_gesture_circle(_params): items = [] keymap = ( @@ -5855,13 +5881,13 @@ def km_3d_view_tool_edit_armature_extrude_to_cursor(params): ) -def km_3d_view_tool_edit_mesh_add_cube(params): +def km_3d_view_tool_interactive_add(params): return ( - "3D View Tool: Edit Mesh, Add Cube", + "3D View Tool: Object, Add Primitive", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("view3d.cursor3d", {"type": params.tool_mouse, "value": 'CLICK'}, None), - ("mesh.primitive_cube_add_gizmo", {"type": params.tool_tweak, "value": 'ANY'}, None), + ("view3d.interactive_add", {"type": params.tool_tweak, "value": 'ANY', "any": True}, + {"properties": [("wait_for_input", False)]}), ]}, ) @@ -6674,6 +6700,7 @@ def generate_keymaps(params=None): km_eyedropper_modal_map(params), km_eyedropper_colorramp_pointsampling_map(params), km_transform_modal_map(params), + km_view3d_interactive_add_tool_modal_map(params), km_view3d_gesture_circle(params), km_gesture_border(params), km_gesture_zoom_border(params), @@ -6733,6 +6760,7 @@ def generate_keymaps(params=None): km_3d_view_tool_scale(params), km_3d_view_tool_shear(params), km_3d_view_tool_measure(params), + km_3d_view_tool_interactive_add(params), km_3d_view_tool_pose_breakdowner(params), km_3d_view_tool_pose_push(params), km_3d_view_tool_pose_relax(params), @@ -6741,7 +6769,6 @@ def generate_keymaps(params=None): km_3d_view_tool_edit_armature_bone_envelope(params), km_3d_view_tool_edit_armature_extrude(params), km_3d_view_tool_edit_armature_extrude_to_cursor(params), - km_3d_view_tool_edit_mesh_add_cube(params), km_3d_view_tool_edit_mesh_extrude_region(params), km_3d_view_tool_edit_mesh_extrude_dissolve_and_intersect(params), km_3d_view_tool_edit_mesh_extrude_along_normals(params), diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index 842a12ed249..3698db4cf94 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -3768,6 +3768,8 @@ def km_object_non_modal(params): ) items.extend([ + ("object.mode_set",{"type": 'ONE', "value": 'PRESS'}, + {"properties": [("mode", 'PAINT_GPENCIL')]}), ("object.mode_set",{"type": 'THREE', "value": 'PRESS'}, {"properties": [("mode", 'POSE')]}), ("object.mode_set_with_submode",{"type": 'ONE', "value": 'PRESS'}, @@ -3790,11 +3792,11 @@ def km_object_non_modal(params): {"properties": [("mode", 'TEXTURE_PAINT')]}), ("object.mode_set",{"type": 'TWO', "value": 'PRESS'}, {"properties": [("mode", 'EDIT_GPENCIL')]}), - ("object.mode_set",{"type": 'THREE', "value": 'PRESS'}, - {"properties": [("mode", 'SCULPT_GPENCIL')]}), - ("object.mode_set",{"type": 'FOUR', "value": 'PRESS'}, - {"properties": [("mode", 'PAINT_GPENCIL')]}), ("object.mode_set",{"type": 'FIVE', "value": 'PRESS'}, + {"properties": [("mode", 'SCULPT_GPENCIL')]}), + ("object.mode_set",{"type": 'SIX', "value": 'PRESS'}, + {"properties": [("mode", 'VERTEX_GPENCIL')]}), + ("object.mode_set",{"type": 'SEVEN', "value": 'PRESS'}, {"properties": [("mode", 'WEIGHT_GPENCIL')]}), ]) diff --git a/release/scripts/presets/tracking_camera/1__colon__2.3_inch.py b/release/scripts/presets/tracking_camera/1__colon__2.3_inch.py index 218e51a53a6..9fcd40fbb65 100644 --- a/release/scripts/presets/tracking_camera/1__colon__2.3_inch.py +++ b/release/scripts/presets/tracking_camera/1__colon__2.3_inch.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/1__colon__2.5_inch.py b/release/scripts/presets/tracking_camera/1__colon__2.5_inch.py index 0f16dc9b503..2f064e59838 100644 --- a/release/scripts/presets/tracking_camera/1__colon__2.5_inch.py +++ b/release/scripts/presets/tracking_camera/1__colon__2.5_inch.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/2__colon__3_inch.py b/release/scripts/presets/tracking_camera/2__colon__3_inch.py index 079d0c6308f..8936e627d77 100644 --- a/release/scripts/presets/tracking_camera/2__colon__3_inch.py +++ b/release/scripts/presets/tracking_camera/2__colon__3_inch.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/4__colon__3_inch.py b/release/scripts/presets/tracking_camera/4__colon__3_inch.py index 0d3313ab755..2317715e1b4 100644 --- a/release/scripts/presets/tracking_camera/4__colon__3_inch.py +++ b/release/scripts/presets/tracking_camera/4__colon__3_inch.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Arri_Alexa.py b/release/scripts/presets/tracking_camera/Arri_Alexa.py index 7144f9a03aa..ded361ec965 100644 --- a/release/scripts/presets/tracking_camera/Arri_Alexa.py +++ b/release/scripts/presets/tracking_camera/Arri_Alexa.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Canon_1100D.py b/release/scripts/presets/tracking_camera/Canon_1100D.py index dc09e3d0896..96d6d456337 100644 --- a/release/scripts/presets/tracking_camera/Canon_1100D.py +++ b/release/scripts/presets/tracking_camera/Canon_1100D.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Canon_APS-C.py b/release/scripts/presets/tracking_camera/Canon_APS-C.py index c55716a06a8..cc4da545272 100644 --- a/release/scripts/presets/tracking_camera/Canon_APS-C.py +++ b/release/scripts/presets/tracking_camera/Canon_APS-C.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Canon_APS-H.py b/release/scripts/presets/tracking_camera/Canon_APS-H.py index 0b757edef20..853edd5dcba 100644 --- a/release/scripts/presets/tracking_camera/Canon_APS-H.py +++ b/release/scripts/presets/tracking_camera/Canon_APS-H.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Canon_C300.py b/release/scripts/presets/tracking_camera/Canon_C300.py index 24fbbc78ff7..809f8f432f8 100644 --- a/release/scripts/presets/tracking_camera/Canon_C300.py +++ b/release/scripts/presets/tracking_camera/Canon_C300.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Full_Frame_35mm_Camera.py b/release/scripts/presets/tracking_camera/Full_Frame_35mm_Camera.py index 478e53584fb..0f3da0b4d72 100644 --- a/release/scripts/presets/tracking_camera/Full_Frame_35mm_Camera.py +++ b/release/scripts/presets/tracking_camera/Full_Frame_35mm_Camera.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/GoPro_Hero3_Black.py b/release/scripts/presets/tracking_camera/GoPro_Hero3_Black.py index 47e026e9d00..29851352284 100644 --- a/release/scripts/presets/tracking_camera/GoPro_Hero3_Black.py +++ b/release/scripts/presets/tracking_camera/GoPro_Hero3_Black.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/GoPro_Hero3_Silver.py b/release/scripts/presets/tracking_camera/GoPro_Hero3_Silver.py index 10ca885769a..9e08cf283a7 100644 --- a/release/scripts/presets/tracking_camera/GoPro_Hero3_Silver.py +++ b/release/scripts/presets/tracking_camera/GoPro_Hero3_Silver.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/GoPro_Hero3_White.py b/release/scripts/presets/tracking_camera/GoPro_Hero3_White.py index c9bda2258c8..6b1f9d97e81 100644 --- a/release/scripts/presets/tracking_camera/GoPro_Hero3_White.py +++ b/release/scripts/presets/tracking_camera/GoPro_Hero3_White.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Nexus_5.py b/release/scripts/presets/tracking_camera/Nexus_5.py index 68ec347d3e1..172c8e93bfd 100644 --- a/release/scripts/presets/tracking_camera/Nexus_5.py +++ b/release/scripts/presets/tracking_camera/Nexus_5.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Samsung_Galaxy_S3.py b/release/scripts/presets/tracking_camera/Samsung_Galaxy_S3.py index 6dbdaefbd2f..d10994e45f5 100644 --- a/release/scripts/presets/tracking_camera/Samsung_Galaxy_S3.py +++ b/release/scripts/presets/tracking_camera/Samsung_Galaxy_S3.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Samsung_Galaxy_S4.py b/release/scripts/presets/tracking_camera/Samsung_Galaxy_S4.py index 051cdf64402..c5fef80b3de 100644 --- a/release/scripts/presets/tracking_camera/Samsung_Galaxy_S4.py +++ b/release/scripts/presets/tracking_camera/Samsung_Galaxy_S4.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Super_16.py b/release/scripts/presets/tracking_camera/Super_16.py index f1a8bb37328..e94da9a99ba 100644 --- a/release/scripts/presets/tracking_camera/Super_16.py +++ b/release/scripts/presets/tracking_camera/Super_16.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/Super_35.py b/release/scripts/presets/tracking_camera/Super_35.py index f533d3e4bcf..e07edc3a22c 100644 --- a/release/scripts/presets/tracking_camera/Super_35.py +++ b/release/scripts/presets/tracking_camera/Super_35.py @@ -7,4 +7,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/iPhone_4.py b/release/scripts/presets/tracking_camera/iPhone_4.py index b0ac49706b3..220e5e08147 100644 --- a/release/scripts/presets/tracking_camera/iPhone_4.py +++ b/release/scripts/presets/tracking_camera/iPhone_4.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/iPhone_4S.py b/release/scripts/presets/tracking_camera/iPhone_4S.py index 2569f9b412b..686cffc8f99 100644 --- a/release/scripts/presets/tracking_camera/iPhone_4S.py +++ b/release/scripts/presets/tracking_camera/iPhone_4S.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/presets/tracking_camera/iPhone_5.py b/release/scripts/presets/tracking_camera/iPhone_5.py index f7944e3fa63..d8e05da8425 100644 --- a/release/scripts/presets/tracking_camera/iPhone_5.py +++ b/release/scripts/presets/tracking_camera/iPhone_5.py @@ -8,4 +8,3 @@ camera.pixel_aspect = 1 camera.k1 = 0.0 camera.k2 = 0.0 camera.k3 = 0.0 - diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index 83d451fbc89..6f441238606 100644 --- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py +++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py @@ -18,9 +18,6 @@ # <pep8 compliant> -# for full docs see... -# https://docs.blender.org/manual/en/latest/editors/uv_image/uv/editing/unwrapping/mapping_types.html#follow-active-quads - import bpy from bpy.types import Operator diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index b54ae67a9c5..633118c3b2e 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1106,8 +1106,8 @@ class WM_OT_doc_view(Operator): doc_id: doc_id if bpy.app.version_cycle in {"release", "rc", "beta"}: - _prefix = ("https://docs.blender.org/api/%d.%d%s" % - (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)) + _prefix = ("https://docs.blender.org/api/%d.%d" % + (bpy.app.version[0], bpy.app.version[1])) else: _prefix = ("https://docs.blender.org/api/master") diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py index aca358870c8..ff4425fbb73 100644 --- a/release/scripts/startup/bl_ui/properties_data_bone.py +++ b/release/scripts/startup/bl_ui/properties_data_bone.py @@ -267,7 +267,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel): if bone: col = layout.column() - col.prop(bone, "hide", text="Hide") + col.prop(bone, "hide", text="Hide", toggle=0) class BONE_PT_display_custom_shape(BoneButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 75e9a320130..d58dec211be 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -1437,6 +1437,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.falloff_type == 'CURVE': layout.template_curve_mapping(md, "map_curve") + row = layout.row(align=True) + row.prop(md, "normalize") + # Common mask options layout.separator() self.vertex_weight_mask(layout, ob, md) @@ -1446,7 +1449,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.label(text="Vertex Group A:") - col.prop_search(md, "vertex_group_a", ob, "vertex_groups", text="") + row = col.row(align=True) + row.prop_search(md, "vertex_group_a", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex_group_a", text="", icon='ARROW_LEFTRIGHT') col.label(text="Default Weight A:") col.prop(md, "default_weight_a", text="") @@ -1455,13 +1460,18 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.label(text="Vertex Group B:") - col.prop_search(md, "vertex_group_b", ob, "vertex_groups", text="") + row = col.row(align=True) + row.prop_search(md, "vertex_group_b", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex_group_b", text="", icon='ARROW_LEFTRIGHT') col.label(text="Default Weight B:") col.prop(md, "default_weight_b", text="") col.label(text="Mix Set:") col.prop(md, "mix_set", text="") + row = layout.row(align=True) + row.prop(md, "normalize") + # Common mask options layout.separator() self.vertex_weight_mask(layout, ob, md) @@ -1495,6 +1505,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): row.prop(md, "falloff_type") row.prop(md, "invert_falloff", text="", icon='ARROW_LEFTRIGHT') + row = layout.row(align=True) + row.prop(md, "normalize") + # Common mask options layout.separator() self.vertex_weight_mask(layout, ob, md) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 64eda42c87a..07c9fc363b5 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -612,7 +612,7 @@ class GreasePencilMaterialsPanel: if is_view3d and brush is not None: gp_settings = brush.gpencil_settings if gp_settings.use_material_pin is False: - if ob.active_material_index >= 0: + if len(ob.material_slots) > 0 and ob.active_material_index >= 0: ma = ob.material_slots[ob.active_material_index].material else: ma = gp_settings.material diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 92d421f63a8..5fadb31c83f 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -125,7 +125,7 @@ class UnifiedPaintPanel: if unified_name and not header: # NOTE: We don't draw UnifiedPaintSettings in the header to reduce clutter. D5928#136281 - row.prop(ups, unified_name, text="", icon="BRUSHES_ALL") + row.prop(ups, unified_name, text="", icon='BRUSHES_ALL') return row @@ -619,10 +619,12 @@ def brush_settings(layout, context, brush, popover=False): if brush.sculpt_tool == 'POSE': layout.separator() + layout.prop(brush, "pose_deform_type") layout.prop(brush, "pose_origin_type") layout.prop(brush, "pose_offset") layout.prop(brush, "pose_smooth_iterations") - layout.prop(brush, "pose_ik_segments") + if brush.pose_deform_type == 'ROTATE_TWIST': + layout.prop(brush, "pose_ik_segments") layout.prop(brush, "use_pose_ik_anchored") layout.separator() diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index 4b0791a63e6..2c8ed363738 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -237,7 +237,7 @@ class PHYSICS_PT_settings(PhysicButtonsPanel, Panel): col = grid.column() col.prop(flow, "flow_behavior", expand=False) if flow.flow_behavior in {'INFLOW', 'OUTFLOW'}: - col.prop(flow, "use_inflow", text="Use Flow") + col.prop(flow, "use_inflow") col.prop(flow, "subframes", text="Sampling Substeps") diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index dd7bf54dc68..b03f80bd600 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -79,14 +79,12 @@ class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel): rigid_body_warning(layout) return - flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - col = flow.column() + col = layout.column() if rbo.type == 'ACTIVE': col.prop(rbo, "mass") col.prop(rbo, "enabled", text="Dynamic") - col = flow.column() col.prop(rbo, "kinematic", text="Animated") diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index c5c75f95937..ad7dc2a586c 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -554,7 +554,6 @@ class RENDER_PT_gpencil(RenderButtonsPanel, Panel): col.prop(props, "antialias_threshold") - class RENDER_PT_opengl_sampling(RenderButtonsPanel, Panel): bl_label = "Sampling" COMPAT_ENGINES = {'BLENDER_WORKBENCH'} diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index bc4665209aa..76b7fc7f156 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -93,9 +93,6 @@ class IMAGE_MT_view(Menu): layout.separator() layout.prop(sima, "use_realtime_update") - if show_uvedit: - layout.prop(tool_settings, "show_uv_local_view") - layout.prop(uv, "show_metadata") if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'): diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index ca25c29960c..41c220f7ee4 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -307,12 +307,15 @@ class SEQUENCER_MT_view(Menu): layout.separator() layout.operator_context = 'INVOKE_DEFAULT' - layout.prop(st, "show_seconds") layout.prop(st, "show_locked_time") + + layout.separator() + layout.prop(st, "show_seconds") layout.prop(st, "show_strip_offset") layout.prop(st, "show_fcurves") - layout.separator() layout.prop(st, "show_markers") + layout.menu("SEQUENCER_MT_view_cache", text="Show Cache") + layout.prop_menu_enum(st, "waveform_display_type", text="Show Waveforms") if is_preview: layout.separator() @@ -324,12 +327,6 @@ class SEQUENCER_MT_view(Menu): elif st.display_mode == 'WAVEFORM': layout.prop(st, "show_separate_color", text="Show Separate Color Channels") - if is_sequencer_view: - layout.separator() - - layout.menu("SEQUENCER_MT_view_cache") - layout.prop_menu_enum(st, "waveform_display_type") - layout.separator() layout.operator("render.opengl", text="Sequence Render Image", icon='RENDER_STILL').sequencer = True @@ -338,7 +335,7 @@ class SEQUENCER_MT_view(Menu): props.sequencer = True layout.separator() - layout.operator("sequencer.export_subtitles", text="Export Subtitles", icon="EXPORT") + layout.operator("sequencer.export_subtitles", text="Export Subtitles", icon='EXPORT') layout.separator() @@ -1033,10 +1030,14 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): if strip.input_count > 0: col = layout.column() - col.enabled = False - col.prop(strip, "input_1") + row = col.row() + row.prop(strip, "input_1") + if strip.input_count > 1: - col.prop(strip, "input_2") + row.operator("sequencer.swap_inputs", text="", icon='SORT_ASC') + row = col.row() + row.prop(strip, "input_2") + row.operator("sequencer.swap_inputs", text="", icon='SORT_DESC') strip_type = strip.type @@ -1195,31 +1196,14 @@ class SEQUENCER_PT_effect_text_style(SequencerButtonsPanel, Panel): col.prop(strip, "font_size") col.prop(strip, "color") - -class SEQUENCER_PT_effect_text_style_shadow(SequencerButtonsPanel, Panel): - bl_label = "Shadow" - bl_parent_id = "SEQUENCER_PT_effect_text_style" - bl_options = {'DEFAULT_CLOSED'} - bl_category = "Strip" - - @classmethod - def poll(cls, context): - strip = act_strip(context) - return strip.type != 'SOUND' - - def draw_header(self, context): - strip = act_strip(context) - self.layout.prop(strip, "use_shadow", text="") - - def draw(self, context): - strip = act_strip(context) - layout = self.layout - layout.use_property_split = True - - layout.active = strip.use_shadow and (not strip.mute) - - col = layout.column(align=True) - col.prop(strip, "shadow_color", text="Color") + row = layout.row(align=True, heading="Shadow") + row.use_property_decorate = False + sub = row.row(align=True) + sub.prop(strip, "use_shadow", text="") + subsub = sub.row(align=True) + subsub.active = strip.use_shadow and (not strip.mute) + subsub.prop(strip, "shadow_color", text="") + row.prop_decorator(strip, "shadow_color") class SEQUENCER_PT_source(SequencerButtonsPanel, Panel): @@ -1931,7 +1915,7 @@ class SEQUENCER_PT_strip_cache(SequencerButtonsPanel, Panel): class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel): - bl_label = "Scene Preview/Render" + bl_label = "Scene Strip Display" bl_space_type = 'SEQUENCE_EDITOR' bl_region_type = 'UI' bl_options = {'DEFAULT_CLOSED'} @@ -1945,7 +1929,7 @@ class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel): render = context.scene.render col = layout.column() - col.prop(render, "sequencer_gl_preview", text="Preview Shading") + col.prop(render, "sequencer_gl_preview", text="Shading") if render.sequencer_gl_preview in {'SOLID', 'WIREFRAME'}: col.prop(render, "use_sequencer_override_scene_strip") @@ -2232,10 +2216,16 @@ classes = ( SEQUENCER_MT_strip_input, SEQUENCER_MT_strip_lock_mute, SEQUENCER_MT_context_menu, + SEQUENCER_PT_active_tool, SEQUENCER_PT_strip, SEQUENCER_PT_effect, + SEQUENCER_PT_scene, + SEQUENCER_PT_mask, + SEQUENCER_PT_effect_text_style, + SEQUENCER_PT_effect_text_layout, + SEQUENCER_PT_adjust, SEQUENCER_PT_adjust_comp, SEQUENCER_PT_adjust_transform, @@ -2245,12 +2235,6 @@ classes = ( SEQUENCER_PT_adjust_color, SEQUENCER_PT_adjust_sound, - SEQUENCER_PT_scene, - SEQUENCER_PT_mask, - SEQUENCER_PT_effect_text_style, - SEQUENCER_PT_effect_text_layout, - SEQUENCER_PT_effect_text_style_shadow, - SEQUENCER_PT_time, SEQUENCER_PT_source, @@ -2263,11 +2247,11 @@ classes = ( SEQUENCER_PT_custom_props, - SEQUENCER_PT_preview, SEQUENCER_PT_view, SEQUENCER_PT_frame_overlay, SEQUENCER_PT_view_safe_areas, SEQUENCER_PT_view_safe_areas_center_cut, + SEQUENCER_PT_preview, SEQUENCER_PT_annotation, SEQUENCER_PT_annotation_onion, diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index e64a7c9731b..1aa5dde168b 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -137,7 +137,6 @@ class _defs_view3d_generic: idname="builtin.measure", label="Measure", description=description, - cursor='CROSSHAIR', icon="ops.view3d.ruler", widget="VIEW3D_GGT_ruler", keymap="3D View Tool: Measure", @@ -407,7 +406,6 @@ class _defs_view3d_select: label="Select Lasso", icon="ops.generic.select_lasso", widget=None, - cursor='DEFAULT', keymap="3D View Tool: Select Lasso", draw_settings=draw_settings, ) @@ -432,17 +430,130 @@ class _defs_view3d_select: label="Select Circle", icon="ops.generic.select_circle", widget=None, - cursor='DEFAULT', keymap="3D View Tool: Select Circle", draw_settings=draw_settings, draw_cursor=draw_cursor, ) +class _defs_view3d_add: + + # Layout tweaks here would be good to avoid, + # this shows limits in layout engine, as buttons are using a lot of space. + @staticmethod + def draw_settings_interactive_add(layout, tool): + props = tool.operator_properties("view3d.interactive_add") + row = layout.row() + row.scale_x = 0.8 + row.label(text="Depth:") + row = layout.row() + row.scale_x = 0.9 + row.prop(props, "plane_depth", text="") + row = layout.row() + row.prop(props, "plane_axis", text="") + row = layout.row() + row.scale_x = 0.7 + row.prop(props, "plane_origin") + + @ToolDef.from_fn + def cube_add(): + def draw_settings(_context, layout, tool): + _defs_view3d_add.draw_settings_interactive_add(layout, tool) + return dict( + idname="builtin.primitive_cube_add", + label="Add Cube", + icon="ops.mesh.primitive_cube_add_gizmo", + description=( + "Add cube to mesh interactively" + ), + widget="VIEW3D_GGT_placement", + keymap="3D View Tool: Object, Add Primitive", + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def cone_add(): + def draw_settings(_context, layout, tool): + _defs_view3d_add.draw_settings_interactive_add(layout, tool) + + props = tool.operator_properties("mesh.primitive_cone_add") + layout.prop(props, "vertices") + layout.prop(props, "end_fill_type") + return dict( + idname="builtin.primitive_cone_add", + label="Add Cone", + icon="ops.mesh.primitive_cube_add_gizmo", + description=( + "Add cone to mesh interactively" + ), + widget="VIEW3D_GGT_placement", + keymap="3D View Tool: Object, Add Primitive", + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def cylinder_add(): + def draw_settings(_context, layout, tool): + _defs_view3d_add.draw_settings_interactive_add(layout, tool) + + props = tool.operator_properties("mesh.primitive_cylinder_add") + layout.prop(props, "vertices") + layout.prop(props, "end_fill_type") + return dict( + idname="builtin.primitive_cylinder_add", + label="Add Cylinder", + icon="ops.mesh.primitive_cylinder_add_gizmo", + description=( + "Add cylinder to mesh interactively" + ), + widget="VIEW3D_GGT_placement", + keymap="3D View Tool: Object, Add Primitive", + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def uv_sphere_add(): + def draw_settings(_context, layout, tool): + _defs_view3d_add.draw_settings_interactive_add(layout, tool) + + props = tool.operator_properties("mesh.primitive_uv_sphere_add") + layout.prop(props, "segments") + layout.prop(props, "ring_count") + return dict( + idname="builtin.primitive_uv_sphere_add", + label="Add UV Sphere", + icon="ops.mesh.primitive_sphere_add_gizmo", + description=( + "Add cylinder to mesh interactively" + ), + widget="VIEW3D_GGT_placement", + keymap="3D View Tool: Object, Add Primitive", + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def ico_sphere_add(): + def draw_settings(_context, layout, tool): + _defs_view3d_add.draw_settings_interactive_add(layout, tool) + + props = tool.operator_properties("mesh.primitive_ico_sphere_add") + layout.prop(props, "subdivisions") + return dict( + idname="builtin.primitive_ico_sphere_add", + label="Add Ico Sphere", + icon="ops.mesh.primitive_sphere_add_gizmo", + description=( + "Add cylinder to mesh interactively" + ), + widget="VIEW3D_GGT_placement", + keymap="3D View Tool: Object, Add Primitive", + draw_settings=draw_settings, + ) + + # ----------------------------------------------------------------------------- # Object Modes (named based on context.mode) - class _defs_edit_armature: @ToolDef.from_fn @@ -501,19 +612,6 @@ class _defs_edit_armature: class _defs_edit_mesh: @ToolDef.from_fn - def cube_add(): - return dict( - idname="builtin.add_cube", - label="Add Cube", - icon="ops.mesh.primitive_cube_add_gizmo", - description=( - "Add cube to mesh interactively" - ), - widget=None, - keymap=(), - ) - - @ToolDef.from_fn def rip_region(): def draw_settings(_context, layout, tool): props = tool.operator_properties("mesh.rip_move") @@ -2150,6 +2248,14 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ), ) + _tools_view3d_add = ( + _defs_view3d_add.cube_add, + _defs_view3d_add.cone_add, + _defs_view3d_add.cylinder_add, + _defs_view3d_add.uv_sphere_add, + _defs_view3d_add.ico_sphere_add, + ) + _tools_default = ( *_tools_select, _defs_view3d_generic.cursor, @@ -2168,6 +2274,9 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ], 'OBJECT': [ *_tools_default, + + None, + _tools_view3d_add, ], 'POSE': [ *_tools_default, @@ -2196,6 +2305,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): 'EDIT_MESH': [ *_tools_default, None, + _tools_view3d_add, + None, ( _defs_edit_mesh.extrude, _defs_edit_mesh.extrude_dissolve_and_intersect, diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 9aedd7ef0b3..6fc29119cdc 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -309,16 +309,18 @@ class TOPBAR_MT_file_new(Menu): template_paths = bpy.utils.app_template_paths() - # expand template paths - app_templates = [] + # Expand template paths. + + # Use a set to avoid duplicate user/system templates. + # This is a corner case, but users managed to do it! T76849. + app_templates = set() for path in template_paths: for d in os.listdir(path): if d.startswith(("__", ".")): continue template = os.path.join(path, d) if os.path.isdir(template): - # template_paths_expand.append(template) - app_templates.append(d) + app_templates.add(d) return sorted(app_templates) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 153533dbde6..63fc44aed38 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -222,7 +222,7 @@ class USERPREF_PT_interface_text(InterfacePanel, CenterAlignMixIn, Panel): flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) - flow.prop(view, "use_text_antialiasing", text="Anti-aliasing") + flow.prop(view, "use_text_antialiasing", text="Anti-Aliasing") sub = flow.column() sub.active = view.use_text_antialiasing sub.prop(view, "text_hinting", text="Hinting") @@ -1080,7 +1080,7 @@ class PreferenceThemeSpacePanel: PreferenceThemeSpacePanel._theme_generic(layout, data, self.theme_area) -class ThemeGenericClassGenerator(): +class ThemeGenericClassGenerator: @staticmethod def generate_panel_classes_for_wcols(): @@ -1436,16 +1436,7 @@ class USERPREF_PT_input_ndof(InputPanel, CenterAlignMixIn, Panel): prefs = context.preferences inputs = prefs.inputs - flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) - - flow.prop(inputs, "ndof_sensitivity", text="Pan Sensitivity") - flow.prop(inputs, "ndof_orbit_sensitivity", text="Orbit Sensitivity") - flow.prop(inputs, "ndof_deadzone", text="Deadzone") - - layout.separator() - - flow.row().prop(inputs, "ndof_view_navigate_method", expand=True) - flow.row().prop(inputs, "ndof_view_rotate_method", expand=True) + USERPREF_PT_ndof_settings.draw_settings(layout, inputs) # ----------------------------------------------------------------------------- @@ -1584,71 +1575,64 @@ class USERPREF_PT_ndof_settings(Panel): bl_label = "3D Mouse Settings" bl_space_type = 'TOPBAR' # dummy. bl_region_type = 'HEADER' + bl_ui_units_x = 12 - def draw(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False # No animation. - - input_prefs = context.preferences.inputs - - is_view3d = context.space_data.type == 'VIEW_3D' + @staticmethod + def draw_settings(layout, props, show_3dview_settings=True): + col = layout.column() + col.prop(props, "ndof_sensitivity", text="Pan Sensitivity") + col.prop(props, "ndof_orbit_sensitivity") + col.prop(props, "ndof_deadzone") - col = layout.column(align=True) - col.prop(input_prefs, "ndof_sensitivity") - col.prop(input_prefs, "ndof_orbit_sensitivity") - col.prop(input_prefs, "ndof_deadzone") + layout.separator() - if is_view3d: - layout.separator() - layout.prop(input_prefs, "ndof_show_guide") + if show_3dview_settings: + col = layout.column() + col.row().prop(props, "ndof_view_navigate_method", expand=True, text="Navigation") + col.row().prop(props, "ndof_view_rotate_method", expand=True, text="Rotation") layout.separator() - layout.label(text="Orbit Style") - layout.row().prop(input_prefs, "ndof_view_navigate_method", text="Navigate") - layout.row().prop(input_prefs, "ndof_view_rotate_method", text="Orbit") - layout.separator() - layout.label(text="Orbit Options") - split = layout.split(factor=0.6) - row = split.row() - row.alignment = 'RIGHT' - row.label(text="Invert Axis") - row = split.row(align=True) - for text, attr in ( - ("X", "ndof_rotx_invert_axis"), - ("Y", "ndof_roty_invert_axis"), - ("Z", "ndof_rotz_invert_axis"), - ): - row.prop(input_prefs, attr, text=text, toggle=True) + col = layout.column() + if show_3dview_settings: + col.prop(props, "ndof_show_guide") + col.prop(props, "ndof_zoom_invert") + row = col.row(heading="Pan") + row.prop(props, "ndof_pan_yz_swap_axis", text="Swap Y and Z Axes") - # view2d use pan/zoom layout.separator() - layout.label(text="Pan Options") - split = layout.split(factor=0.6) - row = split.row() - row.alignment = 'RIGHT' - row.label(text="Invert Axis") - row = split.row(align=True) + row = layout.row(heading=("Invert Axis Pan" if show_3dview_settings else "Invert Pan Axis")) for text, attr in ( ("X", "ndof_panx_invert_axis"), ("Y", "ndof_pany_invert_axis"), ("Z", "ndof_panz_invert_axis"), ): - row.prop(input_prefs, attr, text=text, toggle=True) - - layout.prop(input_prefs, "ndof_pan_yz_swap_axis") + row.prop(props, attr, text=text, toggle=True) - layout.label(text="Zoom Options") - layout.prop(input_prefs, "ndof_zoom_invert") + if show_3dview_settings: + row = layout.row(heading="Orbit") + for text, attr in ( + ("X", "ndof_rotx_invert_axis"), + ("Y", "ndof_roty_invert_axis"), + ("Z", "ndof_rotz_invert_axis"), + ): + row.prop(props, attr, text=text, toggle=True) - if is_view3d: layout.separator() - layout.label(text="Fly/Walk Options") - layout.prop(input_prefs, "ndof_fly_helicopter") - layout.prop(input_prefs, "ndof_lock_horizon") + col = layout.column(heading="Fly/Walk") + col.prop(props, "ndof_lock_horizon") + col.prop(props, "ndof_fly_helicopter") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + input_prefs = context.preferences.inputs + is_view3d = context.space_data.type == 'VIEW_3D' + self.draw_settings(layout, input_prefs, is_view3d) # ----------------------------------------------------------------------------- # Key-Map Editor Panels diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 61d5d79473f..6dc21669f32 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -431,7 +431,7 @@ class _draw_tool_settings_context_mode: row.prop(gp_settings, "use_material_pin", text="") - if brush.gpencil_tool in {'DRAW', 'FILL'} and ma: + if brush.gpencil_tool in {'DRAW', 'FILL'}: row.separator(factor=1.0) subrow = row.row(align=True) row.prop_enum(settings, "color_mode", 'MATERIAL', text="", icon='MATERIAL') @@ -736,7 +736,12 @@ class VIEW3D_HT_header(Header): row.prop(tool_settings, "use_gpencil_vertex_select_mask_stroke", text="") row.prop(tool_settings, "use_gpencil_vertex_select_mask_segment", text="") - if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode or gpd.is_stroke_vertex_mode: + if ( + gpd.use_stroke_edit_mode or + gpd.is_stroke_sculpt_mode or + gpd.is_stroke_weight_mode or + gpd.is_stroke_vertex_mode + ): row = layout.row(align=True) row.prop(gpd, "use_multiedit", text="", icon='GP_MULTIFRAME_EDITING') @@ -3183,7 +3188,6 @@ class VIEW3D_MT_face_sets_init(Menu): op.mode = 'FACE_MAPS' - class VIEW3D_MT_particle(Menu): bl_label = "Particle" @@ -3762,6 +3766,11 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu): col.separator() + col.operator("mesh.mark_seam").clear = False + col.operator("mesh.mark_seam", text="Clear Seam").clear = True + + col.separator() + col.operator("mesh.mark_sharp") col.operator("mesh.mark_sharp", text="Clear Sharp").clear = True @@ -4006,6 +4015,11 @@ class VIEW3D_MT_edit_mesh_edges(Menu): layout.separator() + layout.operator("mesh.mark_seam").clear = False + layout.operator("mesh.mark_seam", text="Clear Seam").clear = True + + layout.separator() + layout.operator("mesh.mark_sharp") layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True @@ -5269,6 +5283,7 @@ class VIEW3D_MT_sculpt_mask_edit_pie(Menu): op.mode = 'INVERT' op = pie.operator("paint.mask_flood_fill", text='Clear Mask') op.mode = 'VALUE' + op.value = 0.0 op = pie.operator("sculpt.mask_filter", text='Smooth Mask') op.filter_type = 'SMOOTH' op.auto_iteration_count = True @@ -6368,7 +6383,7 @@ class VIEW3D_PT_overlay_edit_curve(Panel): col.active = display_all row = col.row() - row.prop(overlay, "show_curve_handles", text="Handles") + row.prop(overlay, "display_handle", text="Handles") row = col.row() row.prop(overlay, "show_curve_normals", text="") diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 83144b33c67..3d72a2a588c 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -777,10 +777,6 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): col.prop(sculpt, "use_smooth_shading") - - - - class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel): bl_context = ".sculpt_mode" # dot on purpose (access from topbar) bl_label = "Remesh" diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h index 8809fadd55c..5aeaf4405f5 100644 --- a/source/blender/blenkernel/BKE_anim_data.h +++ b/source/blender/blenkernel/BKE_anim_data.h @@ -32,6 +32,7 @@ extern "C" { struct AnimData; struct ID; +struct LibraryForeachIDData; struct Main; struct ReportList; struct bAction; @@ -58,6 +59,8 @@ void BKE_animdata_free(struct ID *id, const bool do_id_user); /* Return true if the ID-block has non-empty AnimData. */ bool BKE_animdata_id_is_animated(const struct ID *id); +void BKE_animdata_foreach_id(struct AnimData *adt, struct LibraryForeachIDData *data); + /* Copy AnimData */ struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 5238853a105..c22e7a24afe 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -90,7 +90,7 @@ void BKE_armature_bone_hash_free(struct bArmature *arm); bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag); -void BKE_armature_refresh_layer_used(struct bArmature *arm); +void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm); float distfactor_to_bone( const float vec[3], const float b1[3], const float b2[3], float r1, float r2, float rdist); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 59c7a1dfd2b..3feba4b3a66 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -34,12 +34,6 @@ void BKE_blender_free(void); void BKE_blender_globals_init(void); void BKE_blender_globals_clear(void); -void BKE_blender_version_string(char *version_str, - size_t maxncpy, - short version, - short subversion, - bool v_prefix, - bool include_subversion); void BKE_blender_userdef_data_swap(struct UserDef *userdef_dst, struct UserDef *userdef_src); void BKE_blender_userdef_data_set(struct UserDef *userdef); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 5510f3c3d2e..9d948dfd57b 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -30,22 +30,26 @@ extern "C" { * * \note Use #STRINGIFY() rather than defining with quotes. */ + +/* Blender major and minor version. */ #define BLENDER_VERSION 290 -#define BLENDER_SUBVERSION 2 -/** Several breakages with 280, e.g. collections vs layers. */ -#define BLENDER_MINVERSION 280 -#define BLENDER_MINSUBVERSION 0 - -/** Used by packaging tools. */ -/** Can be left blank, otherwise a,b,c... etc with no quotes. */ -#define BLENDER_VERSION_CHAR -/** alpha/beta/rc/release, docs use this. */ +/* Blender patch version for bugfix releases. */ +#define BLENDER_VERSION_PATCH 0 +/** Blender release cycle stage: alpha/beta/rc/release. */ #define BLENDER_VERSION_CYCLE alpha -/** Optionally set to 1,2,... for example to get alpha1 or rc2. */ -#define BLENDER_VERSION_CYCLE_NUMBER -/** Defined in from blender.c */ -extern char versionstr[]; +/* Blender file format version. */ +#define BLENDER_FILE_VERSION BLENDER_VERSION +#define BLENDER_FILE_SUBVERSION 4 + +/* Minimum Blender version that supports reading file written with the current + * version. Older Blender versions will test this and show a warning if the file + * was written with too new a version. */ +#define BLENDER_FILE_MIN_VERSION 280 +#define BLENDER_FILE_MIN_SUBVERSION 0 + +/** User readable version string. */ +const char *BKE_blender_version_string(void); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index f93003dc423..812f5d520d7 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -22,7 +22,7 @@ /** \file * \ingroup bke - * \brief Camera datablock and utility functions. + * \brief Camera data-block and utility functions. */ #ifdef __cplusplus extern "C" { diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index bf270f2c06f..40f73ccfe84 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -173,7 +173,8 @@ void BKE_nurbList_handles_recalculate(struct ListBase *editnurb, const char flag); void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag); -void BKE_nurbList_flag_set(ListBase *editnurb, short flag); +void BKE_nurbList_flag_set(ListBase *editnurb, short flag, bool set); +bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, short from_flag, short flag); void BKE_nurb_free(struct Nurb *nu); struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu); diff --git a/source/blender/blenkernel/BKE_editmesh_cache.h b/source/blender/blenkernel/BKE_editmesh_cache.h index c6a2541e0a7..6c812098b2e 100644 --- a/source/blender/blenkernel/BKE_editmesh_cache.h +++ b/source/blender/blenkernel/BKE_editmesh_cache.h @@ -33,6 +33,11 @@ void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMe void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd); +bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em, + struct EditMeshData *emd, + float min[3], + float max[3]); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 21a9b7b8b04..1eb5da974ce 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -37,6 +37,7 @@ struct FModifier; struct AnimData; struct BezTriple; +struct LibraryForeachIDData; struct PathResolvedRNA; struct PointerRNA; struct PropertyRNA; @@ -185,6 +186,8 @@ struct FCurve *copy_fcurve(const struct FCurve *fcu); void free_fcurves(ListBase *list); void copy_fcurves(ListBase *dst, ListBase *src); +void BKE_fcurve_foreach_id(struct FCurve *fcu, struct LibraryForeachIDData *data); + /* find matching F-Curve in the given list of F-Curves */ struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index); diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index 353ee3bbf5a..c5a25e8e7af 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -94,6 +94,8 @@ enum { typedef struct LibraryIDLinkCallbackData { void *user_data; + /** Main database used to call `BKE_library_foreach_ID_link()`. */ + struct Main *bmain; /** * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is an * embedded one. @@ -132,6 +134,10 @@ typedef struct LibraryForeachIDData LibraryForeachIDData; bool BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data, struct ID **id_pp, int cb_flag); +int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data); +int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeachIDData *data, + const int cb_flag, + const bool do_replace); #define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \ { \ diff --git a/source/blender/blenkernel/BKE_light.h b/source/blender/blenkernel/BKE_light.h index 17f7a8596bf..ead27ec8002 100644 --- a/source/blender/blenkernel/BKE_light.h +++ b/source/blender/blenkernel/BKE_light.h @@ -31,6 +31,7 @@ extern "C" { #endif +struct Depsgraph; struct Light; struct Main; @@ -38,6 +39,8 @@ struct Light *BKE_light_add(struct Main *bmain, const char *name) ATTR_WARN_UNUS struct Light *BKE_light_copy(struct Main *bmain, const struct Light *la) ATTR_WARN_UNUSED_RESULT; struct Light *BKE_light_localize(struct Light *la) ATTR_WARN_UNUSED_RESULT; +void BKE_light_eval(struct Depsgraph *depsgraph, struct Light *la); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 29ec65166a9..516148728d2 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -87,7 +87,7 @@ enum { typedef struct Main { struct Main *next, *prev; char name[1024]; /* 1024 = FILE_MAX */ - short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION */ + short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */ short minversionfile, minsubversionfile; uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */ char build_hash[16]; /* hash from buildinfo */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index f14b9a30d99..52d458c108d 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -85,12 +85,6 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, const struct CustomData_MeshMasks *cd_mask_extra, const struct Mesh *me_settings); -struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap( - struct BMEditMesh *em, - const struct CustomData_MeshMasks *cd_mask_extra, - float (*vertexCos)[3], - const struct Mesh *me_settings); - int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, uint vert); int poly_get_adj_loops_from_vert(const struct MPoly *poly, const struct MLoop *mloop, @@ -673,6 +667,23 @@ void BKE_mesh_calc_edges_loose(struct Mesh *mesh); void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select); void BKE_mesh_calc_edges_tessface(struct Mesh *mesh); +/* *** mesh_geomtype.c *** */ +struct Mesh *BKE_mesh_wrapper_from_editmesh_with_coords( + struct BMEditMesh *em, + const struct CustomData_MeshMasks *cd_mask_extra, + float (*vertexCos)[3], + const struct Mesh *me_settings); +struct Mesh *BKE_mesh_wrapper_from_editmesh(struct BMEditMesh *em, + const struct CustomData_MeshMasks *cd_mask_extra, + const struct Mesh *me_settings); +void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me); +bool BKE_mesh_wrapper_minmax(const struct Mesh *me, float min[3], float max[3]); +void BKE_mesh_wrapper_normals_update(struct Mesh *me); + +/* In DerivedMesh.c */ +void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval, + const CustomData_MeshMasks *final_datamask); + /* **** Depsgraph evaluation **** */ void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph, struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index a4bf86f61f3..a7bf345567f 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -101,6 +101,9 @@ typedef enum { /* For modifiers that use CD_PREVIEW_MCOL for preview. */ eModifierTypeFlag_UsesPreview = (1 << 9), eModifierTypeFlag_AcceptsVertexCosOnly = (1 << 10), + + /** Accepts #BMesh input (without conversion). */ + eModifierTypeFlag_AcceptsBMesh = (1 << 11), } ModifierTypeFlag; /* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */ @@ -390,7 +393,7 @@ void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *use void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *userData); struct ModifierData *BKE_modifiers_findby_type(struct Object *ob, ModifierType type); -struct ModifierData *BKE_modifiers_findny_name(struct Object *ob, const char *name); +struct ModifierData *BKE_modifiers_findby_name(struct Object *ob, const char *name); void BKE_modifiers_clear_errors(struct Object *ob); int BKE_modifiers_get_cage_index(struct Scene *scene, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index e5a77bce0e6..2be8d657bf4 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -29,6 +29,7 @@ extern "C" { #endif struct AnimData; +struct LibraryForeachIDData; struct Main; struct NlaStrip; struct NlaTrack; @@ -63,6 +64,8 @@ struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain, struct Scene *scene, struct Speaker *spk); +void BKE_nla_strip_foreach_id(struct NlaStrip *strip, struct LibraryForeachIDData *data); + /* ----------------------------- */ /* API */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index a7ece2e3167..ac292432acc 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -239,6 +239,7 @@ typedef struct SculptPoseIKChainSegment { float initial_orig[3]; float initial_head[3]; float len; + float scale; float rot[4]; float *weights; diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index ea81be05b03..00d010cd6d9 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -430,7 +430,7 @@ void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, const float parent_orco[3]); void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata); -void psys_sph_finalise(struct SPHData *sphdata); +void psys_sph_finalize(struct SPHData *sphdata); void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]); /* for anim.c */ diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 409afcd9f75..2bf16e38716 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -309,6 +309,8 @@ void BKE_pbvh_face_sets_set(PBVH *bvh, int *face_sets); void BKE_pbvh_face_sets_color_set(PBVH *bvh, int seed, int color_default); +void BKE_pbvh_respect_hide_set(PBVH *bvh, bool respect_hide); + /* vertex deformer */ float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3]; void BKE_pbvh_vert_coords_apply(struct PBVH *pbvh, const float (*vertCos)[3], const int totvert); @@ -334,6 +336,7 @@ typedef struct PBVHVertexIter { int gy; int i; int index; + bool respect_hide; /* grid */ struct CCGKey key; @@ -402,9 +405,15 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo } \ else if (vi.mverts) { \ vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \ - vi.visible = !(vi.mvert->flag & ME_HIDE); \ - if (mode == PBVH_ITER_UNIQUE && !vi.visible) \ - continue; \ + if (vi.respect_hide) { \ + vi.visible = !(vi.mvert->flag & ME_HIDE); \ + if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \ + continue; \ + } \ + } \ + else { \ + BLI_assert(vi.visible); \ + } \ vi.co = vi.mvert->co; \ vi.no = vi.mvert->no; \ vi.index = vi.vert_indices[vi.i]; \ diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index c49b6e27bba..fc7146b8cf4 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -34,6 +34,7 @@ extern "C" { struct ARegion; struct Header; struct ID; +struct LibraryForeachIDData; struct ListBase; struct Menu; struct Panel; @@ -228,6 +229,25 @@ typedef struct PanelType { /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct Panel *panel); + /* For instanced panels corresponding to a list: */ + + /** Reorder function, called when drag and drop finishes. */ + void (*reorder)(struct bContext *C, struct Panel *pa, int new_index); + /** + * Get the panel and sub-panel's expansion state from the expansion flag in the corresponding + * data item. Called on draw updates. + * \note Sub-panels are indexed in depth first order, + * the visual order you would see if all panels were expanded. + */ + short (*get_list_data_expand_flag)(const struct bContext *C, struct Panel *pa); + /** + * Set the expansion bit-field from the closed / open state of this panel and its sub-panels. + * Called when the expansion state of the panel changes with user input. + * \note Sub-panels are indexed in depth first order, + * the visual order you would see if all panels were expanded. + */ + void (*set_list_data_expand_flag)(const struct bContext *C, struct Panel *pa, short expand_flag); + /* sub panels */ struct PanelType *parent; ListBase children; @@ -389,6 +409,8 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac); void BKE_screen_view3d_shading_init(struct View3DShading *shading); /* screen */ +void BKE_screen_foreach_id_screen_area(struct LibraryForeachIDData *data, struct ScrArea *area); + void BKE_screen_free(struct bScreen *screen); void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL(); diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h index d1cf782e9e5..ff6aaa5e30e 100644 --- a/source/blender/blenkernel/BKE_simulation.h +++ b/source/blender/blenkernel/BKE_simulation.h @@ -21,13 +21,15 @@ extern "C" { #endif +struct Depsgraph; struct Main; struct Simulation; -struct Depsgraph; void *BKE_simulation_add(struct Main *bmain, const char *name); -void BKE_simulation_data_update(struct Depsgraph *depsgraph, struct Scene *scene); +void BKE_simulation_data_update(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Simulation *simulation); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h index 0333d52a464..1323938e479 100644 --- a/source/blender/blenkernel/BKE_subdiv.h +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -194,6 +194,12 @@ typedef struct Subdiv { } cache_; } Subdiv; +/* =================----====--===== MODULE ==========================------== */ + +/* (De)initialize the entire subdivision surface module. */ +void BKE_subdiv_init(void); +void BKE_subdiv_exit(void); + /* ========================== CONVERSION HELPERS ============================ */ /* NOTE: uv_smooth is eSubsurfUVSmooth. */ diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index 16013034823..2dee8de4dc7 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -103,7 +103,7 @@ typedef struct CCGDerivedMesh { struct CCGSubSurf *ss; int freeSS; - int drawInteriorEdges, useSubsurfUv, useGpuBackend; + int drawInteriorEdges, useSubsurfUv; struct { int startVert; @@ -156,13 +156,6 @@ typedef struct CCGDerivedMesh { ThreadRWMutex origindex_cache_rwlock; } CCGDerivedMesh; -#ifdef WITH_OPENSUBDIV -/* TODO(sergey): Not really ideal place, but we don't currently have better one. */ -void BKE_subsurf_osd_init(void); -void BKE_subsurf_free_unused_buffers(void); -void BKE_subsurf_osd_cleanup(void); -#endif - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h index 8582996108a..8a6afd8a753 100644 --- a/source/blender/blenkernel/BKE_workspace.h +++ b/source/blender/blenkernel/BKE_workspace.h @@ -84,6 +84,7 @@ void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook, struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS; void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook, + struct WorkSpace *workspace, struct WorkSpaceLayout *layout) SETTER_ATTRS; struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS; @@ -91,21 +92,14 @@ void BKE_workspace_active_screen_set(struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct bScreen *screen) SETTER_ATTRS; -struct ListBase *BKE_workspace_layouts_get(struct WorkSpace *workspace) GETTER_ATTRS; - const char *BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS; void BKE_workspace_layout_name_set(struct WorkSpace *workspace, struct WorkSpaceLayout *layout, const char *new_name) ATTR_NONNULL(); struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS; -void BKE_workspace_layout_screen_set(struct WorkSpaceLayout *layout, - struct bScreen *screen) SETTER_ATTRS; -struct WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get( +struct WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get( const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS; -void BKE_workspace_hook_layout_for_workspace_set(struct WorkSpaceInstanceHook *hook, - struct WorkSpace *workspace, - struct WorkSpaceLayout *layout) ATTR_NONNULL(); bool BKE_workspace_owner_id_check(const struct WorkSpace *workspace, const char *owner_id) ATTR_NONNULL(); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 4de7ce02559..f6f18f4ab2a 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -64,8 +64,6 @@ set(SRC ${CMAKE_SOURCE_DIR}/release/datafiles/userdef/userdef_default.c intern/CCGSubSurf.c intern/CCGSubSurf_legacy.c - intern/CCGSubSurf_opensubdiv.c - intern/CCGSubSurf_opensubdiv_converter.c intern/CCGSubSurf_util.c intern/DerivedMesh.c intern/action.c @@ -170,6 +168,7 @@ set(SRC intern/mesh_runtime.c intern/mesh_tangent.c intern/mesh_validate.c + intern/mesh_wrapper.c intern/modifier.c intern/movieclip.c intern/multires.c diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index d76a4d8f859..98deddb4316 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -32,13 +32,6 @@ #include "CCGSubSurf.h" #include "CCGSubSurf_intern.h" -#ifdef WITH_OPENSUBDIV -# include "opensubdiv_capi.h" -# include "opensubdiv_converter_capi.h" -# include "opensubdiv_evaluator_capi.h" -# include "opensubdiv_topology_refiner_capi.h" -#endif - #include "GPU_glew.h" /***/ @@ -305,21 +298,6 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, ss->tempVerts = NULL; ss->tempEdges = NULL; -#ifdef WITH_OPENSUBDIV - ss->osd_evaluator = NULL; - ss->osd_mesh = NULL; - ss->osd_topology_refiner = NULL; - ss->osd_mesh_invalid = false; - ss->osd_coarse_coords_invalid = false; - ss->osd_vao = 0; - ss->skip_grids = false; - ss->osd_compute = 0; - ss->osd_next_face_ptex_index = 0; - ss->osd_coarse_coords = NULL; - ss->osd_num_coarse_coords = 0; - ss->osd_subdiv_uvs = false; -#endif - return ss; } } @@ -328,23 +306,6 @@ void ccgSubSurf_free(CCGSubSurf *ss) { CCGAllocatorIFC allocatorIFC = ss->allocatorIFC; CCGAllocatorHDL allocator = ss->allocator; -#ifdef WITH_OPENSUBDIV - if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluator(ss->osd_evaluator); - } - if (ss->osd_mesh != NULL) { - ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); - } - if (ss->osd_vao != 0) { - ccgSubSurf__delete_vertex_array(ss->osd_vao); - } - if (ss->osd_coarse_coords != NULL) { - MEM_freeN(ss->osd_coarse_coords); - } - if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); - } -#endif if (ss->syncState) { ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_free, ss); @@ -529,9 +490,6 @@ CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges"); ss->syncState = eSyncState_Vert; -#ifdef WITH_OPENSUBDIV - ss->osd_next_face_ptex_index = 0; -#endif return eCCGError_None; } @@ -671,9 +629,6 @@ CCGError ccgSubSurf_syncVert( ccg_ehash_insert(ss->vMap, (EHEntry *)v); v->flags = 0; } -#ifdef WITH_OPENSUBDIV - v->osd_index = ss->vMap->numEntries - 1; -#endif } if (v_r) { @@ -874,15 +829,6 @@ CCGError ccgSubSurf_syncFace( } } } -#ifdef WITH_OPENSUBDIV - f->osd_index = ss->osd_next_face_ptex_index; - if (numVerts == 4) { - ss->osd_next_face_ptex_index++; - } - else { - ss->osd_next_face_ptex_index += numVerts; - } -#endif } if (f_r) { @@ -893,15 +839,7 @@ CCGError ccgSubSurf_syncFace( static void ccgSubSurf__sync(CCGSubSurf *ss) { -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - ccgSubSurf__sync_opensubdiv(ss); - } - else -#endif - { - ccgSubSurf__sync_legacy(ss); - } + ccgSubSurf__sync_legacy(ss); } CCGError ccgSubSurf_processSync(CCGSubSurf *ss) @@ -1615,12 +1553,6 @@ int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss) ss->fMap->numEntries + ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2)))); -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - return 0; - } -#endif - return numFinalVerts; } int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss) @@ -1629,22 +1561,12 @@ int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss) int gridSize = ccg_gridsize(ss->subdivLevels); int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) + ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1)))); -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - return 0; - } -#endif return numFinalEdges; } int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss) { int gridSize = ccg_gridsize(ss->subdivLevels); int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1)); -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - return 0; - } -#endif return numFinalFaces; } diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index 83b59941ac7..2e5100db6de 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -211,57 +211,4 @@ CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi); int ccgFaceIterator_isStopped(CCGFaceIterator *fi); void ccgFaceIterator_next(CCGFaceIterator *fi); -#ifdef WITH_OPENSUBDIV -struct DerivedMesh; - -/* Check if topology changed and evaluators are to be re-created. */ -void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm); - -/* Create topology refiner from give derived mesh which then later will be - * used for GL mesh creation. - */ -void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm); - -/* Make sure GL mesh exists, up to date and ready to draw. */ -bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index); - -/* Draw given partitions of the GL mesh. - * - * TODO(sergey): fill_quads is actually an invariant and should be part - * of the prepare routine. - */ -void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, - bool fill_quads, - int start_partition, - int num_partitions); - -/* Get number of base faces in a particular GL mesh. */ -int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss); - -/* Get number of vertices in base faces in a particular GL mesh. */ -int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face); - -/* Controls whether CCG are needed (Cmeaning CPU evaluation) or fully GPU compute - * and draw is allowed. - */ -void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids); -bool ccgSubSurf_needGrids(CCGSubSurf *ss); - -/* Set evaluator's face varying data from UV coordinates. - * Used for CPU evaluation. - */ -void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, struct DerivedMesh *dm, int layer_index); - -/* TODO(sergey): Temporary call to test things. */ -void ccgSubSurf_evaluatorFVarUV( - CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2]); - -void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss); - -void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]); - -void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs); - -#endif - #endif /* __CCGSUBSURF_H__ */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h index 51486db1bdc..7c35d2ccfce 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -157,9 +157,6 @@ typedef enum { eSyncState_Edge, eSyncState_Face, eSyncState_Partial, -#ifdef WITH_OPENSUBDIV - eSyncState_OpenSubdiv, -#endif } SyncState; struct CCGSubSurf { @@ -202,58 +199,6 @@ struct CCGSubSurf { int lenTempArrays; CCGVert **tempVerts; CCGEdge **tempEdges; - -#ifdef WITH_OPENSUBDIV - /* Skip grids means no CCG geometry is created and subsurf is possible - * to be completely done on GPU. - */ - bool skip_grids; - - /* ** GPU backend. ** */ - - /* Compute device used by GL mesh. */ - short osd_compute; - /* Coarse (base mesh) vertex coordinates. - * - * Filled in from the modifier stack and passed to OpenSubdiv compute - * on mesh display. - */ - float (*osd_coarse_coords)[3]; - int osd_num_coarse_coords; - /* Denotes whether coarse positions in the GL mesh are invalid. - * Used to avoid updating GL mesh coords on every redraw. - */ - bool osd_coarse_coords_invalid; - - /* GL mesh descriptor, used for refinement and draw. */ - struct OpenSubdiv_GLMesh *osd_mesh; - /* Refiner which is used to create GL mesh. - * - * Refiner is created from the modifier stack and used later from the main - * thread to construct GL mesh to avoid threaded access to GL. - */ - struct OpenSubdiv_TopologyRefiner - *osd_topology_refiner; /* Only used at synchronization stage. */ - /* Denotes whether osd_mesh is invalid now due to topology changes and needs - * to be reconstructed. - * - * Reconstruction happens from main thread due to OpenGL communication. - */ - bool osd_mesh_invalid; - /* Vertex array used for osd_mesh draw. */ - unsigned int osd_vao; - - /* ** CPU backend. ** */ - - /* Limit evaluator, used to evaluate CCG. */ - struct OpenSubdiv_Evaluator *osd_evaluator; - /* Next PTex face index, used while CCG synchronization - * to fill in PTex index of CCGFace. - */ - int osd_next_face_ptex_index; - - bool osd_subdiv_uvs; -#endif }; /* ** Utility macros ** */ @@ -322,16 +267,6 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss); void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss); -/* Delayed free routines. Will do actual free if called from - * main thread and schedule free for later free otherwise. - */ - -#ifdef WITH_OPENSUBDIV -void ccgSubSurf__delete_osdGLMesh(struct OpenSubdiv_GLMesh *osd_mesh); -void ccgSubSurf__delete_vertex_array(unsigned int vao); -void ccgSubSurf__delete_pending(void); -#endif - /* * CCGSubSurf_opensubdiv_converter.c * */ struct OpenSubdiv_Converter; diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c deleted file mode 100644 index 3257dd2334c..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ /dev/null @@ -1,970 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup bke - */ - -#ifdef WITH_OPENSUBDIV - -# include "BLI_sys_types.h" // for intptr_t support -# include "MEM_guardedalloc.h" - -# include "BLI_listbase.h" -# include "BLI_math.h" -# include "BLI_threads.h" -# include "BLI_utildefines.h" /* for BLI_assert */ - -# include "CCGSubSurf.h" -# include "CCGSubSurf_intern.h" - -# include "BKE_DerivedMesh.h" -# include "BKE_subsurf.h" - -# include "DNA_userdef_types.h" - -# include "opensubdiv_capi.h" -# include "opensubdiv_converter_capi.h" -# include "opensubdiv_evaluator_capi.h" -# include "opensubdiv_gl_mesh_capi.h" -# include "opensubdiv_topology_refiner_capi.h" - -# include "GPU_extensions.h" -# include "GPU_glew.h" - -# define OSD_LOG \ - if (false) \ - printf - -static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) -{ - const int num_verts = dm->getNumVerts(dm); - const int num_edges = dm->getNumEdges(dm); - const int num_polys = dm->getNumPolys(dm); - const MEdge *medge = dm->getEdgeArray(dm); - const MLoop *mloop = dm->getLoopArray(dm); - const MPoly *mpoly = dm->getPolyArray(dm); - - /* Quick preliminary tests based on the number of verts and facces. */ - { - if (num_verts != ss->vMap->numEntries || num_edges != ss->eMap->numEntries || - num_polys != ss->fMap->numEntries) { - return false; - } - } - - /* Rather slow check for faces topology change. */ - { - CCGFaceIterator ccg_face_iter; - for (ccgSubSurf_initFaceIterator(ss, &ccg_face_iter); - !ccgFaceIterator_isStopped(&ccg_face_iter); - ccgFaceIterator_next(&ccg_face_iter)) { - /*const*/ CCGFace *ccg_face = ccgFaceIterator_getCurrent(&ccg_face_iter); - const int poly_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face)); - const MPoly *mp = &mpoly[poly_index]; - int corner; - if (ccg_face->numVerts != mp->totloop) { - return false; - } - for (corner = 0; corner < ccg_face->numVerts; corner++) { - /*const*/ CCGVert *ccg_vert = FACE_getVerts(ccg_face)[corner]; - const int vert_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert)); - if (vert_index != mloop[mp->loopstart + corner].v) { - return false; - } - } - } - } - - /* Check for edge topology change. */ - { - CCGEdgeIterator ccg_edge_iter; - for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter); - !ccgEdgeIterator_isStopped(&ccg_edge_iter); - ccgEdgeIterator_next(&ccg_edge_iter)) { - /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter); - /* const */ CCGVert *ccg_vert1 = ccg_edge->v0; - /* const */ CCGVert *ccg_vert2 = ccg_edge->v1; - const int ccg_vert1_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1)); - const int ccg_vert2_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert2)); - const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - const MEdge *me = &medge[edge_index]; - if (me->v1 != ccg_vert1_index || me->v2 != ccg_vert2_index) { - return false; - } - } - } - - /* TODO(sergey): Crease topology changes detection. */ - { - CCGEdgeIterator ccg_edge_iter; - for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter); - !ccgEdgeIterator_isStopped(&ccg_edge_iter); - ccgEdgeIterator_next(&ccg_edge_iter)) { - /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter); - const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - if (ccg_edge->crease != medge[edge_index].crease) { - return false; - } - } - } - - return true; -} - -static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) -{ - OpenSubdiv_Converter converter; - bool result; - if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) { - return true; - } - /* TODO(sergey): De-duplicate with topology counter at the bottom of - * the file. - */ - ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); - result = openSubdiv_topologyRefinerCompareWithConverter(ss->osd_topology_refiner, &converter); - ccgSubSurf_converter_free(&converter); - return result; -} - -static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm) -{ - if (ss->osd_compute != U.opensubdiv_compute_type) { - return true; - } - if (ss->osd_topology_refiner != NULL) { - const int levels = ss->osd_topology_refiner->getSubdivisionLevel(ss->osd_topology_refiner); - BLI_assert(ss->osd_mesh_invalid == true); - if (levels != ss->subdivLevels) { - return true; - } - } - if (ss->skip_grids == false) { - return compare_ccg_derivedmesh_topology(ss, dm) == false; - } - else { - return compare_osd_derivedmesh_topology(ss, dm) == false; - } - return false; -} - -void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm) -{ - if (opensubdiv_is_topology_changed(ss, dm)) { - /* ** Make sure both GPU and CPU backends are properly reset. ** */ - - ss->osd_coarse_coords_invalid = true; - - /* Reset GPU part. */ - ss->osd_mesh_invalid = true; - if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); - ss->osd_topology_refiner = NULL; - } - - /* Reset CPU side. */ - if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluator(ss->osd_evaluator); - ss->osd_evaluator = NULL; - } - } -} - -static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss) -{ - BLI_assert(ss->meshIFC.numLayers == 3); - ss->osd_mesh->setCoarsePositions( - ss->osd_mesh, (float *)ss->osd_coarse_coords, 0, ss->osd_num_coarse_coords); -} - -bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index) -{ - int compute_type; - - switch (U.opensubdiv_compute_type) { -# define CHECK_COMPUTE_TYPE(type) \ - case USER_OPENSUBDIV_COMPUTE_##type: \ - compute_type = OPENSUBDIV_EVALUATOR_##type; \ - break; - CHECK_COMPUTE_TYPE(CPU) - CHECK_COMPUTE_TYPE(OPENMP) - CHECK_COMPUTE_TYPE(OPENCL) - CHECK_COMPUTE_TYPE(CUDA) - CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK) - CHECK_COMPUTE_TYPE(GLSL_COMPUTE) - default: - compute_type = OPENSUBDIV_EVALUATOR_CPU; - break; -# undef CHECK_COMPUTE_TYPE - } - - if (ss->osd_vao == 0) { - glGenVertexArrays(1, &ss->osd_vao); - } - - if (ss->osd_mesh_invalid) { - if (ss->osd_mesh != NULL) { - ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); - ss->osd_mesh = NULL; - } - ss->osd_mesh_invalid = false; - } - - if (ss->osd_mesh == NULL) { - if (ss->osd_topology_refiner == NULL) { - /* Happens with empty meshes. */ - /* TODO(sergey): Add assert that mesh is indeed empty. */ - return false; - } - - ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(ss->osd_topology_refiner, - compute_type); - - if (UNLIKELY(ss->osd_mesh == NULL)) { - /* Most likely compute device is not available. */ - return false; - } - - ccgSubSurf__updateGLMeshCoords(ss); - ss->osd_mesh->refine(ss->osd_mesh); - ss->osd_mesh->synchronize(ss->osd_mesh); - ss->osd_coarse_coords_invalid = false; - - glBindVertexArray(ss->osd_vao); - ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)12); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - else if (ss->osd_coarse_coords_invalid) { - ccgSubSurf__updateGLMeshCoords(ss); - ss->osd_mesh->refine(ss->osd_mesh); - ss->osd_mesh->synchronize(ss->osd_mesh); - ss->osd_coarse_coords_invalid = false; - } - - ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index); - - return true; -} - -void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, - bool fill_quads, - int start_partition, - int num_partitions) -{ - if (LIKELY(ss->osd_mesh != NULL)) { - glBindVertexArray(ss->osd_vao); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh)); - - ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); - glBindVertexArray(ss->osd_vao); - ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, start_partition, num_partitions); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } -} - -int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss) -{ - if (ss->osd_topology_refiner != NULL) { - return ss->osd_topology_refiner->getNumFaces(ss->osd_topology_refiner); - } - return 0; -} - -/* Get number of vertices in base faces in a particular GL mesh. */ -int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face) -{ - if (ss->osd_topology_refiner != NULL) { - return ss->osd_topology_refiner->getNumFaceVertices(ss->osd_topology_refiner, face); - } - return 0; -} - -void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids) -{ - ss->skip_grids = skip_grids; -} - -bool ccgSubSurf_needGrids(CCGSubSurf *ss) -{ - return ss->skip_grids == false; -} - -BLI_INLINE void ccgSubSurf__mapGridToFace( - int S, float grid_u, float grid_v, float *face_u, float *face_v) -{ - float u, v; - - /* - Each grid covers half of the face along the edges. - * - Grid's (0, 0) starts from the middle of the face. - */ - u = 0.5f - 0.5f * grid_u; - v = 0.5f - 0.5f * grid_v; - - if (S == 0) { - *face_u = v; - *face_v = u; - } - else if (S == 1) { - *face_u = 1.0f - u; - *face_v = v; - } - else if (S == 2) { - *face_u = 1.0f - v; - *face_v = 1.0f - u; - } - else { - *face_u = u; - *face_v = 1.0f - v; - } -} - -BLI_INLINE void ccgSubSurf__mapEdgeToFace( - int S, int edge_segment, bool inverse_edge, int edgeSize, float *face_u, float *face_v) -{ - int t = inverse_edge ? edgeSize - edge_segment - 1 : edge_segment; - if (S == 0) { - *face_u = (float)t / (edgeSize - 1); - *face_v = 0.0f; - } - else if (S == 1) { - *face_u = 1.0f; - *face_v = (float)t / (edgeSize - 1); - } - else if (S == 2) { - *face_u = 1.0f - (float)t / (edgeSize - 1); - *face_v = 1.0f; - } - else { - *face_u = 0.0f; - *face_v = 1.0f - (float)t / (edgeSize - 1); - } -} - -void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, DerivedMesh *dm, int layer_index) -{ - MPoly *mpoly = dm->getPolyArray(dm); - MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index); - int num_polys = dm->getNumPolys(dm); - int index, poly; - BLI_assert(ss->osd_evaluator != NULL); - for (poly = 0, index = 0; poly < num_polys; poly++) { - int loop; - MPoly *mp = &mpoly[poly]; - for (loop = 0; loop < mp->totloop; loop++, index++) { - MLoopUV *mluv = &mloopuv[loop + mp->loopstart]; - (void)mluv; - /* TODO(sergey): Send mluv->uv to the evaluator's face varying - * buffer. - */ - } - } - (void)ss; -} - -void ccgSubSurf_evaluatorFVarUV( - CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2]) -{ - float face_u, face_v; - ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v); - (void)ss; - (void)face_index; - /* TODO(sergey): Evaluate face varying coordinate. */ - zero_v2(uv); -} - -static bool opensubdiv_createEvaluator(CCGSubSurf *ss) -{ - OpenSubdiv_Converter converter; - OpenSubdiv_TopologyRefiner *topology_refiner; - if (ss->fMap->numEntries == 0) { - /* OpenSubdiv doesn't support meshes without faces. */ - return false; - } - ccgSubSurf_converter_setup_from_ccg(ss, &converter); - OpenSubdiv_TopologyRefinerSettings settings; - settings.level = ss->subdivLevels; - settings.is_adaptive = false; - topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, &settings); - ccgSubSurf_converter_free(&converter); - ss->osd_evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner); - if (ss->osd_evaluator == NULL) { - BLI_assert(!"OpenSubdiv initialization failed, should not happen."); - return false; - } - return true; -} - -static bool opensubdiv_ensureEvaluator(CCGSubSurf *ss) -{ - if (ss->osd_evaluator == NULL) { - OSD_LOG("Allocating new evaluator, %d verts\n", ss->vMap->numEntries); - opensubdiv_createEvaluator(ss); - } - return ss->osd_evaluator != NULL; -} - -static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss) -{ - float(*positions)[3]; - int vertDataSize = ss->meshIFC.vertDataSize; - int num_basis_verts = ss->vMap->numEntries; - int i; - - /* TODO(sergey): Avoid allocation on every update. We could either update - * coordinates in chunks of 1K vertices (which will only use stack memory) - * or do some callback magic for OSD evaluator can invoke it and fill in - * buffer directly. - */ - if (ss->meshIFC.numLayers == 3) { - /* If all the components are to be initialized, no need to memset the - * new memory block. - */ - positions = MEM_mallocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points"); - } - else { - /* Calloc in order to have z component initialized to 0 for Uvs */ - positions = MEM_callocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points"); - } -# pragma omp parallel for - for (i = 0; i < ss->vMap->curSize; i++) { - CCGVert *v = (CCGVert *)ss->vMap->buckets[i]; - for (; v; v = v->next) { - float *co = VERT_getCo(v, 0); - BLI_assert(v->osd_index < ss->vMap->numEntries); - VertDataCopy(positions[v->osd_index], co, ss); - OSD_LOG("Point %d has value %f %f %f\n", - v->osd_index, - positions[v->osd_index][0], - positions[v->osd_index][1], - positions[v->osd_index][2]); - } - } - - ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, (float *)positions, 0, num_basis_verts); - ss->osd_evaluator->refine(ss->osd_evaluator); - - MEM_freeN(positions); -} - -static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss, - CCGFace *face, - const int osd_face_index) -{ - int normalDataOffset = ss->normalDataOffset; - int subdivLevels = ss->subdivLevels; - int gridSize = ccg_gridsize(subdivLevels); - int edgeSize = ccg_edgesize(subdivLevels); - int vertDataSize = ss->meshIFC.vertDataSize; - int S; - bool do_normals = ss->meshIFC.numLayers == 3; - -# pragma omp parallel for - for (S = 0; S < face->numVerts; S++) { - int x, y, k; - CCGEdge *edge = NULL; - bool inverse_edge = false; - - for (x = 0; x < gridSize; x++) { - for (y = 0; y < gridSize; y++) { - float *co = FACE_getIFCo(face, subdivLevels, S, x, y); - float *no = FACE_getIFNo(face, subdivLevels, S, x, y); - float grid_u = (float)x / (gridSize - 1), grid_v = (float)y / (gridSize - 1); - float face_u, face_v; - float P[3], dPdu[3], dPdv[3]; - - ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v); - - /* TODO(sergey): Need proper port. */ - ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, - osd_face_index, - face_u, - face_v, - P, - do_normals ? dPdu : NULL, - do_normals ? dPdv : NULL); - - OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n", - osd_face_index, - S, - grid_u, - grid_v, - face_u, - face_v, - P[0], - P[1], - P[2]); - - VertDataCopy(co, P, ss); - if (do_normals) { - cross_v3_v3v3(no, dPdu, dPdv); - normalize_v3(no); - } - - if (x == gridSize - 1 && y == gridSize - 1) { - float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_co, co, ss); - if (do_normals) { - float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_no, no, ss); - } - } - if (S == 0 && x == 0 && y == 0) { - float *center_co = (float *)FACE_getCenterData(face); - VertDataCopy(center_co, co, ss); - if (do_normals) { - float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset); - VertDataCopy(center_no, no, ss); - } - } - } - } - - for (x = 0; x < gridSize; x++) { - VertDataCopy( - FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss); - if (do_normals) { - VertDataCopy( - FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss); - } - } - - for (k = 0; k < face->numVerts; k++) { - CCGEdge *current_edge = FACE_getEdges(face)[k]; - CCGVert **face_verts = FACE_getVerts(face); - if (current_edge->v0 == face_verts[S] && - current_edge->v1 == face_verts[(S + 1) % face->numVerts]) { - edge = current_edge; - inverse_edge = false; - break; - } - if (current_edge->v1 == face_verts[S] && - current_edge->v0 == face_verts[(S + 1) % face->numVerts]) { - edge = current_edge; - inverse_edge = true; - break; - } - } - - BLI_assert(edge != NULL); - - for (x = 0; x < edgeSize; x++) { - float u = 0, v = 0; - float *co = EDGE_getCo(edge, subdivLevels, x); - float *no = EDGE_getNo(edge, subdivLevels, x); - float P[3], dPdu[3], dPdv[3]; - ccgSubSurf__mapEdgeToFace(S, x, inverse_edge, edgeSize, &u, &v); - - /* TODO(sergey): Ideally we will re-use grid here, but for now - * let's just re-evaluate for simplicity. - */ - /* TODO(sergey): Need proper port. */ - ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv); - VertDataCopy(co, P, ss); - if (do_normals) { - cross_v3_v3v3(no, dPdu, dPdv); - normalize_v3(no); - } - } - } -} - -static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss, - CCGFace *face, - const int osd_face_index) -{ - CCGVert **all_verts = FACE_getVerts(face); - int normalDataOffset = ss->normalDataOffset; - int subdivLevels = ss->subdivLevels; - int gridSize = ccg_gridsize(subdivLevels); - int edgeSize = ccg_edgesize(subdivLevels); - int vertDataSize = ss->meshIFC.vertDataSize; - int S; - bool do_normals = ss->meshIFC.numLayers == 3; - - /* Note about handling non-quad faces. - * - * In order to deal with non-quad faces we need to split them - * into a quads in the following way: - * - * | - * (vert_next) - * | - * | - * | - * (face_center) ------------------- (v2) - * | (o)--------------------> | - * | | v | - * | | | - * | | | - * | | | - * | | y ^ | - * | | | | - * | v u x | | - * | <---(o) | - * ---- (vert_prev) ---- (v1) -------------------- (vert) - * - * This is how grids are expected to be stored and it's how - * OpenSubdiv deals with non-quad faces using ptex face indices. - * We only need to convert ptex (x, y) to grid (u, v) by some - * simple flips and evaluate the ptex face. - */ - - /* Evaluate face grids. */ -# pragma omp parallel for - for (S = 0; S < face->numVerts; S++) { - int x, y; - for (x = 0; x < gridSize; x++) { - for (y = 0; y < gridSize; y++) { - float *co = FACE_getIFCo(face, subdivLevels, S, x, y); - float *no = FACE_getIFNo(face, subdivLevels, S, x, y); - float u = 1.0f - (float)y / (gridSize - 1), v = 1.0f - (float)x / (gridSize - 1); - float P[3], dPdu[3], dPdv[3]; - - /* TODO(sergey): Need proper port. */ - ss->osd_evaluator->evaluateLimit( - ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv); - - OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n", - osd_face_index + S, - S, - u, - v, - P[0], - P[1], - P[2]); - - VertDataCopy(co, P, ss); - if (do_normals) { - cross_v3_v3v3(no, dPdu, dPdv); - normalize_v3(no); - } - - /* TODO(sergey): De-dpuplicate with the quad case. */ - if (x == gridSize - 1 && y == gridSize - 1) { - float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_co, co, ss); - if (do_normals) { - float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_no, no, ss); - } - } - if (S == 0 && x == 0 && y == 0) { - float *center_co = (float *)FACE_getCenterData(face); - VertDataCopy(center_co, co, ss); - if (do_normals) { - float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset); - VertDataCopy(center_no, no, ss); - } - } - } - } - for (x = 0; x < gridSize; x++) { - VertDataCopy( - FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss); - if (do_normals) { - VertDataCopy( - FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss); - } - } - } - - /* Evaluate edges. */ - for (S = 0; S < face->numVerts; S++) { - CCGEdge *edge = FACE_getEdges(face)[S]; - int x, S0 = 0, S1 = 0; - bool flip; - - for (x = 0; x < face->numVerts; x++) { - if (all_verts[x] == edge->v0) { - S0 = x; - } - else if (all_verts[x] == edge->v1) { - S1 = x; - } - } - if (S == face->numVerts - 1) { - flip = S0 > S1; - } - else { - flip = S0 < S1; - } - - for (x = 0; x <= edgeSize / 2; x++) { - float *edge_co = EDGE_getCo(edge, subdivLevels, x); - float *edge_no = EDGE_getNo(edge, subdivLevels, x); - float *face_edge_co; - float *face_edge_no; - if (flip) { - face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x); - face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x); - } - else { - face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1); - face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1); - } - VertDataCopy(edge_co, face_edge_co, ss); - if (do_normals) { - VertDataCopy(edge_no, face_edge_no, ss); - } - } - for (x = edgeSize / 2 + 1; x < edgeSize; x++) { - float *edge_co = EDGE_getCo(edge, subdivLevels, x); - float *edge_no = EDGE_getNo(edge, subdivLevels, x); - float *face_edge_co; - float *face_edge_no; - if (flip) { - face_edge_co = FACE_getIFCo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1); - face_edge_no = FACE_getIFNo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1); - } - else { - face_edge_co = FACE_getIFCo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2); - face_edge_no = FACE_getIFNo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2); - } - VertDataCopy(edge_co, face_edge_co, ss); - if (do_normals) { - VertDataCopy(edge_no, face_edge_no, ss); - } - } - } -} - -static void opensubdiv_evaluateGrids(CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->fMap->curSize; i++) { - CCGFace *face = (CCGFace *)ss->fMap->buckets[i]; - for (; face; face = face->next) { - if (face->numVerts == 4) { - /* For quads we do special magic with converting face coords - * into corner coords and interpolating grids from it. - */ - opensubdiv_evaluateQuadFaceGrids(ss, face, face->osd_index); - } - else { - /* NGons and tris are split into separate osd faces which - * evaluates onto grids directly. - */ - opensubdiv_evaluateNGonFaceGrids(ss, face, face->osd_index); - } - } - } -} - -CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss) -{ - if (ss->syncState != eSyncState_None) { - return eCCGError_InvalidSyncState; - } - ss->syncState = eSyncState_OpenSubdiv; - return eCCGError_None; -} - -void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm) -{ - if (ss->osd_mesh == NULL || ss->osd_mesh_invalid) { - if (dm->getNumPolys(dm) != 0) { - OpenSubdiv_Converter converter; - ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); - /* TODO(sergey): Remove possibly previously allocated refiner. */ - OpenSubdiv_TopologyRefinerSettings settings; - settings.level = ss->subdivLevels; - settings.is_adaptive = false; - ss->osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, - &settings); - ccgSubSurf_converter_free(&converter); - } - } - - /* Update number of grids, needed for things like final faces - * counter, used by display drawing. - */ - { - const int num_polys = dm->getNumPolys(dm); - const MPoly *mpoly = dm->getPolyArray(dm); - int poly; - ss->numGrids = 0; - for (poly = 0; poly < num_polys; poly++) { - ss->numGrids += mpoly[poly].totloop; - } - } - - { - const int num_verts = dm->getNumVerts(dm); - const MVert *mvert = dm->getVertArray(dm); - int vert; - if (ss->osd_coarse_coords != NULL && num_verts != ss->osd_num_coarse_coords) { - MEM_freeN(ss->osd_coarse_coords); - ss->osd_coarse_coords = NULL; - } - if (ss->osd_coarse_coords == NULL) { - ss->osd_coarse_coords = MEM_mallocN(sizeof(float) * 6 * num_verts, "osd coarse positions"); - } - for (vert = 0; vert < num_verts; vert++) { - copy_v3_v3(ss->osd_coarse_coords[vert * 2 + 0], mvert[vert].co); - normal_short_to_float_v3(ss->osd_coarse_coords[vert * 2 + 1], mvert[vert].no); - } - ss->osd_num_coarse_coords = num_verts; - ss->osd_coarse_coords_invalid = true; - } -} - -void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss) -{ - BLI_assert(ss->meshIFC.numLayers == 2 || ss->meshIFC.numLayers == 3); - - /* Common synchronization steps */ - ss->osd_compute = U.opensubdiv_compute_type; - - if (ss->skip_grids == false) { - /* Make sure OSD evaluator is up-to-date. */ - if (opensubdiv_ensureEvaluator(ss)) { - /* Update coarse points in the OpenSubdiv evaluator. */ - opensubdiv_updateEvaluatorCoarsePositions(ss); - - /* Evaluate opensubdiv mesh into the CCG grids. */ - opensubdiv_evaluateGrids(ss); - } - } - else { - BLI_assert(ss->meshIFC.numLayers == 3); - } - -# ifdef DUMP_RESULT_GRIDS - ccgSubSurf__dumpCoords(ss); -# endif -} - -void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss) -{ - if (ss->osd_mesh != NULL) { - ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); - ss->osd_mesh = NULL; - } - if (ss->osd_vao != 0) { - glDeleteVertexArrays(1, &ss->osd_vao); - ss->osd_vao = 0; - } -} - -void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]) -{ - int i; - BLI_assert(ss->skip_grids == true); - if (ss->osd_num_coarse_coords == 0) { - zero_v3(r_min); - zero_v3(r_max); - } - for (i = 0; i < ss->osd_num_coarse_coords; i++) { - /* Coarse coordinates has normals interleaved into the array. */ - DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max); - } -} - -/* ** Delayed delete routines ** */ - -typedef struct OsdDeletePendingItem { - struct OsdDeletePendingItem *next, *prev; - OpenSubdiv_GLMesh *osd_mesh; - unsigned int vao; -} OsdDeletePendingItem; - -static SpinLock delete_spin; -static ListBase delete_pool = {NULL, NULL}; - -static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh, unsigned int vao) -{ - OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem), - "opensubdiv delete entry"); - new_entry->osd_mesh = osd_mesh; - new_entry->vao = vao; - BLI_spin_lock(&delete_spin); - BLI_addtail(&delete_pool, new_entry); - BLI_spin_unlock(&delete_spin); -} - -void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh) -{ - if (BLI_thread_is_main()) { - openSubdiv_deleteOsdGLMesh(osd_mesh); - } - else { - delete_pending_push(osd_mesh, 0); - } -} - -void ccgSubSurf__delete_vertex_array(unsigned int vao) -{ - if (BLI_thread_is_main()) { - glDeleteVertexArrays(1, &vao); - } - else { - delete_pending_push(NULL, vao); - } -} - -void ccgSubSurf__delete_pending(void) -{ - OsdDeletePendingItem *entry; - BLI_assert(BLI_thread_is_main()); - BLI_spin_lock(&delete_spin); - for (entry = delete_pool.first; entry != NULL; entry = entry->next) { - if (entry->osd_mesh != NULL) { - openSubdiv_deleteOsdGLMesh(entry->osd_mesh); - } - if (entry->vao != 0) { - glDeleteVertexArrays(1, &entry->vao); - } - } - BLI_freelistN(&delete_pool); - BLI_spin_unlock(&delete_spin); -} - -void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs) -{ - ss->osd_subdiv_uvs = subdiv_uvs; -} - -/* ** Public API ** */ - -void BKE_subsurf_osd_init(void) -{ - openSubdiv_init(); - BLI_spin_init(&delete_spin); -} - -void BKE_subsurf_free_unused_buffers(void) -{ - ccgSubSurf__delete_pending(); -} - -void BKE_subsurf_osd_cleanup(void) -{ - openSubdiv_cleanup(); - ccgSubSurf__delete_pending(); - BLI_spin_end(&delete_spin); -} - -#endif /* WITH_OPENSUBDIV */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c deleted file mode 100644 index 16766d52e57..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c +++ /dev/null @@ -1,777 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup bke - */ - -#ifdef WITH_OPENSUBDIV - -# include <stdlib.h> - -# include "BLI_sys_types.h" // for intptr_t support -# include "MEM_guardedalloc.h" - -# include "BLI_math.h" -# include "BLI_utildefines.h" /* for BLI_assert */ - -# include "CCGSubSurf.h" -# include "CCGSubSurf_intern.h" - -# include "BKE_DerivedMesh.h" -# include "BKE_mesh_mapping.h" - -# include "opensubdiv_capi.h" -# include "opensubdiv_converter_capi.h" - -/* Use mesh element mapping structures during conversion. - * Uses more memory but is much faster than naive algorithm. - */ -# define USE_MESH_ELEMENT_MAPPING - -/** - * Converter from DerivedMesh. - */ - -typedef struct ConvDMStorage { - CCGSubSurf *ss; - DerivedMesh *dm; - -# ifdef USE_MESH_ELEMENT_MAPPING - MeshElemMap *vert_edge_map, *vert_poly_map, *edge_poly_map; - int *vert_edge_mem, *vert_poly_mem, *edge_poly_mem; -# endif - - MVert *mvert; - MEdge *medge; - MLoop *mloop; - MPoly *mpoly; - - MeshIslandStore island_store; - int num_uvs; - float *uvs; - int *face_uvs; -} ConvDMStorage; - -static OpenSubdiv_SchemeType conv_dm_get_type(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - if (storage->ss->meshIFC.simpleSubdiv) { - return OSD_SCHEME_BILINEAR; - } - else { - return OSD_SCHEME_CATMARK; - } -} - -static OpenSubdiv_VtxBoundaryInterpolation conv_dm_get_vtx_boundary_interpolation( - const OpenSubdiv_Converter *UNUSED(converter)) -{ - return OSD_VTX_BOUNDARY_EDGE_ONLY; -} - -static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation( - const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - if (storage->ss->osd_subdiv_uvs) { - return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY; - } - return OSD_FVAR_LINEAR_INTERPOLATION_ALL; -} - -static bool conv_dm_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return true; -} - -static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - return dm->getNumPolys(dm); -} - -static int conv_dm_get_num_edges(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - return dm->getNumEdges(dm); -} - -static int conv_dm_get_num_verts(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - return dm->getNumVerts(dm); -} - -static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter, int face) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - return mpoly->totloop; -} - -static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter, - int face, - int *face_verts) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v; - } -} - -static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter, - int face, - int *face_edges) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e; - } -} - -static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter, - int edge, - int *edge_verts) -{ - ConvDMStorage *storage = converter->user_data; - const MEdge *medge = &storage->medge[edge]; - edge_verts[0] = medge->v1; - edge_verts[1] = medge->v2; -} - -static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &user_data->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->e == edge) { - num++; - break; - } - } - } - return num; -# else - return storage->edge_poly_map[edge].count; -# endif -} - -static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter, - int edge, - int *edge_faces) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &user_data->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->e == edge) { - edge_faces[num++] = poly; - break; - } - } - } -# else - memcpy(edge_faces, - storage->edge_poly_map[edge].indices, - sizeof(int) * storage->edge_poly_map[edge].count); -# endif -} - -static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge) -{ - ConvDMStorage *storage = converter->user_data; - CCGSubSurf *ss = storage->ss; - const MEdge *medge = storage->medge; - return (float)medge[edge].crease / 255.0f * ss->subdivLevels; -} - -static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, edge; - for (edge = 0; edge < dm->getNumEdges(dm); edge++) { - const MEdge *medge = &user_data->medge[edge]; - if (medge->v1 == vert || medge->v2 == vert) { - num++; - } - } - return num; -# else - return storage->vert_edge_map[vert].count; -# endif -} - -static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter, - int vert, - int *vert_edges) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, edge; - for (edge = 0; edge < dm->getNumEdges(dm); edge++) { - const MEdge *medge = &user_data->medge[edge]; - if (medge->v1 == vert || medge->v2 == vert) { - vert_edges[num++] = edge; - } - } -# else - memcpy(vert_edges, - storage->vert_edge_map[vert].indices, - sizeof(int) * storage->vert_edge_map[vert].count); -# endif -} - -static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &user_data->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->v == vert) { - num++; - break; - } - } - } - return num; -# else - return storage->vert_poly_map[vert].count; -# endif -} - -static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter, - int vert, - int *vert_faces) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &storage->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->v == vert) { - vert_faces[num++] = poly; - break; - } - } - } -# else - memcpy(vert_faces, - storage->vert_poly_map[vert].indices, - sizeof(int) * storage->vert_poly_map[vert].count); -# endif -} - -static bool conv_dm_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return false; -} - -static float conv_dm_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return 0.0f; -} - -static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); - return num_uv_layers; -} - -static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int layer) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - - const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer); - const int num_loops = dm->getNumLoops(dm); - - /* Initialize memory required for the operations. */ - if (storage->uvs == NULL) { - storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs"); - } - if (storage->face_uvs == NULL) { - storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs"); - } - - /* Calculate islands connectivity of the UVs. */ - BKE_mesh_calc_islands_loop_poly_uvmap(storage->mvert, - dm->getNumVerts(dm), - storage->medge, - dm->getNumEdges(dm), - storage->mpoly, - dm->getNumPolys(dm), - storage->mloop, - dm->getNumLoops(dm), - mloopuv, - &storage->island_store); - - /* Here we "weld" duplicated vertices from island to the same UV value. - * The idea here is that we need to pass individual islands to OpenSubdiv. - */ - storage->num_uvs = 0; - for (int island = 0; island < storage->island_store.islands_num; island++) { - MeshElemMap *island_poly_map = storage->island_store.islands[island]; - for (int poly = 0; poly < island_poly_map->count; poly++) { - int poly_index = island_poly_map->indices[poly]; - /* Within the same UV island we should share UV points across - * loops. Otherwise each poly will be subdivided individually - * which we don't really want. - */ - const MPoly *mpoly = &storage->mpoly[poly_index]; - for (int loop = 0; loop < mpoly->totloop; loop++) { - const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop]; - bool found = false; - /* TODO(sergey): Quite bad loop, which gives us O(N^2) - * complexity here. But how can we do it smarter, hopefully - * without requiring lots of additional memory. - */ - for (int i = 0; i < storage->num_uvs; i++) { - if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) { - storage->face_uvs[mpoly->loopstart + loop] = i; - found = true; - break; - } - } - if (!found) { - copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv); - storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs; - ++storage->num_uvs; - } - } - } - } -} - -static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - BKE_mesh_loop_islands_free(&storage->island_store); -} - -static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - return storage->num_uvs; -} - -static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter, - int face, - int corner) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - return storage->face_uvs[mpoly->loopstart + corner]; -} - -static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *user_data = converter->user_data; - if (user_data->uvs != NULL) { - MEM_freeN(user_data->uvs); - } - if (user_data->face_uvs != NULL) { - MEM_freeN(user_data->face_uvs); - } - -# ifdef USE_MESH_ELEMENT_MAPPING - MEM_freeN(user_data->vert_edge_map); - MEM_freeN(user_data->vert_edge_mem); - MEM_freeN(user_data->vert_poly_map); - MEM_freeN(user_data->vert_poly_mem); - MEM_freeN(user_data->edge_poly_map); - MEM_freeN(user_data->edge_poly_mem); -# endif - MEM_freeN(user_data); -} - -void ccgSubSurf_converter_setup_from_derivedmesh(CCGSubSurf *ss, - DerivedMesh *dm, - OpenSubdiv_Converter *converter) -{ - ConvDMStorage *user_data; - - converter->getSchemeType = conv_dm_get_type; - - converter->getVtxBoundaryInterpolation = conv_dm_get_vtx_boundary_interpolation; - converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation; - converter->specifiesFullTopology = conv_dm_specifies_full_topology; - - converter->getNumFaces = conv_dm_get_num_faces; - converter->getNumEdges = conv_dm_get_num_edges; - converter->getNumVertices = conv_dm_get_num_verts; - - converter->getNumFaceVertices = conv_dm_get_num_face_verts; - converter->getFaceVertices = conv_dm_get_face_verts; - converter->getFaceEdges = conv_dm_get_face_edges; - - converter->getEdgeVertices = conv_dm_get_edge_verts; - converter->getNumEdgeFaces = conv_dm_get_num_edge_faces; - converter->getEdgeFaces = conv_dm_get_edge_faces; - converter->getEdgeSharpness = conv_dm_get_edge_sharpness; - - converter->getNumVertexEdges = conv_dm_get_num_vert_edges; - converter->getVertexEdges = conv_dm_get_vert_edges; - converter->getNumVertexFaces = conv_dm_get_num_vert_faces; - converter->getVertexFaces = conv_dm_get_vert_faces; - converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex; - converter->getVertexSharpness = conv_dm_get_vertex_sharpness; - - converter->getNumUVLayers = conv_dm_get_num_uv_layers; - converter->precalcUVLayer = conv_dm_precalc_uv_layer; - converter->finishUVLayer = conv_dm_finish_uv_layer; - converter->getNumUVCoordinates = conv_dm_get_num_uvs; - converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index; - - user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__); - user_data->ss = ss; - user_data->dm = dm; - - user_data->mvert = dm->getVertArray(dm); - user_data->medge = dm->getEdgeArray(dm); - user_data->mloop = dm->getLoopArray(dm); - user_data->mpoly = dm->getPolyArray(dm); - - memset(&user_data->island_store, 0, sizeof(user_data->island_store)); - - user_data->uvs = NULL; - user_data->face_uvs = NULL; - - converter->freeUserData = conv_dm_free_user_data; - converter->user_data = user_data; - -# ifdef USE_MESH_ELEMENT_MAPPING - { - const MEdge *medge = dm->getEdgeArray(dm); - const MLoop *mloop = dm->getLoopArray(dm); - const MPoly *mpoly = dm->getPolyArray(dm); - const int num_vert = dm->getNumVerts(dm), num_edge = dm->getNumEdges(dm), - num_loop = dm->getNumLoops(dm), num_poly = dm->getNumPolys(dm); - BKE_mesh_vert_edge_map_create( - &user_data->vert_edge_map, &user_data->vert_edge_mem, medge, num_vert, num_edge); - - BKE_mesh_vert_poly_map_create(&user_data->vert_poly_map, - &user_data->vert_poly_mem, - mpoly, - mloop, - num_vert, - num_poly, - num_loop); - - BKE_mesh_edge_poly_map_create(&user_data->edge_poly_map, - &user_data->edge_poly_mem, - medge, - num_edge, - mpoly, - num_poly, - mloop, - num_loop); - } -# endif /* USE_MESH_ELEMENT_MAPPING */ -} - -/** - * Converter from CCGSubSurf - */ - -static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - if (ss->meshIFC.simpleSubdiv) { - return OSD_SCHEME_BILINEAR; - } - else { - return OSD_SCHEME_CATMARK; - } -} - -static OpenSubdiv_VtxBoundaryInterpolation conv_ccg_get_vtx_boundary_interpolation( - const OpenSubdiv_Converter *UNUSED(converter)) -{ - return OSD_VTX_BOUNDARY_EDGE_ONLY; -} - -static OpenSubdiv_FVarLinearInterpolation conv_ccg_get_fvar_linear_interpolation( - const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - if (ss->osd_subdiv_uvs) { - return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY; - } - return OSD_FVAR_LINEAR_INTERPOLATION_ALL; -} - -static bool conv_ccg_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return true; -} - -static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - return ss->fMap->numEntries; -} - -static int conv_ccg_get_num_edges(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - return ss->eMap->numEntries; -} - -static int conv_ccg_get_num_verts(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - return ss->vMap->numEntries; -} - -static int conv_ccg_get_num_face_verts(const OpenSubdiv_Converter *converter, int face) -{ - CCGSubSurf *ss = converter->user_data; - CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face)); - return ccgSubSurf_getFaceNumVerts(ccg_face); -} - -static void conv_ccg_get_face_verts(const OpenSubdiv_Converter *converter, - int face, - int *face_verts) -{ - CCGSubSurf *ss = converter->user_data; - CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face)); - int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face); - int loop; - for (loop = 0; loop < num_face_verts; loop++) { - CCGVert *ccg_vert = ccgSubSurf_getFaceVert(ccg_face, loop); - face_verts[loop] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert)); - } -} - -static void conv_ccg_get_face_edges(const OpenSubdiv_Converter *converter, - int face, - int *face_edges) -{ - CCGSubSurf *ss = converter->user_data; - CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face)); - int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face); - int loop; - for (loop = 0; loop < num_face_verts; loop++) { - CCGEdge *ccg_edge = ccgSubSurf_getFaceEdge(ccg_face, loop); - face_edges[loop] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - } -} - -static void conv_ccg_get_edge_verts(const OpenSubdiv_Converter *converter, - int edge, - int *edge_verts) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - CCGVert *ccg_vert0 = ccgSubSurf_getEdgeVert0(ccg_edge); - CCGVert *ccg_vert1 = ccgSubSurf_getEdgeVert1(ccg_edge); - edge_verts[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert0)); - edge_verts[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1)); -} - -static int conv_ccg_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - return ccgSubSurf_getEdgeNumFaces(ccg_edge); -} - -static void conv_ccg_get_edge_faces(const OpenSubdiv_Converter *converter, - int edge, - int *edge_faces) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - int num_edge_faces = ccgSubSurf_getEdgeNumFaces(ccg_edge); - int face; - for (face = 0; face < num_edge_faces; face++) { - CCGFace *ccg_face = ccgSubSurf_getEdgeFace(ccg_edge, face); - edge_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face)); - } -} - -static float conv_ccg_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - /* TODO(sergey): Multiply by subdivision level once CPU evaluator - * is switched to uniform subdivision type. - */ - return ccg_edge->crease; -} - -static int conv_ccg_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - return ccgSubSurf_getVertNumEdges(ccg_vert); -} - -static void conv_ccg_get_vert_edges(const OpenSubdiv_Converter *converter, - int vert, - int *vert_edges) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - int num_vert_edges = ccgSubSurf_getVertNumEdges(ccg_vert); - int edge; - for (edge = 0; edge < num_vert_edges; edge++) { - CCGEdge *ccg_edge = ccgSubSurf_getVertEdge(ccg_vert, edge); - vert_edges[edge] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - } -} - -static int conv_ccg_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - return ccgSubSurf_getVertNumFaces(ccg_vert); -} - -static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter, - int vert, - int *vert_faces) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - int num_vert_faces = ccgSubSurf_getVertNumFaces(ccg_vert); - int face; - for (face = 0; face < num_vert_faces; face++) { - CCGFace *ccg_face = ccgSubSurf_getVertFace(ccg_vert, face); - vert_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face)); - } -} - -static bool conv_ccg_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return false; -} - -static float conv_ccg_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return 0.0f; -} - -static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return 0; -} - -static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(layer)) -{ -} - -static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter)) -{ -} - -static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return 0; -} - -static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(face), - int UNUSED(corner_)) -{ - return 0; -} - -void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter) -{ - converter->getSchemeType = conv_ccg_get_bilinear_type; - - converter->getVtxBoundaryInterpolation = conv_ccg_get_vtx_boundary_interpolation; - converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation; - converter->specifiesFullTopology = conv_ccg_specifies_full_topology; - - converter->getNumFaces = conv_ccg_get_num_faces; - converter->getNumEdges = conv_ccg_get_num_edges; - converter->getNumVertices = conv_ccg_get_num_verts; - - converter->getNumFaceVertices = conv_ccg_get_num_face_verts; - converter->getFaceVertices = conv_ccg_get_face_verts; - converter->getFaceEdges = conv_ccg_get_face_edges; - - converter->getEdgeVertices = conv_ccg_get_edge_verts; - converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces; - converter->getEdgeFaces = conv_ccg_get_edge_faces; - converter->getEdgeSharpness = conv_ccg_get_edge_sharpness; - - converter->getNumVertexEdges = conv_ccg_get_num_vert_edges; - converter->getVertexEdges = conv_ccg_get_vert_edges; - converter->getNumVertexFaces = conv_ccg_get_num_vert_faces; - converter->getVertexFaces = conv_ccg_get_vert_faces; - converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex; - converter->getVertexSharpness = conv_ccg_get_vertex_sharpness; - - converter->getNumUVLayers = conv_ccg_get_num_uv_layers; - converter->precalcUVLayer = conv_ccg_precalc_uv_layer; - converter->finishUVLayer = conv_ccg_finish_uv_layer; - converter->getNumUVCoordinates = conv_ccg_get_num_uvs; - converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index; - - converter->freeUserData = NULL; - converter->user_data = ss; -} - -void ccgSubSurf_converter_free(struct OpenSubdiv_Converter *converter) -{ - if (converter->freeUserData) { - converter->freeUserData(converter); - } -} - -#endif /* WITH_OPENSUBDIV */ diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index b3893d8600f..8f820a873fe 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -90,6 +90,8 @@ static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; static void mesh_init_origspace(Mesh *mesh); +static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, + const CustomData_MeshMasks *final_datamask); /* -------------------------------------------------------------------- */ @@ -861,6 +863,16 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval) mesh_eval->edit_mesh = mesh_input->edit_mesh; } +void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval, + const CustomData_MeshMasks *cd_mask_finalize) +{ + 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); + } + BLI_assert(me_eval->runtime.wrapper_type_finalize == 0); +} + static void mesh_calc_modifiers(struct Depsgraph *depsgraph, Scene *scene, Object *ob, @@ -1391,11 +1403,16 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev return true; } -static void editbmesh_calc_modifier_final_normals(const Mesh *mesh_input, - const CustomData_MeshMasks *final_datamask, - Mesh *mesh_final) +static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, + const CustomData_MeshMasks *final_datamask) { - const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || + 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); + return; + } + + const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 || (final_datamask->lmask & CD_MASK_NORMAL) != 0); /* Some modifiers may need this info from their target (other) object, * simpler to generate it here as well. */ @@ -1501,7 +1518,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* Evaluate modifiers up to certain index to get the mesh cage. */ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1); if (r_cage && cageIndex == -1) { - mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( + mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords( em_input, &final_datamask, NULL, mesh_input); } @@ -1574,12 +1591,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } } else { - mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input); - ASSERT_IS_VALID_MESH(mesh_final); - - if (deformed_verts) { - BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); - } + mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords( + em_input, NULL, deformed_verts, mesh_input); + deformed_verts = NULL; } /* create an orco derivedmesh in parallel */ @@ -1657,7 +1671,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, BKE_mesh_runtime_ensure_edit_data(me_orig); me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts); } - mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( + mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords( em_input, &final_datamask, deformed_verts ? MEM_dupallocN(deformed_verts) : NULL, @@ -1689,7 +1703,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } else { /* this is just a copy of the editmesh, no need to calc normals */ - mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap( + mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords( em_input, &final_datamask, deformed_verts, mesh_input); deformed_verts = NULL; } @@ -1700,6 +1714,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* Add orco coordinates to final and deformed mesh if requested. */ if (final_datamask.vmask & CD_MASK_ORCO) { + /* FIXME(Campbell): avoid the need to convert to mesh data just to add an orco layer. */ + BKE_mesh_wrapper_ensure_mdata(mesh_final); + add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO); } @@ -1707,10 +1724,15 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, BKE_id_free(NULL, mesh_orco); } + /* Ensure normals calculation below is correct. */ + BLI_assert((mesh_input->flag & ME_AUTOSMOOTH) == (mesh_final->flag & ME_AUTOSMOOTH)); + BLI_assert(mesh_input->smoothresh == mesh_final->smoothresh); + BLI_assert(mesh_input->smoothresh == mesh_cage->smoothresh); + /* Compute normals. */ - editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_final); + editbmesh_calc_modifier_final_normals(mesh_final, &final_datamask); if (mesh_cage && (mesh_cage != mesh_final)) { - editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_cage); + editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask); } /* Return final mesh. */ @@ -1798,9 +1820,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph, } } - if (mesh_eval != NULL) { - mesh_runtime_check_normals_valid(mesh_eval); - } + mesh_runtime_check_normals_valid(mesh_eval); mesh_build_extra_data(depsgraph, ob, mesh_eval); } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 4f51e23496c..ca58b69689c 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -52,6 +52,7 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_object.h" @@ -154,6 +155,19 @@ static void action_free_data(struct ID *id) BLI_freelistN(&action->markers); } +static void action_foreach_id(ID *id, LibraryForeachIDData *data) +{ + bAction *act = (bAction *)id; + + LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { + BKE_fcurve_foreach_id(fcu, data); + } + + LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { + BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP); + } +} + IDTypeInfo IDType_ID_AC = { .id_code = ID_AC, .id_filter = FILTER_ID_AC, @@ -168,6 +182,7 @@ IDTypeInfo IDType_ID_AC = { .copy_data = action_copy_data, .free_data = action_free_data, .make_local = NULL, + .foreach_id = action_foreach_id, }; /* ***************** Library data level operations on action ************** */ diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 02b7763a9b4..726753a4e70 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -32,6 +32,7 @@ #include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_nla.h" #include "BKE_node.h" @@ -289,6 +290,24 @@ bool BKE_animdata_id_is_animated(const struct ID *id) !BLI_listbase_is_empty(&adt->overrides); } +/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of + * `IDTypeInfo` structure). */ +void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data) +{ + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + BKE_fcurve_foreach_id(fcu, data); + } + + BKE_LIB_FOREACHID_PROCESS(data, adt->action, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, adt->tmpact, IDWALK_CB_USER); + + LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) { + LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) { + BKE_nla_strip_foreach_id(nla_strip, data); + } + } +} + /* Copying -------------------------------------------- */ /** diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 06a97fc3826..36921bd2662 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -67,6 +67,7 @@ #include "BKE_scene.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "BIK_api.h" @@ -500,14 +501,21 @@ static void armature_refresh_layer_used_recursive(bArmature *arm, ListBase *bone } } -/* Update the layers_used variable after bones are moved between layer - * NOTE: Used to be done in drawing code in 2.7, but that won't work with - * Copy-on-Write, as drawing uses evaluated copies. - */ -void BKE_armature_refresh_layer_used(bArmature *arm) +void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm) { + if (arm->edbo != NULL) { + /* Don't perform this update when the armature is in edit mode. In that case it should be + * handled by ED_armature_edit_refresh_layer_used(). */ + return; + } + arm->layer_used = 0; armature_refresh_layer_used_recursive(arm, &arm->bonebase); + + if (depsgraph == NULL || DEG_is_active(depsgraph)) { + bArmature *arm_orig = (bArmature *)DEG_get_original_id(&arm->id); + arm_orig->layer_used = arm->layer_used; + } } /* Finds the best possible extension to the name on a particular axis. (For renaming, check for diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index b3a4de02451..1fb4ca95c93 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -66,7 +66,7 @@ Global G; UserDef U; -char versionstr[48] = ""; +static char blender_version_string[48] = ""; /* ********** free ********** */ @@ -102,26 +102,43 @@ void BKE_blender_free(void) free_nodesystem(); } -void BKE_blender_version_string(char *version_str, - size_t maxncpy, - short version, - short subversion, - bool v_prefix, - bool include_subversion) +static void blender_version_init() { - const char *prefix = v_prefix ? "v" : ""; - - if (include_subversion && subversion > 0) { - BLI_snprintf( - version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion); + const char *version_cycle = ""; + if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) { + version_cycle = " Alpha"; + } + else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) { + version_cycle = " Beta"; + } + else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) { + version_cycle = " Release Candidate"; + } + else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { + version_cycle = ""; } else { - BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100); + BLI_assert(!"Invalid Blender version cycle"); } + + BLI_snprintf(blender_version_string, + ARRAY_SIZE(blender_version_string), + "%d.%02d.%d%s", + BLENDER_VERSION / 100, + BLENDER_VERSION % 100, + BLENDER_VERSION_PATCH, + version_cycle); +} + +const char *BKE_blender_version_string() +{ + return blender_version_string; } void BKE_blender_globals_init(void) { + blender_version_init(); + memset(&G, 0, sizeof(Global)); U.savetime = 1; @@ -130,9 +147,6 @@ void BKE_blender_globals_init(void) strcpy(G.ima, "//"); - BKE_blender_version_string( - versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true); - #ifndef WITH_PYTHON_SECURITY /* default */ G.f |= G_FLAG_SCRIPT_AUTOEXEC; #else diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 13dcc7b06f6..ef474022f19 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -415,8 +415,9 @@ static void setup_app_blend_file_data(bContext *C, static int handle_subversion_warning(Main *main, ReportList *reports) { - if (main->minversionfile > BLENDER_VERSION || - (main->minversionfile == BLENDER_VERSION && main->minsubversionfile > BLENDER_SUBVERSION)) { + if (main->minversionfile > BLENDER_FILE_VERSION || + (main->minversionfile == BLENDER_FILE_VERSION && + main->minsubversionfile > BLENDER_FILE_SUBVERSION)) { BKE_reportf(reports, RPT_ERROR, "File written by newer Blender binary (%d.%d), expect loss of data!", diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2d795136b05..133917e441c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -1092,7 +1092,7 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r bool r_new = false; Paint *paint = &ts->gp_paint->paint; - + Brush *brush_prev = paint->brush; Brush *brush, *deft_draw; /* Airbrush brush. */ brush = gpencil_brush_ensure(bmain, ts, "Airbrush", OB_MODE_PAINT_GPENCIL, &r_new); @@ -1180,7 +1180,9 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r } /* Set default Draw brush. */ - BKE_paint_brush_set(paint, deft_draw); + if (reset || brush_prev == NULL) { + BKE_paint_brush_set(paint, deft_draw); + } } /* Create a set of grease pencil Vertex Paint presets. */ @@ -1189,7 +1191,7 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool bool r_new = false; Paint *vertexpaint = &ts->gp_vertexpaint->paint; - + Brush *brush_prev = vertexpaint->brush; Brush *brush, *deft_vertex; /* Vertex Draw brush. */ brush = gpencil_brush_ensure(bmain, ts, "Vertex Draw", OB_MODE_VERTEX_GPENCIL, &r_new); @@ -1220,7 +1222,9 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool } /* Set default Vertex brush. */ - BKE_paint_brush_set(vertexpaint, deft_vertex); + if (reset || brush_prev == NULL) { + BKE_paint_brush_set(vertexpaint, deft_vertex); + } } /* Create a set of grease pencil Sculpt Paint presets. */ @@ -1229,6 +1233,7 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool bool r_new = false; Paint *sculptpaint = &ts->gp_sculptpaint->paint; + Brush *brush_prev = sculptpaint->brush; Brush *brush, *deft_sculpt; /* Smooth brush. */ @@ -1287,7 +1292,9 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool } /* Set default brush. */ - BKE_paint_brush_set(sculptpaint, deft_sculpt); + if (reset || brush_prev == NULL) { + BKE_paint_brush_set(sculptpaint, deft_sculpt); + } } /* Create a set of grease pencil Weight Paint presets. */ @@ -1296,7 +1303,7 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool bool r_new = false; Paint *weightpaint = &ts->gp_weightpaint->paint; - + Brush *brush_prev = weightpaint->brush; Brush *brush, *deft_weight; /* Vertex Draw brush. */ brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL, &r_new); @@ -1306,7 +1313,9 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool deft_weight = brush; /* save default brush. */ /* Set default brush. */ - BKE_paint_brush_set(weightpaint, deft_weight); + if (reset || brush_prev == NULL) { + BKE_paint_brush_set(weightpaint, deft_weight); + } } struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode) diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index d23b643ce70..da9dab36044 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -97,6 +97,7 @@ IDTypeInfo IDType_ID_CF = { .copy_data = cache_file_copy_data, .free_data = cache_file_free_data, .make_local = NULL, + .foreach_id = NULL, }; /* TODO: make this per cache file to avoid global locks. */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 67516d014bd..a28cc73cb94 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -34,6 +34,7 @@ #include "BKE_idtype.h" #include "BKE_layer.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_object.h" @@ -128,6 +129,28 @@ static void collection_free_data(ID *id) BKE_collection_object_cache_free(collection); } +static void collection_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Collection *collection = (Collection *)id; + + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + BKE_LIB_FOREACHID_PROCESS(data, cob->ob, IDWALK_CB_USER); + } + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + BKE_LIB_FOREACHID_PROCESS(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER); + } + LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) { + /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad + * anyway... */ + const int cb_flag = ((parent->collection != NULL && + (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS( + data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag); + } +} + IDTypeInfo IDType_ID_GR = { .id_code = ID_GR, .id_filter = FILTER_ID_GR, @@ -142,6 +165,7 @@ IDTypeInfo IDType_ID_GR = { .copy_data = collection_copy_data, .free_data = collection_free_data, .make_local = NULL, + .foreach_id = collection_foreach_id, }; /***************************** Add Collection *******************************/ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 679fe703b13..050e8d434ae 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -951,6 +951,10 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar /* If requested, compute the inverse matrix from the computed parent matrix. */ if (data->flag & CHILDOF_SET_INVERSE) { invert_m4_m4(data->invmat, parmat); + if (cob->pchan != NULL) { + mul_m4_series(data->invmat, data->invmat, cob->ob->obmat); + } + copy_m4_m4(inverse_matrix, data->invmat); data->flag &= ~CHILDOF_SET_INVERSE; @@ -4691,7 +4695,7 @@ static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *co MovieTrackingTrack *track = context->track; MovieTrackingObject *tracking_object = context->tracking_object; - /* Matrix of the object which is being solved prior to this contraint. */ + /* Matrix of the object which is being solved prior to this constraint. */ float obmat[4][4]; copy_m4_m4(obmat, cob->matrix); @@ -4716,7 +4720,7 @@ static void followtrack_evaluate_using_3d_position_camera(FollowTrackContext *co Object *camera_object = context->camera_object; MovieTrackingTrack *track = context->track; - /* Matrix of the object which is being solved prior to this contraint. */ + /* Matrix of the object which is being solved prior to this constraint. */ float obmat[4][4]; copy_m4_m4(obmat, cob->matrix); diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index f4acbdca772..6c8438e478e 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -293,7 +293,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra cd_mask_extra = datamasks->mask; BLI_linklist_free((LinkNode *)datamasks, NULL); - me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &cd_mask_extra, NULL, me_input); + me = BKE_mesh_wrapper_from_editmesh_with_coords(em, &cd_mask_extra, NULL, me_input); deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts); defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats"); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0798bc95797..e67cf8573f3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -4485,7 +4485,7 @@ void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length } } -void BKE_nurbList_flag_set(ListBase *editnurb, short flag) +void BKE_nurbList_flag_set(ListBase *editnurb, short flag, bool set) { Nurb *nu; BezTriple *bezt; @@ -4497,7 +4497,16 @@ void BKE_nurbList_flag_set(ListBase *editnurb, short flag) a = nu->pntsu; bezt = nu->bezt; while (a--) { - bezt->f1 = bezt->f2 = bezt->f3 = flag; + if (set) { + bezt->f1 |= flag; + bezt->f2 |= flag; + bezt->f3 |= flag; + } + else { + bezt->f1 &= ~flag; + bezt->f2 &= ~flag; + bezt->f3 &= ~flag; + } bezt++; } } @@ -4505,13 +4514,47 @@ void BKE_nurbList_flag_set(ListBase *editnurb, short flag) a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a--) { - bp->f1 = flag; + SET_FLAG_FROM_TEST(bp->f1, set, flag); bp++; } } } } +/** + * Set \a flag for every point that already has \a from_flag set. + */ +bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, short from_flag, short flag) +{ + bool changed = false; + + for (Nurb *nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + for (int i = 0; i < nu->pntsu; i++) { + BezTriple *bezt = &nu->bezt[i]; + int old_f1 = bezt->f1, old_f2 = bezt->f2, old_f3 = bezt->f3; + + SET_FLAG_FROM_TEST(bezt->f1, bezt->f1 & from_flag, flag); + SET_FLAG_FROM_TEST(bezt->f2, bezt->f2 & from_flag, flag); + SET_FLAG_FROM_TEST(bezt->f3, bezt->f3 & from_flag, flag); + + changed |= (old_f1 != bezt->f1) || (old_f2 != bezt->f2) || (old_f3 != bezt->f3); + } + } + else { + for (int i = 0; i < nu->pntsu * nu->pntsv; i++) { + BPoint *bp = &nu->bp[i]; + int old_f1 = bp->f1; + + SET_FLAG_FROM_TEST(bp->f1, bp->f1 & from_flag, flag); + changed |= (old_f1 != bp->f1); + } + } + } + + return changed; +} + void BKE_nurb_direction_switch(Nurb *nu) { BezTriple *bezt1, *bezt2; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 8c47401cbc3..b0007c2a598 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -699,6 +699,24 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int return size; } +static void layerInterp_paint_mask( + const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +{ + float mask = 0.0f; + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { + float weight = weights ? weights[i] : 1.0f; + const float *src = sources[i]; + if (sub_weights) { + mask += (*src) * (*sub_weight) * weight; + sub_weight++; + } + else { + mask += (*src) * weight; + } + } + *(float *)dest = mask; +} static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) { @@ -1321,6 +1339,132 @@ static void layerDefault_fmap(void *data, int count) } } +static void layerCopyValue_propcol(const void *source, + void *dest, + const int mixmode, + const float mixfactor) +{ + const MPropCol *m1 = source; + MPropCol *m2 = dest; + float tmp_col[4]; + + if (ELEM(mixmode, + CDT_MIX_NOMIX, + CDT_MIX_REPLACE_ABOVE_THRESHOLD, + CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* Modes that do a full copy or nothing. */ + if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) { + /* TODO: Check for a real valid way to get 'factor' value of our dest color? */ + const float f = (m2->col[0] + m2->col[1] + m2->col[2]) / 3.0f; + if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) { + return; /* Do Nothing! */ + } + else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) { + return; /* Do Nothing! */ + } + } + copy_v3_v3(m2->col, m1->col); + } + else { /* Modes that support 'real' mix factor. */ + if (mixmode == CDT_MIX_MIX) { + blend_color_mix_float(tmp_col, m2->col, m1->col); + } + else if (mixmode == CDT_MIX_ADD) { + blend_color_add_float(tmp_col, m2->col, m1->col); + } + else if (mixmode == CDT_MIX_SUB) { + blend_color_sub_float(tmp_col, m2->col, m1->col); + } + else if (mixmode == CDT_MIX_MUL) { + blend_color_mul_float(tmp_col, m2->col, m1->col); + } + else { + memcpy(tmp_col, m1->col, sizeof(tmp_col)); + } + blend_color_interpolate_float(m2->col, m2->col, tmp_col, mixfactor); + + copy_v3_v3(m2->col, m1->col); + } + m2->col[3] = m1->col[3]; +} + +static bool layerEqual_propcol(const void *data1, const void *data2) +{ + const MPropCol *m1 = data1, *m2 = data2; + float tot = 0; + + for (int i = 0; i < 4; i++) { + float c = (m1->col[i] - m2->col[i]); + tot += c * c; + } + + return tot < 0.001f; +} + +static void layerMultiply_propcol(void *data, float fac) +{ + MPropCol *m = data; + mul_v4_fl(m->col, fac); +} + +static void layerAdd_propcol(void *data1, const void *data2) +{ + MPropCol *m = data1; + const MPropCol *m2 = data2; + add_v4_v4(m->col, m2->col); +} + +static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax) +{ + const MPropCol *m = data; + MPropCol *min = vmin, *max = vmax; + minmax_v4v4_v4(min->col, max->col, m->col); +} + +static void layerInitMinMax_propcol(void *vmin, void *vmax) +{ + MPropCol *min = vmin, *max = vmax; + + copy_v4_fl(min->col, FLT_MAX); + copy_v4_fl(max->col, FLT_MIN); +} + +static void layerDefault_propcol(void *data, int count) +{ + /* Default to white, full alpha. */ + MPropCol default_propcol = {{1.0f, 1.0f, 1.0f, 1.0f}}; + MPropCol *pcol = (MPropCol *)data; + int i; + for (i = 0; i < count; i++) { + copy_v4_v4(pcol[i].col, default_propcol.col); + } +} + +static void layerInterp_propcol( + const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +{ + MPropCol *mc = dest; + float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { + float weight = weights ? weights[i] : 1.0f; + const MPropCol *src = sources[i]; + if (sub_weights) { + madd_v4_v4fl(col, src->col, (*sub_weight) * weight); + sub_weight++; + } + else { + madd_v4_v4fl(col, src->col, weight); + } + } + copy_v4_v4(mc->col, col); +} + +static int layerMaxNum_propcol(void) +{ + return MAX_MCOL; +} + static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 0: CD_MVERT */ {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL}, @@ -1595,7 +1739,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* END BMESH ONLY */ /* 34: CD_PAINT_MASK */ - {sizeof(float), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float), "", 0, NULL, NULL, NULL, layerInterp_paint_mask, NULL, NULL}, /* 35: CD_GRID_PAINT_MASK */ {sizeof(GridPaintMask), "GridPaintMask", @@ -1636,7 +1780,27 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(HairCurve), "HairCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL}, /* 46: CD_HAIR_MAPPING */ {sizeof(HairMapping), "HairMapping", 1, NULL, NULL, NULL, NULL, NULL, NULL}, -}; + /* 47: CD_PROP_COL */ + {sizeof(MPropCol), + "MPropCol", + 1, + N_("Col"), + NULL, + NULL, + layerInterp_propcol, + NULL, + layerDefault_propcol, + NULL, + layerEqual_propcol, + layerMultiply_propcol, + layerInitMinMax_propcol, + layerAdd_propcol, + layerDoMinMax_propcol, + layerCopyValue_propcol, + NULL, + NULL, + NULL, + layerMaxNum_propcol}}; static const char *LAYERTYPENAMES[CD_NUMTYPES] = { /* 0-4 */ "CDMVert", @@ -1688,6 +1852,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDHairCurve", "CDHairMapping", "CDPoint", + "CDPropCol", }; const CustomData_MeshMasks CD_MASK_BAREMESH = { diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index d73f92b6073..a3e1eeb89c7 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -1134,17 +1134,18 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, if (r_final) { if (force_mesh_conversion && !modified) { - /* XXX 2.8 : This is a workaround for by some deeper technical depts: + /* XXX 2.8 : This is a workaround for by some deeper technical debts: * - DRW Batch cache is stored inside the ob->data. * - Curve data is not COWed for instances that use different modifiers. - * This can causes the modifiers to be applied on all user of the same datablock (see T71055) + * This can causes the modifiers to be applied on all user of the same data-block + * (see T71055) * * The easy workaround is to force to generate a Mesh that will be used for display data * since a Mesh output is already used for generative modifiers. * However it does not fix problems with actual edit data still being shared. * - * The right solution would be to COW the Curve data block at the input of the modifer stack - * just like what the mesh modifier does. + * The right solution would be to COW the Curve data block at the input of the modifier + * stack just like what the mesh modifier does. * */ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase); } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 79d9a40f06b..dae8a59fe43 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2704,15 +2704,16 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa } } + const int final_tri_index = tempPoints[final_index].tri_index; /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */ - if (tempPoints[final_index].tri_index != target_tri) { + if (final_tri_index != target_tri && final_tri_index != -1) { /* Check if it's close enough to likely touch the intended triangle. Any triangle * becomes thinner than a pixel at its vertices, so robustness requires some margin. */ const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h}; const float threshold = square_f(0.7f) / (w * h); - if (dist_squared_to_looptri_uv_edges( - mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold) { + if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, final_tri_index, final_pt) > + threshold) { continue; } } @@ -4646,9 +4647,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, return 1; } - /* begin thread safe malloc */ - BLI_threaded_malloc_begin(); - /* only continue if particle bb is close enough to canvas bb */ if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) { int c_index; @@ -4684,7 +4682,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, &settings); } } - BLI_threaded_malloc_end(); BLI_kdtree_3d_free(tree); return 1; diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 5aaae74e670..c4160d6d253 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -32,6 +32,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_iterators.h" @@ -266,7 +267,7 @@ BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em) float min[3], max[3]; INIT_MINMAX(min, max); if (em->mesh_eval_cage) { - BKE_mesh_minmax(em->mesh_eval_cage, min, max); + BKE_mesh_wrapper_minmax(em->mesh_eval_cage, min, max); } em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage"); diff --git a/source/blender/blenkernel/intern/editmesh_cache.c b/source/blender/blenkernel/intern/editmesh_cache.c index 8d3f1e84bcd..5017a48d14e 100644 --- a/source/blender/blenkernel/intern/editmesh_cache.c +++ b/source/blender/blenkernel/intern/editmesh_cache.c @@ -22,11 +22,17 @@ #include "MEM_guardedalloc.h" +#include "BLI_math_vector.h" + #include "DNA_mesh_types.h" #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" /* own include */ +/* -------------------------------------------------------------------- */ +/** \name Ensure Data (derived from coords) + * \{ */ + void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd) { if (!(emd->vertexCos && (emd->polyNos == NULL))) { @@ -112,3 +118,41 @@ void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd) emd->polyCos = (const float(*)[3])polyCos; } + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Calculate Min/Max + * \{ */ + +bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em, + struct EditMeshData *emd, + float min[3], + float max[3]) +{ + BMesh *bm = em->bm; + BMVert *eve; + BMIter iter; + int i; + + if (bm->totvert) { + if (emd->vertexCos) { + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + minmax_v3v3_v3(min, max, emd->vertexCos[i]); + } + } + else { + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + minmax_v3v3_v3(min, max, eve->co); + } + } + return true; + } + else { + zero_v3(min); + zero_v3(max); + return false; + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5d2207b5b80..c0843e049f3 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -31,6 +31,7 @@ #include "DNA_anim_types.h" #include "DNA_object_types.h" +#include "DNA_text_types.h" #include "BLI_blenlib.h" #include "BLI_easing.h" @@ -43,6 +44,8 @@ #include "BKE_fcurve.h" #include "BKE_fcurve_driver.h" #include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_lib_query.h" #include "BKE_nla.h" #include "RNA_access.h" @@ -158,6 +161,38 @@ void copy_fcurves(ListBase *dst, ListBase *src) } } +/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of + * `IDTypeInfo` structure). */ +void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data) +{ + ChannelDriver *driver = fcu->driver; + + if (driver != NULL) { + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + /* only used targets */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + BKE_LIB_FOREACHID_PROCESS_ID(data, dtar->id, IDWALK_CB_NOP); + } + DRIVER_TARGETS_LOOPER_END; + } + } + + LISTBASE_FOREACH (FModifier *, fcm, &fcu->modifiers) { + switch (fcm->type) { + case FMODIFIER_TYPE_PYTHON: { + FMod_Python *fcm_py = (FMod_Python *)fcm->data; + BKE_LIB_FOREACHID_PROCESS(data, fcm_py->script, IDWALK_CB_NOP); + + IDP_foreach_property(fcm_py->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data); + break; + } + } + } +} + /* ----------------- Finding F-Curves -------------------------- */ /* high level function to get an fcurve from C without having the rna */ @@ -1447,8 +1482,8 @@ static float fcurve_eval_keyframes_extrapolate( return endpoint_bezt->vec[1][1] - (fac * dx); } - /* Use the gradient of the second handle (later) of neighbour to calculate the gradient and thus - * the value of the curve at evaltime */ + /* Use the gradient of the second handle (later) of neighbor to calculate the gradient and thus + * the value of the curve at evaluation time. */ int handle = direction_to_neighbor > 0 ? 0 : 2; float dx = endpoint_bezt->vec[1][0] - evaltime; float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0]; diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index fddc6b5e0ee..b75592836e0 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -3306,6 +3306,16 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj /* Biggest dimension will be used for upscaling. */ float max_size = MAX3(size[0], size[1], size[2]); + float co_scale[3]; + co_scale[0] = max_size / ob->scale[0]; + co_scale[1] = max_size / ob->scale[1]; + co_scale[2] = max_size / ob->scale[2]; + + float co_offset[3]; + co_offset[0] = (mds->p0[0] + mds->p1[0]) / 2.0f; + co_offset[1] = (mds->p0[1] + mds->p1[1]) / 2.0f; + co_offset[2] = (mds->p0[2] + mds->p1[2]) / 2.0f; + /* Normals. */ normals = MEM_callocN(sizeof(short) * num_normals * 3, "Fluidmesh_tmp_normals"); @@ -3329,9 +3339,9 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj mverts->co[2] *= mds->dx / mds->mesh_scale; } - mverts->co[0] *= max_size / fabsf(ob->scale[0]); - mverts->co[1] *= max_size / fabsf(ob->scale[1]); - mverts->co[2] *= max_size / fabsf(ob->scale[2]); + mul_v3_v3(mverts->co, co_scale); + add_v3_v3(mverts->co, co_offset); + # ifdef DEBUG_PRINT /* Debugging: Print coordinates of vertices. */ printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n", @@ -3977,9 +3987,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } } if (!baking_data && !baking_noise && next_data && next_noise) { - /* TODO (sebbas): Confirm if this read call is really needed or not. - * Currently only important to load the shadow grid. */ - has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame); + /* Nothing to do here since we already loaded noise grids. */ } else { has_data = manta_read_data(mds->fluid, mmd, data_frame); @@ -4380,8 +4388,8 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *v } } -/* get smoke velocity and density at given coordinates - * returns fluid density or -1.0f if outside domain. */ +/* Get fluid velocity and density at given coordinates + * Returns fluid density or -1.0f if outside domain. */ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]) { FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); @@ -4390,16 +4398,15 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) { FluidDomainSettings *mds = mmd->domain; float time_mult = 25.f * DT_DEFAULT; + float size_mult = MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2]) / + mds->maxres; float vel_mag; - float *velX = manta_get_velocity_x(mds->fluid); - float *velY = manta_get_velocity_y(mds->fluid); - float *velZ = manta_get_velocity_z(mds->fluid); float density = 0.0f, fuel = 0.0f; float pos[3]; copy_v3_v3(pos, position); manta_pos_to_cell(mds, pos); - /* check if point is outside domain max bounds */ + /* Check if position is outside domain max bounds. */ if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) { return -1.0f; } @@ -4412,9 +4419,8 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]); pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]); - /* check if point is outside active area */ - if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS && - mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + /* Check if position is outside active area. */ + if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) { return 0.0f; } @@ -4423,21 +4429,22 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo } } - /* get interpolated velocity */ - velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] * - time_mult; - velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] * - time_mult; - velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] * - time_mult; + /* Get interpolated velocity at given position. */ + velocity[0] = BLI_voxel_sample_trilinear(manta_get_velocity_x(mds->fluid), mds->res, pos); + velocity[1] = BLI_voxel_sample_trilinear(manta_get_velocity_y(mds->fluid), mds->res, pos); + velocity[2] = BLI_voxel_sample_trilinear(manta_get_velocity_z(mds->fluid), mds->res, pos); + + /* Convert simulation units to Blender units. */ + mul_v3_fl(velocity, size_mult); + mul_v3_fl(velocity, time_mult); - /* convert velocity direction to global space */ + /* Convert velocity direction to global space. */ vel_mag = len_v3(velocity); mul_mat3_m4_v3(mds->obmat, velocity); normalize_v3(velocity); mul_v3_fl(velocity, vel_mag); - /* use max value of fuel or smoke density */ + /* Use max value of fuel or smoke density. */ density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos); if (manta_smoke_has_fuel(mds->fluid)) { fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos); @@ -4922,7 +4929,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) /* cache options */ mmd->domain->cache_frame_start = 1; - mmd->domain->cache_frame_end = 50; + mmd->domain->cache_frame_end = 250; mmd->domain->cache_frame_pause_data = 0; mmd->domain->cache_frame_pause_noise = 0; mmd->domain->cache_frame_pause_mesh = 0; diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 92eb6ea03e2..54f2492af93 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -134,6 +134,7 @@ IDTypeInfo IDType_ID_VF = { .copy_data = vfont_copy_data, .free_data = vfont_free_data, .make_local = NULL, + .foreach_id = NULL, }; /***************************** VFont *******************************/ diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index d0ca5cebdc5..7f65dfc2b51 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -55,6 +55,7 @@ #include "BKE_idtype.h" #include "BKE_image.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_paint.h" @@ -97,6 +98,19 @@ static void greasepencil_free_data(ID *id) BKE_gpencil_free((bGPdata *)id, true); } +static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data) +{ + bGPdata *gpencil = (bGPdata *)id; + /* materials */ + for (int i = 0; i < gpencil->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, gpencil->mat[i], IDWALK_CB_USER); + } + + LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) { + BKE_LIB_FOREACHID_PROCESS(data, gplayer->parent, IDWALK_CB_NOP); + } +} + IDTypeInfo IDType_ID_GD = { .id_code = ID_GD, .id_filter = FILTER_ID_GD, @@ -111,6 +125,7 @@ IDTypeInfo IDType_ID_GD = { .copy_data = greasepencil_copy_data, .free_data = greasepencil_free_data, .make_local = NULL, + .foreach_id = greasepencil_foreach_id, }; /* ************************************************** */ diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c index 808c0347a37..90761d24b73 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.c @@ -22,6 +22,7 @@ #include "DNA_defaults.h" #include "DNA_hair_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "BLI_listbase.h" @@ -48,50 +49,7 @@ /* Hair datablock */ -static void hair_random(Hair *hair) -{ - const int numpoints = 8; - - hair->totcurve = 500; - hair->totpoint = hair->totcurve * numpoints; - - CustomData_realloc(&hair->pdata, hair->totpoint); - CustomData_realloc(&hair->cdata, hair->totcurve); - BKE_hair_update_customdata_pointers(hair); - - RNG *rng = BLI_rng_new(0); - - for (int i = 0; i < hair->totcurve; i++) { - HairCurve *curve = &hair->curves[i]; - curve->firstpoint = i * numpoints; - curve->numpoints = numpoints; - - float theta = 2.0f * M_PI * BLI_rng_get_float(rng); - float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f); - - float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)}; - normalize_v3(no); - - float co[3]; - copy_v3_v3(co, no); - - float(*curve_co)[3] = hair->co + curve->firstpoint; - float *curve_radius = hair->radius + curve->firstpoint; - for (int key = 0; key < numpoints; key++) { - float t = key / (float)(numpoints - 1); - copy_v3_v3(curve_co[key], co); - curve_radius[key] = 0.02f * (1.0f - t); - - float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f, - 2.0f * BLI_rng_get_float(rng) - 1.0f, - 2.0f * BLI_rng_get_float(rng) - 1.0f}; - add_v3_v3(offset, no); - madd_v3_v3fl(co, offset, 1.0f / numpoints); - } - } - - BLI_rng_free(rng); -} +static void hair_random(Hair *hair); static void hair_init_data(ID *id) { @@ -111,15 +69,6 @@ static void hair_init_data(ID *id) hair_random(hair); } -void *BKE_hair_add(Main *bmain, const char *name) -{ - Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0); - - hair_init_data(&hair->id); - - return hair; -} - static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) { Hair *hair_dst = (Hair *)id_dst; @@ -134,18 +83,6 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co hair_dst->batch_cache = NULL; } -Hair *BKE_hair_copy(Main *bmain, const Hair *hair) -{ - Hair *hair_copy; - BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy); - return hair_copy; -} - -static void hair_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - static void hair_free_data(ID *id) { Hair *hair = (Hair *)id; @@ -159,6 +96,14 @@ static void hair_free_data(ID *id) MEM_SAFE_FREE(hair->mat); } +static void hair_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Hair *hair = (Hair *)id; + for (int i = 0; i < hair->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, hair->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_HA = { .id_code = ID_HA, .id_filter = FILTER_ID_HA, @@ -172,9 +117,71 @@ IDTypeInfo IDType_ID_HA = { .init_data = hair_init_data, .copy_data = hair_copy_data, .free_data = hair_free_data, - .make_local = hair_make_local, + .make_local = NULL, + .foreach_id = hair_foreach_id, }; +static void hair_random(Hair *hair) +{ + const int numpoints = 8; + + hair->totcurve = 500; + hair->totpoint = hair->totcurve * numpoints; + + CustomData_realloc(&hair->pdata, hair->totpoint); + CustomData_realloc(&hair->cdata, hair->totcurve); + BKE_hair_update_customdata_pointers(hair); + + RNG *rng = BLI_rng_new(0); + + for (int i = 0; i < hair->totcurve; i++) { + HairCurve *curve = &hair->curves[i]; + curve->firstpoint = i * numpoints; + curve->numpoints = numpoints; + + float theta = 2.0f * M_PI * BLI_rng_get_float(rng); + float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f); + + float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)}; + normalize_v3(no); + + float co[3]; + copy_v3_v3(co, no); + + float(*curve_co)[3] = hair->co + curve->firstpoint; + float *curve_radius = hair->radius + curve->firstpoint; + for (int key = 0; key < numpoints; key++) { + float t = key / (float)(numpoints - 1); + copy_v3_v3(curve_co[key], co); + curve_radius[key] = 0.02f * (1.0f - t); + + float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f, + 2.0f * BLI_rng_get_float(rng) - 1.0f, + 2.0f * BLI_rng_get_float(rng) - 1.0f}; + add_v3_v3(offset, no); + madd_v3_v3fl(co, offset, 1.0f / numpoints); + } + } + + BLI_rng_free(rng); +} + +void *BKE_hair_add(Main *bmain, const char *name) +{ + Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0); + + hair_init_data(&hair->id); + + return hair; +} + +Hair *BKE_hair_copy(Main *bmain, const Hair *hair) +{ + Hair *hair_copy; + BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy); + return hair_copy; +} + BoundBox *BKE_hair_boundbox_get(Object *ob) { BLI_assert(ob->type == OB_HAIR); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 56cdce05d57..b4a3f249c63 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -199,6 +199,7 @@ IDTypeInfo IDType_ID_IM = { .copy_data = image_copy_data, .free_data = image_free_data, .make_local = NULL, + .foreach_id = NULL, }; /* prototypes */ diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 12c1cf6bafa..780c3c2f14a 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -123,6 +123,7 @@ IDTypeInfo IDType_ID_IP = { .copy_data = NULL, .free_data = ipo_free_data, .make_local = NULL, + .foreach_id = NULL, }; /* *************************************************** */ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 0eaf7cf2f41..f03bf60817f 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -694,14 +694,14 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection * in at least one layer collection. That list is also synchronized here, and * stores state like selection. */ -static short layer_collection_sync(ViewLayer *view_layer, - const ListBase *lb_scene, - ListBase *lb_layer, - ListBase *new_object_bases, - short parent_exclude, - short parent_restrict, - short parent_layer_restrict, - unsigned short parent_local_collections_bits) +static void layer_collection_sync(ViewLayer *view_layer, + const ListBase *lb_scene, + ListBase *lb_layer, + ListBase *new_object_bases, + short parent_exclude, + short parent_restrict, + short parent_layer_restrict, + unsigned short parent_local_collections_bits) { /* TODO: support recovery after removal of intermediate collections, reordering, .. * For local edits we can make editing operating do the appropriate thing, but for @@ -732,7 +732,6 @@ static short layer_collection_sync(ViewLayer *view_layer, /* Add layer collections for any new scene collections, and ensure order is the same. */ ListBase new_lb_layer = {NULL, NULL}; - short runtime_flag = 0; LISTBASE_FOREACH (const CollectionChild *, child, lb_scene) { Collection *collection = child->collection; @@ -763,23 +762,20 @@ static short layer_collection_sync(ViewLayer *view_layer, } /* Sync child collections. */ - short child_runtime_flag = layer_collection_sync(view_layer, - &collection->children, - &lc->layer_collections, - new_object_bases, - lc->flag, - child_restrict, - child_layer_restrict, - local_collections_bits); + layer_collection_sync(view_layer, + &collection->children, + &lc->layer_collections, + new_object_bases, + lc->flag, + child_restrict, + child_layer_restrict, + local_collections_bits); /* Layer collection exclude is not inherited. */ + lc->runtime_flag = 0; if (lc->flag & LAYER_COLLECTION_EXCLUDE) { - lc->runtime_flag = 0; continue; } - else { - lc->runtime_flag = child_runtime_flag; - } /* We separate restrict viewport and visible view layer because a layer collection can be * hidden in the view layer yet (locally) visible in a viewport (if it is not restricted).*/ @@ -846,15 +842,11 @@ static short layer_collection_sync(ViewLayer *view_layer, lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS; } - - runtime_flag |= lc->runtime_flag; } /* Replace layer collection list with new one. */ *lb_layer = new_lb_layer; BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer)); - - return runtime_flag; } /** diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 9ef5c549235..19462c62496 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -128,8 +128,6 @@ static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id) */ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) { - bNodeTree *ntree = NULL; - Key *key = NULL; const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 && (id->flag & LIB_EMBEDDED_DATA) == 0; @@ -146,14 +144,11 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) } } - /* Internal bNodeTree blocks inside data-blocks also stores id->lib, - * make sure this stays in sync. */ - if ((ntree = ntreeFromID(id))) { - lib_id_clear_library_data_ex(bmain, &ntree->id); - } - - /* Same goes for shapekeys. */ - if ((key = BKE_key_from_id(id))) { + /* Internal shape key blocks inside data-blocks also stores id->lib, + * make sure this stays in sync (note that we do not need any explicit handling for real EMBEDDED + * IDs here, this is down automatically in `lib_id_expand_local_cb()`. */ + Key *key = BKE_key_from_id(id); + if (key != NULL) { lib_id_clear_library_data_ex(bmain, &key->id); } } @@ -310,10 +305,23 @@ void BKE_id_clear_newpoin(ID *id) static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data) { + Main *bmain = cb_data->bmain; ID *id_self = cb_data->id_self; ID **id_pointer = cb_data->id_pointer; int const cb_flag = cb_data->cb_flag; + + if (cb_flag & IDWALK_CB_LOOPBACK) { + /* We should never have anything to do with loopback pointers here. */ + return IDWALK_RET_NOP; + } + if (cb_flag & IDWALK_CB_EMBEDDED) { + /* Embedded data-blocks need to be made fully local as well. */ + if (*id_pointer != NULL) { + BLI_assert(*id_pointer != id_self); + + lib_id_clear_library_data_ex(bmain, *id_pointer); + } return IDWALK_RET_NOP; } @@ -335,7 +343,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data) */ void BKE_lib_id_expand_local(Main *bmain, ID *id) { - BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, NULL, IDWALK_READONLY); + BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, bmain, IDWALK_READONLY); } /** @@ -393,6 +401,13 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags) if (ntree && ntree_new) { ID_NEW_SET(ntree, ntree_new); } + if (GS(id->name) == ID_SCE) { + Collection *master_collection = ((Scene *)id)->master_collection, + *master_collection_new = ((Scene *)id_new)->master_collection; + if (master_collection && master_collection_new) { + ID_NEW_SET(master_collection, master_collection_new); + } + } if (!lib_local) { BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE); @@ -1676,20 +1691,6 @@ static void library_make_local_copying_check(ID *id, /* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual * relation we want to check is in the other way around. */ if (entry->usage_flag & IDWALK_CB_LOOPBACK) { -#ifndef NDEBUG - /* Some debug checks to ensure we explicitly are aware of all 'loop-back' cases, since those - * may not always be manageable in the same way... */ - switch (GS(par_id->name)) { - case ID_OB: - BLI_assert(((Object *)par_id)->proxy_from == (Object *)id); - break; - case ID_KE: - BLI_assert(((Key *)par_id)->from == id); - break; - default: - BLI_assert(0); - } -#endif continue; } diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index f1314beae38..00a42b12e07 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -24,41 +24,6 @@ #include <stdlib.h> #include "DNA_anim_types.h" -#include "DNA_armature_types.h" -#include "DNA_brush_types.h" -#include "DNA_camera_types.h" -#include "DNA_collection_types.h" -#include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" -#include "DNA_key_types.h" -#include "DNA_lattice_types.h" -#include "DNA_light_types.h" -#include "DNA_lightprobe_types.h" -#include "DNA_linestyle_types.h" -#include "DNA_mask_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_node_types.h" -#include "DNA_object_force_types.h" -#include "DNA_outliner_types.h" -#include "DNA_pointcloud_types.h" -#include "DNA_rigidbody_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_sequence_types.h" -#include "DNA_simulation_types.h" -#include "DNA_sound_types.h" -#include "DNA_space_types.h" -#include "DNA_speaker_types.h" -#include "DNA_text_types.h" -#include "DNA_vfont_types.h" -#include "DNA_volume_types.h" -#include "DNA_windowmanager_types.h" -#include "DNA_workspace_types.h" -#include "DNA_world_types.h" #include "BLI_ghash.h" #include "BLI_linklist_stack.h" @@ -66,76 +31,12 @@ #include "BLI_utildefines.h" #include "BKE_anim_data.h" -#include "BKE_collection.h" -#include "BKE_constraint.h" -#include "BKE_fcurve_driver.h" -#include "BKE_gpencil_modifier.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" -#include "BKE_modifier.h" #include "BKE_node.h" -#include "BKE_particle.h" -#include "BKE_rigidbody.h" -#include "BKE_sequencer.h" -#include "BKE_shader_fx.h" -#include "BKE_texture.h" -#include "BKE_workspace.h" - -#define FOREACH_FINALIZE _finalize -#define FOREACH_FINALIZE_VOID \ - if (0) { \ - goto FOREACH_FINALIZE; \ - } \ - FOREACH_FINALIZE: \ - ((void)0) - -#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \ - CHECK_TYPE(id_pp, ID **); \ - if (!((_data)->status & IDWALK_STOP)) { \ - const int _flag = (_data)->flag; \ - ID *old_id = *(id_pp); \ - const int callback_return = (_data)->callback(&(struct LibraryIDLinkCallbackData){ \ - .user_data = (_data)->user_data, \ - .id_owner = (_data)->owner_id, \ - .id_self = (_data)->self_id, \ - .id_pointer = id_pp, \ - .cb_flag = ((_cb_flag | (_data)->cb_flag) & ~(_data)->cb_flag_clear)}); \ - if (_flag & IDWALK_READONLY) { \ - BLI_assert(*(id_pp) == old_id); \ - } \ - if (old_id && (_flag & IDWALK_RECURSE)) { \ - if (BLI_gset_add((_data)->ids_handled, old_id)) { \ - if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \ - BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \ - } \ - } \ - } \ - if (callback_return & IDWALK_RET_STOP_ITER) { \ - (_data)->status |= IDWALK_STOP; \ - goto FOREACH_FINALIZE; \ - } \ - } \ - else { \ - goto FOREACH_FINALIZE; \ - } \ - ((void)0) - -#define FOREACH_CALLBACK_INVOKE_ID(_data, id, cb_flag) \ - { \ - CHECK_TYPE_ANY(id, ID *, void *); \ - FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \ - } \ - ((void)0) - -#define FOREACH_CALLBACK_INVOKE(_data, id_super, cb_flag) \ - { \ - CHECK_TYPE(&((id_super)->id), ID *); \ - FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \ - } \ - ((void)0) /* status */ enum { @@ -174,6 +75,7 @@ bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int ID *old_id = *id_pp; const int callback_return = data->callback(&(struct LibraryIDLinkCallbackData){ .user_data = data->user_data, + .bmain = data->bmain, .id_owner = data->owner_id, .id_self = data->self_id, .id_pointer = id_pp, @@ -199,6 +101,25 @@ bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int } } +int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data) +{ + return data->flag; +} + +int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData *data, + const int cb_flag, + const bool do_replace) +{ + const int cb_flag_backup = data->cb_flag; + if (do_replace) { + data->cb_flag = cb_flag; + } + else { + data->cb_flag |= cb_flag; + } + return cb_flag_backup; +} + static void library_foreach_ID_link(Main *bmain, ID *id_owner, ID *id, @@ -215,303 +136,6 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, IDWALK_CB_USER); } -static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw), - ID **id_pointer, - void *user_data, - int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_modifiersForeachIDLink(void *user_data, - Object *UNUSED(object), - ID **id_pointer, - int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, - Object *UNUSED(object), - ID **id_pointer, - int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_shaderfxForeachIDLink(void *user_data, - Object *UNUSED(object), - ID **id_pointer, - int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), - ID **id_pointer, - bool is_reference, - void *user_data) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys), - ID **id_pointer, - void *user_data, - int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip) -{ - FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER); - - LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { - library_foreach_nla_strip(data, substrip); - } - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) -{ - LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - ChannelDriver *driver = fcu->driver; - - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - /* only used targets */ - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP); - } - DRIVER_TARGETS_LOOPER_END; - } - } - - FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER); - FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER); - - LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) { - LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) { - library_foreach_nla_strip(data, nla_strip); - } - } - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) -{ - FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER); - for (int i = 0; i < paint->tool_slots_len; i++) { - FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER); - } - FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) -{ - LISTBASE_FOREACH (LayerCollection *, lc, lb) { - /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad - * anyway... */ - const int cb_flag = (lc->collection != NULL && - (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? - IDWALK_CB_EMBEDDED : - IDWALK_CB_NOP; - FOREACH_CALLBACK_INVOKE(data, lc->collection, cb_flag); - library_foreach_layer_collection(data, &lc->layer_collections); - } - - FOREACH_FINALIZE_VOID; -} - -/* Used by both real Collection data-blocks, and the fake horror of master collection from Scene. - */ -static void library_foreach_collection(LibraryForeachIDData *data, Collection *collection) -{ - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - FOREACH_CALLBACK_INVOKE(data, cob->ob, IDWALK_CB_USER); - } - LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - FOREACH_CALLBACK_INVOKE(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER); - } - LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) { - /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad - * anyway... */ - const int cb_flag = ((parent->collection != NULL && - (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? - IDWALK_CB_EMBEDDED : - IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE( - data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag); - } - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads) -{ - if (ads != NULL) { - FOREACH_CALLBACK_INVOKE_ID(data, ads->source, IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE(data, ads->filter_grp, IDWALK_CB_NOP); - } - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *area) -{ - FOREACH_CALLBACK_INVOKE(data, area->full, IDWALK_CB_NOP); - - LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - switch (sl->spacetype) { - case SPACE_VIEW3D: { - View3D *v3d = (View3D *)sl; - - FOREACH_CALLBACK_INVOKE(data, v3d->camera, IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE(data, v3d->ob_center, IDWALK_CB_NOP); - - if (v3d->localvd) { - FOREACH_CALLBACK_INVOKE(data, v3d->localvd->camera, IDWALK_CB_NOP); - } - break; - } - case SPACE_GRAPH: { - SpaceGraph *sipo = (SpaceGraph *)sl; - - library_foreach_dopesheet(data, sipo->ads); - break; - } - case SPACE_PROPERTIES: { - SpaceProperties *sbuts = (SpaceProperties *)sl; - - FOREACH_CALLBACK_INVOKE_ID(data, sbuts->pinid, IDWALK_CB_NOP); - break; - } - case SPACE_FILE: - break; - case SPACE_ACTION: { - SpaceAction *saction = (SpaceAction *)sl; - - library_foreach_dopesheet(data, &saction->ads); - FOREACH_CALLBACK_INVOKE(data, saction->action, IDWALK_CB_NOP); - break; - } - case SPACE_IMAGE: { - SpaceImage *sima = (SpaceImage *)sl; - - FOREACH_CALLBACK_INVOKE(data, sima->image, IDWALK_CB_USER_ONE); - FOREACH_CALLBACK_INVOKE(data, sima->mask_info.mask, IDWALK_CB_USER_ONE); - FOREACH_CALLBACK_INVOKE(data, sima->gpd, IDWALK_CB_USER); - break; - } - case SPACE_SEQ: { - SpaceSeq *sseq = (SpaceSeq *)sl; - - FOREACH_CALLBACK_INVOKE(data, sseq->gpd, IDWALK_CB_USER); - break; - } - case SPACE_NLA: { - SpaceNla *snla = (SpaceNla *)sl; - - library_foreach_dopesheet(data, snla->ads); - break; - } - case SPACE_TEXT: { - SpaceText *st = (SpaceText *)sl; - - FOREACH_CALLBACK_INVOKE(data, st->text, IDWALK_CB_NOP); - break; - } - case SPACE_SCRIPT: { - SpaceScript *scpt = (SpaceScript *)sl; - - FOREACH_CALLBACK_INVOKE(data, scpt->script, IDWALK_CB_NOP); - break; - } - case SPACE_OUTLINER: { - SpaceOutliner *so = (SpaceOutliner *)sl; - - FOREACH_CALLBACK_INVOKE_ID(data, so->search_tse.id, IDWALK_CB_NOP); - - if (so->treestore != NULL) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - FOREACH_CALLBACK_INVOKE_ID(data, tselem->id, IDWALK_CB_NOP); - } - } - break; - } - case SPACE_NODE: { - SpaceNode *snode = (SpaceNode *)sl; - - const bool is_private_nodetree = snode->id != NULL && - ntreeFromID(snode->id) == snode->nodetree; - - FOREACH_CALLBACK_INVOKE_ID(data, snode->id, IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE_ID(data, snode->from, IDWALK_CB_NOP); - - FOREACH_CALLBACK_INVOKE( - data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); - - LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) { - if (path == snode->treepath.first) { - /* first nodetree in path is same as snode->nodetree */ - FOREACH_CALLBACK_INVOKE(data, - path->nodetree, - is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); - } - else { - FOREACH_CALLBACK_INVOKE(data, path->nodetree, IDWALK_CB_USER_ONE); - } - - if (path->nodetree == NULL) { - break; - } - } - - FOREACH_CALLBACK_INVOKE(data, snode->edittree, IDWALK_CB_NOP); - break; - } - case SPACE_CLIP: { - SpaceClip *sclip = (SpaceClip *)sl; - - FOREACH_CALLBACK_INVOKE(data, sclip->clip, IDWALK_CB_USER_ONE); - FOREACH_CALLBACK_INVOKE(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE); - break; - } - default: - break; - } - } - - FOREACH_FINALIZE_VOID; -} - bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) { /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ @@ -556,7 +180,6 @@ static void library_foreach_ID_link(Main *bmain, LibraryForeachIDData *inherit_data) { LibraryForeachIDData data = {.bmain = bmain}; - int i; BLI_assert(inherit_data == NULL || data.bmain == inherit_data->bmain); @@ -577,10 +200,11 @@ static void library_foreach_ID_link(Main *bmain, data.callback = callback; data.user_data = user_data; -#define CALLBACK_INVOKE_ID(check_id, cb_flag) FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag) +#define CALLBACK_INVOKE_ID(check_id, cb_flag) \ + BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag) #define CALLBACK_INVOKE(check_id_super, cb_flag) \ - FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag) + BKE_LIB_FOREACHID_PROCESS(&data, check_id_super, cb_flag) for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; @@ -616,7 +240,7 @@ static void library_foreach_ID_link(Main *bmain, * especially if/when it starts modifying Main database). */ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id); for (; entry != NULL; entry = entry->next) { - FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag); + BKE_lib_query_foreachid_process(&data, entry->id_pointer, entry->usage_flag); } continue; } @@ -638,472 +262,19 @@ static void library_foreach_ID_link(Main *bmain, AnimData *adt = BKE_animdata_from_id(id); if (adt) { - library_foreach_animationData(&data, adt); + BKE_animdata_foreach_id(adt, &data); } const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); - - /* Note: this is temp logic until all code has been ported to IDTypeInfo... */ if (id_type->foreach_id != NULL) { id_type->foreach_id(id, &data); if (data.status & IDWALK_STOP) { break; } - else { - continue; - } - } - - switch ((ID_Type)GS(id->name)) { - case ID_LI: { - BLI_assert(0); - break; - } - case ID_SCE: { - Scene *scene = (Scene *)id; - ToolSettings *toolsett = scene->toolsettings; - - CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP); - CALLBACK_INVOKE(scene->world, IDWALK_CB_USER); - CALLBACK_INVOKE(scene->set, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER); - CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); - CALLBACK_INVOKE(scene->r.bake.cage_object, IDWALK_CB_NOP); - if (scene->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(&data, (ID **)&scene->nodetree); - } - if (scene->ed) { - Sequence *seq; - SEQP_BEGIN (scene->ed, seq) { - CALLBACK_INVOKE(seq->scene, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP); - CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER); - CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER); - CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER); - IDP_foreach_property(seq->prop, - IDP_TYPE_FILTER_ID, - BKE_lib_query_idpropertiesForeachIDLink_callback, - &data); - LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) { - CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER); - } - - if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) { - TextVars *text_data = seq->effectdata; - CALLBACK_INVOKE(text_data->text_font, IDWALK_CB_USER); - } - } - SEQ_END; - } - - /* This pointer can be NULL during old files reading, better be safe than sorry. */ - if (scene->master_collection != NULL) { - library_foreach_collection(&data, scene->master_collection); - } - - if (scene->master_collection->lanpr) { - CALLBACK_INVOKE(scene->master_collection->lanpr->target, IDWALK_CB_USER); - } - - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER); - - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - CALLBACK_INVOKE(base->object, IDWALK_CB_NOP); - } - - library_foreach_layer_collection(&data, &view_layer->layer_collections); - - LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { - if (fmc->script) { - CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP); - } - } - - LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { - if (fls->group) { - CALLBACK_INVOKE(fls->group, IDWALK_CB_USER); - } - - if (fls->linestyle) { - CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER); - } - } - } - - LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { - CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP); - } - - if (toolsett) { - CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP); - CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP); - CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP); - - library_foreach_paint(&data, &toolsett->imapaint.paint); - CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER); - CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER); - CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER); - - if (toolsett->vpaint) { - library_foreach_paint(&data, &toolsett->vpaint->paint); - } - if (toolsett->wpaint) { - library_foreach_paint(&data, &toolsett->wpaint->paint); - } - if (toolsett->sculpt) { - library_foreach_paint(&data, &toolsett->sculpt->paint); - CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP); - } - if (toolsett->uvsculpt) { - library_foreach_paint(&data, &toolsett->uvsculpt->paint); - } - if (toolsett->gp_paint) { - library_foreach_paint(&data, &toolsett->gp_paint->paint); - } - if (toolsett->gp_vertexpaint) { - library_foreach_paint(&data, &toolsett->gp_vertexpaint->paint); - } - if (toolsett->gp_sculptpaint) { - library_foreach_paint(&data, &toolsett->gp_sculptpaint->paint); - } - if (toolsett->gp_weightpaint) { - library_foreach_paint(&data, &toolsett->gp_weightpaint->paint); - } - - CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP); - } - - if (scene->rigidbody_world) { - BKE_rigidbody_world_id_loop( - scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data); - } - - break; - } - - case ID_OB: { - Object *object = (Object *)id; - - /* Object is special, proxies make things hard... */ - const int data_cb_flag = data.cb_flag; - const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && - (object->proxy || object->proxy_group)) ? - IDWALK_CB_INDIRECT_USAGE : - 0; - - /* object data special case */ - data.cb_flag |= proxy_cb_flag; - if (object->type == OB_EMPTY) { - /* empty can have NULL or Image */ - CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER); - } - else { - /* when set, this can't be NULL */ - if (object->data) { - CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); - } - } - data.cb_flag = data_cb_flag; - - CALLBACK_INVOKE(object->parent, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(object->track, IDWALK_CB_NEVER_SELF); - /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ - CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP); - - /* Special case! - * Since this field is set/owned by 'user' of this ID (and not ID itself), - * it is only indirect usage if proxy object is linked... Twisted. */ - if (object->proxy_from) { - data.cb_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0; - } - CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF); - data.cb_flag = data_cb_flag; - - CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER); - - data.cb_flag |= proxy_cb_flag; - for (i = 0; i < object->totcol; i++) { - CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER); - } - data.cb_flag = data_cb_flag; - - /* Note that ob->gpd is deprecated, so no need to handle it here. */ - CALLBACK_INVOKE(object->instance_collection, IDWALK_CB_USER); - - if (object->pd) { - CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER); - CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP); - } - /* Note that ob->effect is deprecated, so no need to handle it here. */ - - if (object->pose) { - data.cb_flag |= proxy_cb_flag; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - IDP_foreach_property(pchan->prop, - IDP_TYPE_FILTER_ID, - BKE_lib_query_idpropertiesForeachIDLink_callback, - &data); - CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER); - BKE_constraints_id_loop( - &pchan->constraints, library_foreach_constraintObjectLooper, &data); - } - data.cb_flag = data_cb_flag; - } - - if (object->rigidbody_constraint) { - CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF); - } - - if (object->lodlevels.first) { - LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) { - CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF); - } - } - - BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, &data); - BKE_gpencil_modifiers_foreach_ID_link( - object, library_foreach_gpencil_modifiersForeachIDLink, &data); - BKE_constraints_id_loop( - &object->constraints, library_foreach_constraintObjectLooper, &data); - BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, &data); - - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data); - } - - if (object->soft) { - CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP); - - if (object->soft->effector_weights) { - CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP); - } - } - break; - } - - case ID_AR: { - BLI_assert(0); - break; - } - - case ID_ME: { - BLI_assert(0); - break; - } - - case ID_CU: { - BLI_assert(0); - break; - } - - case ID_MB: { - BLI_assert(0); - break; - } - - case ID_MA: { - BLI_assert(0); - break; - } - - case ID_TE: { - BLI_assert(0); - break; - } - - case ID_LT: { - BLI_assert(0); - break; - } - - case ID_LA: { - break; - } - - case ID_CA: { - BLI_assert(0); - break; - } - - case ID_KE: { - break; - } - - case ID_WO: { - BLI_assert(0); - break; - } - - case ID_SPK: { - BLI_assert(0); - break; - } - - case ID_LP: { - BLI_assert(0); - break; - } - - case ID_GR: { - Collection *collection = (Collection *)id; - library_foreach_collection(&data, collection); - break; - } - - case ID_NT: { - BLI_assert(0); - break; - } - - case ID_BR: { - BLI_assert(0); - break; - } - - case ID_PA: { - BLI_assert(0); - break; - } - - case ID_MC: { - BLI_assert(0); - break; - } - - case ID_MSK: { - BLI_assert(0); - break; - } - - case ID_LS: { - BLI_assert(0); - break; - } - - case ID_AC: { - bAction *act = (bAction *)id; - - LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { - CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP); - } - break; - } - - case ID_WM: { - wmWindowManager *wm = (wmWindowManager *)id; - - LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE); - - /* This pointer can be NULL during old files reading, better be safe than sorry. */ - if (win->workspace_hook != NULL) { - ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); - CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP); - /* allow callback to set a different workspace */ - BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); - } - if (data.flag & IDWALK_INCLUDE_UI) { - LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { - library_foreach_screen_area(&data, area); - } - } - } - break; - } - - case ID_WS: { - WorkSpace *workspace = (WorkSpace *)id; - ListBase *layouts = BKE_workspace_layouts_get(workspace); - - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { - bScreen *screen = BKE_workspace_layout_screen_get(layout); - - /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer. - * However we can't access layout->screen here - * since we are outside the workspace project. */ - CALLBACK_INVOKE(screen, IDWALK_CB_USER); - /* allow callback to set a different screen */ - BKE_workspace_layout_screen_set(layout, screen); - } - break; - } - - case ID_GD: { - bGPdata *gpencil = (bGPdata *)id; - /* materials */ - for (i = 0; i < gpencil->totcol; i++) { - CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER); - } - - LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) { - CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP); - } - - break; - } - case ID_HA: { - Hair *hair = (Hair *)id; - for (i = 0; i < hair->totcol; i++) { - CALLBACK_INVOKE(hair->mat[i], IDWALK_CB_USER); - } - break; - } - case ID_PT: { - PointCloud *pointcloud = (PointCloud *)id; - for (i = 0; i < pointcloud->totcol; i++) { - CALLBACK_INVOKE(pointcloud->mat[i], IDWALK_CB_USER); - } - break; - } - case ID_VO: { - Volume *volume = (Volume *)id; - for (i = 0; i < volume->totcol; i++) { - CALLBACK_INVOKE(volume->mat[i], IDWALK_CB_USER); - } - break; - } - - case ID_SCR: { - if (data.flag & IDWALK_INCLUDE_UI) { - bScreen *screen = (bScreen *)id; - - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - library_foreach_screen_area(&data, area); - } - } - break; - } - case ID_SIM: { - Simulation *simulation = (Simulation *)id; - if (simulation->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(&data, (ID **)&simulation->nodetree); - } - break; - } - - /* Nothing needed for those... */ - case ID_IM: - case ID_VF: - case ID_TXT: - case ID_SO: - case ID_PAL: - case ID_PC: - case ID_CF: - break; - - /* Deprecated. */ - case ID_IP: - break; } } -FOREACH_FINALIZE: if (data.ids_handled) { BLI_gset_free(data.ids_handled, NULL); BLI_LINKSTACK_FREE(data.ids_todo); @@ -1113,9 +284,6 @@ FOREACH_FINALIZE: #undef CALLBACK_INVOKE } -#undef FOREACH_CALLBACK_INVOKE_ID -#undef FOREACH_CALLBACK_INVOKE - /** * Loop over all of the ID's this data-block links to. */ diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index 9dc338ce580..aa1005c663f 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -48,6 +48,8 @@ #include "BLT_translation.h" +#include "DEG_depsgraph.h" + static void light_init_data(ID *id) { Light *la = (Light *)id; @@ -178,3 +180,8 @@ Light *BKE_light_localize(Light *la) return lan; } + +void BKE_light_eval(struct Depsgraph *depsgraph, Light *la) +{ + DEG_debug_print_eval(depsgraph, __func__, la->id.name, la); +} diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index aeef287bb87..0d20d25f84c 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -866,26 +866,6 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, return mesh; } -/** - * TODO(campbell): support mesh with only an edit-mesh which is lazy initialized. - */ -Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em, - const CustomData_MeshMasks *cd_mask_extra, - float (*vertexCos)[3], - const Mesh *me_settings) -{ - Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, cd_mask_extra, me_settings); - /* Use editmesh directly where possible. */ - me->runtime.is_original = true; - if (vertexCos) { - /* We will own this array in the future. */ - BKE_mesh_vert_coords_apply(me, vertexCos); - MEM_freeN(vertexCos); - me->runtime.is_original = false; - } - return me; -} - BoundBox *BKE_mesh_boundbox_get(Object *ob) { /* This is Object-level data access, @@ -895,7 +875,7 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) float min[3], max[3]; INIT_MINMAX(min, max); - if (!BKE_mesh_minmax(me, min, max)) { + if (!BKE_mesh_wrapper_minmax(me, min, max)) { min[0] = min[1] = min[2] = -1.0f; max[0] = max[1] = max[2] = 1.0f; } @@ -916,7 +896,7 @@ void BKE_mesh_texspace_calc(Mesh *me) float min[3], max[3]; INIT_MINMAX(min, max); - if (!BKE_mesh_minmax(me, min, max)) { + if (!BKE_mesh_wrapper_minmax(me, min, max)) { min[0] = min[1] = min[2] = -1.0f; max[0] = max[1] = max[2] = 1.0f; } diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 655c70bcf61..f2c84028570 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -1076,6 +1076,10 @@ static Mesh *mesh_new_from_mball_object(Object *object) 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. */ + BKE_mesh_wrapper_ensure_mdata(mesh); + Mesh *mesh_result = NULL; BKE_id_copy_ex(NULL, &mesh->id, diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index f0d19f01aab..433db26ded8 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -46,6 +46,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" +#include "BKE_editmesh_cache.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_multires.h" @@ -396,6 +397,21 @@ void BKE_mesh_ensure_normals(Mesh *mesh) */ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) { + switch ((eMeshWrapperType)mesh->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_MDATA: + /* Run code below. */ + break; + case ME_WRAPPER_TYPE_BMESH: { + struct BMEditMesh *em = mesh->edit_mesh; + 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); + } + return; + } + } + float(*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL); const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0; const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL); diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c index f2ed9456b11..5ecf5ae316d 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.c +++ b/source/blender/blenkernel/intern/mesh_iterators.c @@ -24,6 +24,8 @@ #include "DNA_meshdata_types.h" #include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_mesh.h" #include "BKE_mesh_iterators.h" @@ -42,23 +44,53 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh, void *userData, MeshForeachFlag flag) { - const MVert *mv = mesh->mvert; - const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); - - if (index) { - for (int i = 0; i < mesh->totvert; i++, mv++) { - const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL; - const int orig = *index++; - if (orig == ORIGINDEX_NONE) { - continue; + if (mesh->edit_mesh != NULL) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + BMIter iter; + BMVert *eve; + int i; + if (mesh->runtime.edit_data->vertexCos != NULL) { + 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; + } + else { + vertexNos = NULL; + } + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL; + func(userData, i, vertexCos[i], no, NULL); + } + } + else { + BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL; + func(userData, i, eve->co, no, NULL); } - func(userData, orig, mv->co, NULL, no); } } else { - for (int i = 0; i < mesh->totvert; i++, mv++) { - const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL; - func(userData, i, mv->co, NULL, no); + const MVert *mv = mesh->mvert; + const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); + + if (index) { + for (int i = 0; i < mesh->totvert; i++, mv++) { + const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL; + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + func(userData, orig, mv->co, NULL, no); + } + } + else { + for (int i = 0; i < mesh->totvert; i++, mv++) { + const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL; + func(userData, i, mv->co, NULL, no); + } } } } @@ -69,22 +101,47 @@ void BKE_mesh_foreach_mapped_edge( void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), void *userData) { - const MVert *mv = mesh->mvert; - const MEdge *med = mesh->medge; - const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX); + if (mesh->edit_mesh != NULL) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + BMIter iter; + BMEdge *eed; + int i; + if (mesh->runtime.edit_data->vertexCos != NULL) { + const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; + BM_mesh_elem_index_ensure(bm, BM_VERT); - if (index) { - for (int i = 0; i < mesh->totedge; i++, med++) { - const int orig = *index++; - if (orig == ORIGINDEX_NONE) { - continue; + BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { + func(userData, + i, + vertexCos[BM_elem_index_get(eed->v1)], + vertexCos[BM_elem_index_get(eed->v2)]); + } + } + else { + BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { + func(userData, i, eed->v1->co, eed->v2->co); } - func(userData, orig, mv[med->v1].co, mv[med->v2].co); } } else { - for (int i = 0; i < mesh->totedge; i++, med++) { - func(userData, i, mv[med->v1].co, mv[med->v2].co); + const MVert *mv = mesh->mvert; + const MEdge *med = mesh->medge; + const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX); + + if (index) { + for (int i = 0; i < mesh->totedge; i++, med++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + func(userData, orig, mv[med->v1].co, mv[med->v2].co); + } + } + else { + for (int i = 0; i < mesh->totedge; i++, med++) { + func(userData, i, mv[med->v1].co, mv[med->v2].co); + } } } } @@ -99,40 +156,72 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, void *userData, MeshForeachFlag flag) { + /* We can't use dm->getLoopDataLayout(dm) here, * we want to always access dm->loopData, EditDerivedBMesh would * return loop data from bmesh itself. */ - const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? - CustomData_get_layer(&mesh->ldata, CD_NORMAL) : - NULL; + if (mesh->edit_mesh != NULL) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + BMIter iter; + BMFace *efa; - const MVert *mv = mesh->mvert; - const MLoop *ml = mesh->mloop; - const MPoly *mp = mesh->mpoly; - const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); - const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); - int p_idx, i; - - if (v_index || f_index) { - for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { - for (i = 0; i < mp->totloop; i++, ml++) { - const int v_idx = v_index ? v_index[ml->v] : ml->v; - const int f_idx = f_index ? f_index[p_idx] : p_idx; + const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; + + /* XXX: investigate using EditMesh data. */ + const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? + CustomData_get_layer(&mesh->ldata, CD_NORMAL) : + NULL; + + int f_idx; + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) { + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const BMVert *eve = l_iter->v; + const int v_idx = BM_elem_index_get(eve); const float *no = lnors ? *lnors++ : NULL; - if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) { - continue; - } - func(userData, v_idx, f_idx, mv[ml->v].co, no); - } + func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no); + } while ((l_iter = l_iter->next) != l_first); } } else { - for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { - for (i = 0; i < mp->totloop; i++, ml++) { - const int v_idx = ml->v; - const int f_idx = p_idx; - const float *no = lnors ? *lnors++ : NULL; - func(userData, v_idx, f_idx, mv[ml->v].co, no); + const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? + CustomData_get_layer(&mesh->ldata, CD_NORMAL) : + NULL; + + const MVert *mv = mesh->mvert; + const MLoop *ml = mesh->mloop; + const MPoly *mp = mesh->mpoly; + const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); + const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + int p_idx, i; + + if (v_index || f_index) { + for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { + for (i = 0; i < mp->totloop; i++, ml++) { + const int v_idx = v_index ? v_index[ml->v] : ml->v; + const int f_idx = f_index ? f_index[p_idx] : p_idx; + const float *no = lnors ? *lnors++ : NULL; + if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) { + continue; + } + func(userData, v_idx, f_idx, mv[ml->v].co, no); + } + } + } + else { + for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { + for (i = 0; i < mp->totloop; i++, ml++) { + const int v_idx = ml->v; + const int f_idx = p_idx; + const float *no = lnors ? *lnors++ : NULL; + func(userData, v_idx, f_idx, mv[ml->v].co, no); + } } } } @@ -145,37 +234,72 @@ void BKE_mesh_foreach_mapped_face_center( void *userData, MeshForeachFlag flag) { - const MVert *mvert = mesh->mvert; - const MPoly *mp = mesh->mpoly; - const MLoop *ml; - float _no_buf[3]; - float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL; - const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + if (mesh->edit_mesh != NULL) { + BMEditMesh *em = mesh->edit_mesh; + BMesh *bm = em->bm; + const float(*polyCos)[3]; + const float(*polyNos)[3]; + BMFace *efa; + BMIter iter; + int i; - if (index) { - for (int i = 0; i < mesh->totpoly; i++, mp++) { - const int orig = *index++; - if (orig == ORIGINDEX_NONE) { - continue; + 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 NULL */ + } + else { + polyNos = NULL; + } + + if (polyNos) { + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + const float *no = polyNos[i]; + func(userData, i, polyCos[i], no); } - float cent[3]; - ml = &mesh->mloop[mp->loopstart]; - BKE_mesh_calc_poly_center(mp, ml, mvert, cent); - if (flag & MESH_FOREACH_USE_NORMAL) { - BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + } + else { + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : NULL; + func(userData, i, polyCos[i], no); } - func(userData, orig, cent, no); } } else { - for (int i = 0; i < mesh->totpoly; i++, mp++) { - float cent[3]; - ml = &mesh->mloop[mp->loopstart]; - BKE_mesh_calc_poly_center(mp, ml, mvert, cent); - if (flag & MESH_FOREACH_USE_NORMAL) { - BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + const MVert *mvert = mesh->mvert; + const MPoly *mp = mesh->mpoly; + const MLoop *ml; + float _no_buf[3]; + float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL; + const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + + if (index) { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + float cent[3]; + ml = &mesh->mloop[mp->loopstart]; + BKE_mesh_calc_poly_center(mp, ml, mvert, cent); + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + } + func(userData, orig, cent, no); + } + } + else { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + float cent[3]; + ml = &mesh->mloop[mp->loopstart]; + BKE_mesh_calc_poly_center(mp, ml, mvert, cent); + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + } + func(userData, i, cent, no); } - func(userData, i, cent, no); } } } diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c new file mode 100644 index 00000000000..f073feffedc --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_wrapper.c @@ -0,0 +1,166 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + * + * The primary purpose of this API is to avoid unnecessary mesh conversion for the final + * output of a modified mesh. + * + * This API handles the case when the modifier stack outputs a mesh which does not have + * #Mesh data (#MPoly, #MLoop, #MEdge, #MVert). + * Currently this is used so the resulting mesh can have #BMEditMesh data, + * postponing the converting until it's needed or avoiding conversion entirely + * which can be an expensive operation. + * Once converted, the meshes type changes to #ME_WRAPPER_TYPE_MDATA, + * although the edit mesh is not cleared. + * + * This API exposes functions that abstract over the different kinds of internal data, + * as well as supporting converting the mesh into regular mesh. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_defaults.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BLI_bitmap.h" +#include "BLI_edgehash.h" +#include "BLI_ghash.h" +#include "BLI_hash.h" +#include "BLI_linklist.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_animsys.h" +#include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" +#include "BKE_global.h" +#include "BKE_idtype.h" +#include "BKE_key.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_object.h" + +#include "PIL_time.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, + const CustomData_MeshMasks *cd_mask_extra, + float (*vertexCos)[3], + const Mesh *me_settings) +{ + Mesh *me = BKE_id_new_nomain(ID_ME, NULL); + BKE_mesh_copy_settings(me, me_settings); + BKE_mesh_runtime_ensure_edit_data(me); + + me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH; + if (cd_mask_extra) { + me->runtime.cd_mask_extra = *cd_mask_extra; + } + + /* Use edit-mesh directly where possible. */ + me->runtime.is_original = true; + me->edit_mesh = MEM_dupallocN(em); + +/* Make sure, we crash if these are ever used. */ +#ifdef DEBUG + me->totvert = INT_MAX; + me->totedge = INT_MAX; + me->totpoly = INT_MAX; + me->totloop = INT_MAX; +#else + me->totvert = 0; + me->totedge = 0; + me->totpoly = 0; + me->totloop = 0; +#endif + + EditMeshData *edit_data = me->runtime.edit_data; + edit_data->vertexCos = vertexCos; + return me; +} + +Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em, + const CustomData_MeshMasks *cd_mask_extra, + const Mesh *me_settings) +{ + return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, NULL, me_settings); +} + +void BKE_mesh_wrapper_ensure_mdata(Mesh *me) +{ + if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { + return; + } + const eMeshWrapperType geom_type_orig = me->runtime.wrapper_type; + me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA; + + switch (geom_type_orig) { + case ME_WRAPPER_TYPE_MDATA: { + break; /* Quiet warning. */ + } + case ME_WRAPPER_TYPE_BMESH: { + me->totvert = 0; + me->totedge = 0; + me->totpoly = 0; + me->totloop = 0; + + BLI_assert(me->edit_mesh != NULL); + BLI_assert(me->runtime.edit_data != NULL); + + BMEditMesh *em = me->edit_mesh; + BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra); + + EditMeshData *edit_data = me->runtime.edit_data; + if (edit_data->vertexCos) { + BKE_mesh_vert_coords_apply(me, edit_data->vertexCos); + me->runtime.is_original = false; + } + break; + } + } + + if (me->runtime.wrapper_type_finalize) { + BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra); + } +} + +bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3]) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_BMESH: + return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max); + case ME_WRAPPER_TYPE_MDATA: + return BKE_mesh_minmax(me, min, max); + } + BLI_assert(0); + return false; +} diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index e872edf0784..6b54a530034 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -50,6 +50,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_appdir.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_key.h" @@ -235,7 +236,7 @@ ModifierData *BKE_modifiers_findby_type(Object *ob, ModifierType type) return md; } -ModifierData *BKE_modifiers_findny_name(Object *ob, const char *name) +ModifierData *BKE_modifiers_findby_name(Object *ob, const char *name) { return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name)); } @@ -934,6 +935,30 @@ void BKE_modifier_path_init(char *path, int path_maxlen, const char *name) BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name); } +/** + * Call when #ModifierTypeInfo.dependsOnNormals callback requests normals. + */ +static void modwrap_dependsOnNormals(Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_BMESH: { + 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. */ + BKE_editmesh_cache_ensure_vert_normals(me->edit_mesh, edit_data); + } + else { + BM_mesh_normals_update(me->edit_mesh->bm); + } + break; + } + case ME_WRAPPER_TYPE_MDATA: + BKE_mesh_calc_normals(me); + break; + } +} + /* wrapper around ModifierTypeInfo.modifyMesh that ensures valid normals */ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md, @@ -943,8 +968,14 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md, const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false); + if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) { + BKE_mesh_wrapper_ensure_mdata(me); + } + } + if (mti->dependsOnNormals && mti->dependsOnNormals(md)) { - BKE_mesh_calc_normals(me); + modwrap_dependsOnNormals(me); } return mti->modifyMesh(md, ctx, me); } @@ -959,7 +990,7 @@ void BKE_modifier_deform_verts(ModifierData *md, BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false); if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - BKE_mesh_calc_normals(me); + modwrap_dependsOnNormals(me); } mti->deformVerts(md, ctx, me, vertexCos, numVerts); } @@ -1030,5 +1061,5 @@ struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph, if (object_eval == object) { return md; } - return BKE_modifiers_findny_name(object_eval, md->name); + return BKE_modifiers_findby_name(object_eval, md->name); } diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index e59b19638f8..64cc9130e25 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -197,7 +197,16 @@ void multiresModifier_subdivide_to_level(struct Object *object, if (!has_mdisps) { CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); } - if (!has_mdisps || top_level == 1) { + + /* NOTE: Subdivision happens from the top level of the existing multires modifier. If it is set + * to 0 and there is mdisps layer it would mean that the modifier went out of sync with the data. + * This happens when, for example, linking modifiers from one object to another. + * + * In such cases simply ensure grids to be the proper level. + * + * If something smarter is needed it is up to the operators which does data synchronization, so + * that the mdisps layer is also synchronized. */ + if (!has_mdisps || top_level == 1 || mmd->totlvl == 0) { multires_reshape_ensure_grids(coarse_mesh, top_level); if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) { multires_subdivide_create_tangent_displacement_linear_grids(object, mmd); diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index 7312ac2bf5e..3564ae80d24 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -55,7 +55,7 @@ /* Surface refers to a simplified and lower-memory footprint representation of the limit surface. * * Used to store pre-calculated information which is expensive or impossible to evaluate when - * travesing the final limit surface. */ + * traversing the final limit surface. */ typedef struct SurfacePoint { float P[3]; diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 6edccbccc76..4ef68b91a84 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -49,6 +49,7 @@ #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_nla.h" #include "BKE_sound.h" @@ -425,6 +426,21 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker) return strip; } +/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of + * `IDTypeInfo` structure). */ +void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data) +{ + BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER); + + LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) { + BKE_fcurve_foreach_id(fcu, data); + } + + LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { + BKE_nla_strip_foreach_id(substrip, data); + } +} + /* *************************************************** */ /* NLA Evaluation <-> Editing Stuff */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 6bd841ca8e5..3e2629f8272 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -81,6 +81,7 @@ #include "BKE_displist.h" #include "BKE_duplilist.h" #include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" #include "BKE_effect.h" #include "BKE_fcurve.h" #include "BKE_fcurve_driver.h" @@ -375,6 +376,153 @@ static void object_make_local(Main *bmain, ID *id, const int flags) } } +static void library_foreach_modifiersForeachIDLink(void *user_data, + Object *UNUSED(object), + ID **id_pointer, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, + Object *UNUSED(object), + ID **id_pointer, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_shaderfxForeachIDLink(void *user_data, + Object *UNUSED(object), + ID **id_pointer, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), + ID **id_pointer, + bool is_reference, + void *user_data) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys), + ID **id_pointer, + void *user_data, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void object_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Object *object = (Object *)id; + + /* Object is special, proxies make things hard... */ + const int proxy_cb_flag = ((BKE_lib_query_foreachid_process_flags_get(data) & + IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && + (object->proxy || object->proxy_group)) ? + IDWALK_CB_INDIRECT_USAGE : + 0; + + /* object data special case */ + if (object->type == OB_EMPTY) { + /* empty can have NULL or Image */ + BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, proxy_cb_flag | IDWALK_CB_USER); + } + else { + /* when set, this can't be NULL */ + if (object->data) { + BKE_LIB_FOREACHID_PROCESS_ID( + data, object->data, proxy_cb_flag | IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); + } + } + + BKE_LIB_FOREACHID_PROCESS(data, object->parent, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, object->track, IDWALK_CB_NEVER_SELF); + /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ + BKE_LIB_FOREACHID_PROCESS(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, object->proxy_group, IDWALK_CB_NOP); + + /* Special case! + * Since this field is set/owned by 'user' of this ID (and not ID itself), + * it is only indirect usage if proxy object is linked... Twisted. */ + { + const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( + data, + (object->proxy_from != NULL && ID_IS_LINKED(object->proxy_from)) ? + IDWALK_CB_INDIRECT_USAGE : + 0, + true); + BKE_LIB_FOREACHID_PROCESS(data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF); + BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); + } + + BKE_LIB_FOREACHID_PROCESS(data, object->poselib, IDWALK_CB_USER); + + for (int i = 0; i < object->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER); + } + + /* Note that ob->gpd is deprecated, so no need to handle it here. */ + BKE_LIB_FOREACHID_PROCESS(data, object->instance_collection, IDWALK_CB_USER); + + if (object->pd) { + BKE_LIB_FOREACHID_PROCESS(data, object->pd->tex, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, object->pd->f_source, IDWALK_CB_NOP); + } + /* Note that ob->effect is deprecated, so no need to handle it here. */ + + if (object->pose) { + const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( + data, proxy_cb_flag, false); + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + IDP_foreach_property( + pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS(data, pchan->custom, IDWALK_CB_USER); + BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data); + } + BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); + } + + if (object->rigidbody_constraint) { + BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF); + } + + if (object->lodlevels.first) { + LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) { + BKE_LIB_FOREACHID_PROCESS(data, level->source, IDWALK_CB_NEVER_SELF); + } + } + + BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data); + BKE_gpencil_modifiers_foreach_ID_link( + object, library_foreach_gpencil_modifiersForeachIDLink, data); + BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data); + BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data); + + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data); + } + + if (object->soft) { + BKE_LIB_FOREACHID_PROCESS(data, object->soft->collision_group, IDWALK_CB_NOP); + + if (object->soft->effector_weights) { + BKE_LIB_FOREACHID_PROCESS(data, object->soft->effector_weights->group, IDWALK_CB_NOP); + } + } +} + IDTypeInfo IDType_ID_OB = { .id_code = ID_OB, .id_filter = FILTER_ID_OB, @@ -389,6 +537,7 @@ IDTypeInfo IDType_ID_OB = { .copy_data = object_copy_data, .free_data = object_free_data, .make_local = object_make_local, + .foreach_id = object_foreach_id, }; void BKE_object_workob_clear(Object *workob) @@ -2941,7 +3090,7 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval) INIT_MINMAX(min, max); - if (!BKE_mesh_minmax(me_eval, min, max)) { + if (!BKE_mesh_wrapper_minmax(me_eval, min, max)) { zero_v3(min); zero_v3(max); } @@ -3887,6 +4036,10 @@ bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_chi * cases false positives are hard to avoid (shape keys for example) */ int BKE_object_is_modified(Scene *scene, Object *ob) { + /* Always test on original object since evaluated object may no longer + * have shape keys or modifiers that were used to evaluate it. */ + ob = DEG_get_original_object(ob); + int flag = 0; if (BKE_key_from_object(ob)) { @@ -4017,6 +4170,10 @@ static bool modifiers_has_animation_check(const Object *ob) * and we can still if there was actual deformation afterwards */ int BKE_object_is_deform_modified(Scene *scene, Object *ob) { + /* Always test on original object since evaluated object may no longer + * have shape keys or modifiers that were used to evaluate it. */ + ob = DEG_get_original_object(ob); + ModifierData *md; VirtualModifierData virtualModifierData; int flag = 0; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 5b608d579e8..f26b478c680 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -116,6 +116,7 @@ IDTypeInfo IDType_ID_PAL = { .copy_data = palette_copy_data, .free_data = palette_free_data, .make_local = NULL, + .foreach_id = NULL, }; static void paint_curve_copy_data(Main *UNUSED(bmain), @@ -153,6 +154,7 @@ IDTypeInfo IDType_ID_PC = { .copy_data = paint_curve_copy_data, .free_data = paint_curve_free_data, .make_local = NULL, + .foreach_id = NULL, }; const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; @@ -547,35 +549,35 @@ void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint) paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool); paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT; } - else if (paint == &ts->sculpt->paint) { + else if (ts->sculpt && paint == &ts->sculpt->paint) { paint->runtime.tool_offset = offsetof(Brush, sculpt_tool); paint->runtime.ob_mode = OB_MODE_SCULPT; } - else if (paint == &ts->vpaint->paint) { + else if (ts->vpaint && paint == &ts->vpaint->paint) { paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool); paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT; } - else if (paint == &ts->wpaint->paint) { + else if (ts->wpaint && paint == &ts->wpaint->paint) { paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool); paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT; } - else if (paint == &ts->uvsculpt->paint) { + else if (ts->uvsculpt && paint == &ts->uvsculpt->paint) { paint->runtime.tool_offset = offsetof(Brush, uv_sculpt_tool); paint->runtime.ob_mode = OB_MODE_EDIT; } - else if (paint == &ts->gp_paint->paint) { + else if (ts->gp_paint && paint == &ts->gp_paint->paint) { paint->runtime.tool_offset = offsetof(Brush, gpencil_tool); paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL; } - else if (paint == &ts->gp_vertexpaint->paint) { + else if (ts->gp_vertexpaint && paint == &ts->gp_vertexpaint->paint) { paint->runtime.tool_offset = offsetof(Brush, gpencil_vertex_tool); paint->runtime.ob_mode = OB_MODE_VERTEX_GPENCIL; } - else if (paint == &ts->gp_sculptpaint->paint) { + else if (ts->gp_sculptpaint && paint == &ts->gp_sculptpaint->paint) { paint->runtime.tool_offset = offsetof(Brush, gpencil_sculpt_tool); paint->runtime.ob_mode = OB_MODE_SCULPT_GPENCIL; } - else if (paint == &ts->gp_weightpaint->paint) { + else if (ts->gp_weightpaint && paint == &ts->gp_weightpaint->paint) { paint->runtime.tool_offset = offsetof(Brush, gpencil_weight_tool); paint->runtime.ob_mode = OB_MODE_WEIGHT_GPENCIL; } @@ -1480,6 +1482,7 @@ static void sculpt_update_object( SculptSession *ss = ob->sculpt; Mesh *me = BKE_object_get_original_mesh(ob); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0; ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0; @@ -1535,17 +1538,22 @@ static void sculpt_update_object( } /* Sculpt Face Sets. */ - if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { - ss->face_sets = CustomData_add_layer( - &me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly); - for (int i = 0; i < me->totpoly; i++) { - ss->face_sets[i] = 1; - } + if (use_face_sets) { + if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { + ss->face_sets = CustomData_add_layer( + &me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly); + for (int i = 0; i < me->totpoly; i++) { + ss->face_sets[i] = 1; + } - /* Set the default face set color if the datalayer did not exist. */ - me->face_sets_color_default = 1; + /* Set the default face set color if the datalayer did not exist. */ + me->face_sets_color_default = 1; + } + ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); + } + else { + ss->face_sets = NULL; } - ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); ss->subdiv_ccg = me_eval->runtime.subdiv_ccg; @@ -1805,11 +1813,12 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob) return pbvh; } -static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform) +static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool respect_hide) { Mesh *me = BKE_object_get_original_mesh(ob); const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); PBVH *pbvh = BKE_pbvh_new(); + BKE_pbvh_respect_hide_set(pbvh, respect_hide); MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__); @@ -1841,11 +1850,12 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform) return pbvh; } -static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg) +static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect_hide) { CCGKey key; BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); PBVH *pbvh = BKE_pbvh_new(); + BKE_pbvh_respect_hide_set(pbvh, respect_hide); BKE_pbvh_build_grids(pbvh, subdiv_ccg->grids, subdiv_ccg->num_grids, @@ -1863,6 +1873,14 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) if (ob == NULL || ob->sculpt == NULL) { return NULL; } + + bool respect_hide = true; + if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { + if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) { + respect_hide = false; + } + } + PBVH *pbvh = ob->sculpt->pbvh; if (pbvh != NULL) { /* NOTE: It is possible that grids were re-allocated due to modifier @@ -1886,11 +1904,11 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *mesh_eval = object_eval->data; if (mesh_eval->runtime.subdiv_ccg != NULL) { - pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg); + 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; - pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform); + pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide); } } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index df74b7a75da..31d51a74e7f 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2163,7 +2163,7 @@ static void psys_sph_flush_springs(SPHData *sphdata) BLI_buffer_field_free(&sphdata->new_springs); } -void psys_sph_finalise(SPHData *sphdata) +void psys_sph_finalize(SPHData *sphdata) { psys_sph_flush_springs(sphdata); @@ -4046,7 +4046,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) BLI_spin_end(&task_data.spin); - psys_sph_finalise(&sphdata); + psys_sph_finalize(&sphdata); break; } } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 21bbdf46104..e31d2a8e005 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -295,6 +295,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) node->face_vert_indices = (const int(*)[3])face_vert_indices; + if (bvh->respect_hide == false) { + has_visible = true; + } + for (int i = 0; i < totface; i++) { const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]]; for (int j = 0; j < 3; j++) { @@ -302,8 +306,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v); } - if (!paint_is_face_hidden(lt, bvh->verts, bvh->mloop)) { - has_visible = true; + if (has_visible == false) { + if (!paint_is_face_hidden(lt, bvh->verts, bvh->mloop)) { + has_visible = true; + } } } @@ -666,7 +672,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, PBVH *BKE_pbvh_new(void) { PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); - + bvh->respect_hide = true; return bvh; } @@ -2117,7 +2123,7 @@ static bool pbvh_faces_node_raycast(PBVH *bvh, const MLoopTri *lt = &bvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (paint_is_face_hidden(lt, vert, mloop)) { + if (bvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { continue; } @@ -2426,7 +2432,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh, const MLoopTri *lt = &bvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (paint_is_face_hidden(lt, vert, mloop)) { + if (bvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { continue; } @@ -2900,6 +2906,12 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo vi->fno = NULL; vi->mvert = NULL; + vi->respect_hide = bvh->respect_hide; + if (bvh->respect_hide == false) { + /* The same value for all vertices. */ + vi->visible = true; + } + BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids); BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); @@ -3014,3 +3026,8 @@ void BKE_pbvh_face_sets_set(PBVH *bvh, int *face_sets) { bvh->face_sets = face_sets; } + +void BKE_pbvh_respect_hide_set(PBVH *bvh, bool respect_hide) +{ + bvh->respect_hide = respect_hide; +} diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index d3e42ac7705..7397f939894 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -160,6 +160,7 @@ struct PBVH { bool deformed; bool show_mask; bool show_face_sets; + bool respect_hide; /* Dynamic topology */ BMesh *bm; diff --git a/source/blender/blenkernel/intern/pointcloud.c b/source/blender/blenkernel/intern/pointcloud.c index 79b16443122..e03888dcad7 100644 --- a/source/blender/blenkernel/intern/pointcloud.c +++ b/source/blender/blenkernel/intern/pointcloud.c @@ -21,6 +21,7 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_pointcloud_types.h" @@ -48,23 +49,7 @@ /* PointCloud datablock */ -static void pointcloud_random(PointCloud *pointcloud) -{ - pointcloud->totpoint = 400; - CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); - BKE_pointcloud_update_customdata_pointers(pointcloud); - - RNG *rng = BLI_rng_new(0); - - for (int i = 0; i < pointcloud->totpoint; i++) { - pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng); - } - - BLI_rng_free(rng); -} +static void pointcloud_random(PointCloud *pointcloud); static void pointcloud_init_data(ID *id) { @@ -81,15 +66,6 @@ static void pointcloud_init_data(ID *id) pointcloud_random(pointcloud); } -void *BKE_pointcloud_add(Main *bmain, const char *name) -{ - PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0); - - pointcloud_init_data(&pointcloud->id); - - return pointcloud; -} - static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) { PointCloud *pointcloud_dst = (PointCloud *)id_dst; @@ -105,18 +81,6 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s BKE_pointcloud_update_customdata_pointers(pointcloud_dst); } -PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud) -{ - PointCloud *pointcloud_copy; - BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy); - return pointcloud_copy; -} - -static void pointcloud_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - static void pointcloud_free_data(ID *id) { PointCloud *pointcloud = (PointCloud *)id; @@ -126,6 +90,14 @@ static void pointcloud_free_data(ID *id) MEM_SAFE_FREE(pointcloud->mat); } +static void pointcloud_foreach_id(ID *id, LibraryForeachIDData *data) +{ + PointCloud *pointcloud = (PointCloud *)id; + for (int i = 0; i < pointcloud->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, pointcloud->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_PT = { .id_code = ID_PT, .id_filter = FILTER_ID_PT, @@ -139,9 +111,44 @@ IDTypeInfo IDType_ID_PT = { .init_data = pointcloud_init_data, .copy_data = pointcloud_copy_data, .free_data = pointcloud_free_data, - .make_local = pointcloud_make_local, + .make_local = NULL, + .foreach_id = pointcloud_foreach_id, }; +static void pointcloud_random(PointCloud *pointcloud) +{ + pointcloud->totpoint = 400; + CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); + BKE_pointcloud_update_customdata_pointers(pointcloud); + + RNG *rng = BLI_rng_new(0); + + for (int i = 0; i < pointcloud->totpoint; i++) { + pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f; + pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f; + pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f; + pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng); + } + + BLI_rng_free(rng); +} + +void *BKE_pointcloud_add(Main *bmain, const char *name) +{ + PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0); + + pointcloud_init_data(&pointcloud->id); + + return pointcloud; +} + +PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud) +{ + PointCloud *pointcloud_copy; + BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy); + return pointcloud_copy; +} + BoundBox *BKE_pointcloud_boundbox_get(Object *ob) { BLI_assert(ob->type == OB_POINTCLOUD); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 4d37c2ea931..c9911d2cf85 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -2116,6 +2116,7 @@ void BKE_rigidbody_ensure_local_object(Main *bmain, Object *ob) bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports) { + BKE_report(reports, RPT_ERROR, "Compiled without Bullet physics engine"); return false; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 1d0c7458b2e..7d60d21a496 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -33,6 +33,7 @@ #include "DNA_defaults.h" #include "DNA_gpencil_types.h" #include "DNA_linestyle_types.h" +#include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -42,6 +43,7 @@ #include "DNA_sequence_types.h" #include "DNA_sound_types.h" #include "DNA_space_types.h" +#include "DNA_text_types.h" #include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" @@ -77,6 +79,7 @@ #include "BKE_image.h" #include "BKE_layer.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_linestyle.h" #include "BKE_main.h" @@ -158,7 +161,7 @@ static void scene_init_data(ID *id) scene->unit.mass_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS); scene->unit.time_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME); - /* Anti-aliasing threshold. */ + /* Anti-Aliasing threshold. */ scene->grease_pencil_settings.smaa_threshold = 1.0f; { @@ -421,6 +424,155 @@ static void scene_free_data(ID *id) BLI_assert(scene->layer_properties == NULL); } +static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw), + ID **id_pointer, + void *user_data, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) +{ + BKE_LIB_FOREACHID_PROCESS(data, paint->brush, IDWALK_CB_USER); + for (int i = 0; i < paint->tool_slots_len; i++) { + BKE_LIB_FOREACHID_PROCESS(data, paint->tool_slots[i].brush, IDWALK_CB_USER); + } + BKE_LIB_FOREACHID_PROCESS(data, paint->palette, IDWALK_CB_USER); +} + +static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) +{ + LISTBASE_FOREACH (LayerCollection *, lc, lb) { + /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad + * anyway... */ + const int cb_flag = (lc->collection != NULL && + (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : + IDWALK_CB_NOP; + BKE_LIB_FOREACHID_PROCESS(data, lc->collection, cb_flag); + library_foreach_layer_collection(data, &lc->layer_collections); + } +} + +static void scene_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Scene *scene = (Scene *)id; + + BKE_LIB_FOREACHID_PROCESS(data, scene->camera, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, scene->world, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, scene->set, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, scene->clip, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, scene->gpd, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, scene->r.bake.cage_object, IDWALK_CB_NOP); + if (scene->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree); + } + if (scene->ed) { + Sequence *seq; + SEQP_BEGIN (scene->ed, seq) { + BKE_LIB_FOREACHID_PROCESS(data, seq->scene, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, seq->scene_camera, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, seq->clip, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, seq->mask, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, seq->sound, IDWALK_CB_USER); + IDP_foreach_property( + seq->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) { + BKE_LIB_FOREACHID_PROCESS(data, smd->mask_id, IDWALK_CB_USER); + } + + if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) { + TextVars *text_data = seq->effectdata; + BKE_LIB_FOREACHID_PROCESS(data, text_data->text_font, IDWALK_CB_USER); + } + } + SEQ_END; + } + + /* This pointer can be NULL during old files reading, better be safe than sorry. */ + if (scene->master_collection != NULL) { + BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection); + } + + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + BKE_LIB_FOREACHID_PROCESS(data, view_layer->mat_override, IDWALK_CB_USER); + + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + BKE_LIB_FOREACHID_PROCESS(data, base->object, IDWALK_CB_NOP); + } + + library_foreach_layer_collection(data, &view_layer->layer_collections); + + LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { + if (fmc->script) { + BKE_LIB_FOREACHID_PROCESS(data, fmc->script, IDWALK_CB_NOP); + } + } + + LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { + if (fls->group) { + BKE_LIB_FOREACHID_PROCESS(data, fls->group, IDWALK_CB_USER); + } + + if (fls->linestyle) { + BKE_LIB_FOREACHID_PROCESS(data, fls->linestyle, IDWALK_CB_USER); + } + } + } + + LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { + BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP); + } + + ToolSettings *toolsett = scene->toolsettings; + if (toolsett) { + BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.scene, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.object, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.shape_object, IDWALK_CB_NOP); + + library_foreach_paint(data, &toolsett->imapaint.paint); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.stencil, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.clone, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.canvas, IDWALK_CB_USER); + + if (toolsett->vpaint) { + library_foreach_paint(data, &toolsett->vpaint->paint); + } + if (toolsett->wpaint) { + library_foreach_paint(data, &toolsett->wpaint->paint); + } + if (toolsett->sculpt) { + library_foreach_paint(data, &toolsett->sculpt->paint); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->sculpt->gravity_object, IDWALK_CB_NOP); + } + if (toolsett->uvsculpt) { + library_foreach_paint(data, &toolsett->uvsculpt->paint); + } + if (toolsett->gp_paint) { + library_foreach_paint(data, &toolsett->gp_paint->paint); + } + if (toolsett->gp_vertexpaint) { + library_foreach_paint(data, &toolsett->gp_vertexpaint->paint); + } + if (toolsett->gp_sculptpaint) { + library_foreach_paint(data, &toolsett->gp_sculptpaint->paint); + } + if (toolsett->gp_weightpaint) { + library_foreach_paint(data, &toolsett->gp_weightpaint->paint); + } + + BKE_LIB_FOREACHID_PROCESS(data, toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP); + } + + if (scene->rigidbody_world) { + BKE_rigidbody_world_id_loop( + scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, data); + } +} + IDTypeInfo IDType_ID_SCE = { .id_code = ID_SCE, .id_filter = FILTER_ID_SCE, @@ -437,6 +589,7 @@ IDTypeInfo IDType_ID_SCE = { /* For now default `BKE_lib_id_make_local_generic()` should work, may need more work though to * support all possible corner cases. */ .make_local = NULL, + .foreach_id = scene_foreach_id, }; const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE"; @@ -1539,9 +1692,7 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce) } /** - * This function is needed to cope with fractional frames - including two Blender rendering - * features mblur (motion blur that renders 'subframes' and blurs them together), - * and fields rendering. + * This function is needed to cope with fractional frames, needed for motion blur & physics. */ float BKE_scene_frame_get(const Scene *scene) { @@ -1618,34 +1769,6 @@ int BKE_scene_orientation_slot_get_index(const TransformOrientationSlot *orient_ /** \} */ -/* That's like really a bummer, because currently animation data for armatures - * might want to use pose, and pose might be missing on the object. - * This happens when changing visible layers, which leads to situations when - * pose is missing or marked for recalc, animation will change it and then - * object update will restore the pose. - * - * This could be solved by the new dependency graph, but for until then we'll - * do an extra pass on the objects to ensure it's all fine. - */ -#define POSE_ANIMATION_WORKAROUND - -#ifdef POSE_ANIMATION_WORKAROUND -static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph) -{ - Object *ob; - if (BLI_listbase_is_empty(&bmain->armatures) || !DEG_id_type_updated(depsgraph, ID_OB)) { - return; - } - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->type == OB_ARMATURE && ob->adt) { - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(bmain, ob, ob->data, true); - } - } - } -} -#endif - static bool check_rendered_viewport_visible(Main *bmain) { wmWindowManager *wm = bmain->wm.first; @@ -1830,9 +1953,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain) BKE_image_editors_update_frame(bmain, scene->r.cfra); BKE_sound_set_cfra(scene->r.cfra); DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); -#ifdef POSE_ANIMATION_WORKAROUND - scene_armature_depsgraph_workaround(bmain, depsgraph); -#endif /* Update all objects: drivers, matrices, displists, etc. flags set * by depgraph or manual, no layer check here, gets correct flushed. * diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 997e807a253..bfc0d437994 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -32,14 +32,18 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_gpencil_types.h" +#include "DNA_mask_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_text_types.h" #include "DNA_view3d_types.h" #include "DNA_workspace_types.h" #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_mempool.h" #include "BLI_rect.h" #include "BLI_utildefines.h" @@ -48,6 +52,8 @@ #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" +#include "BKE_lib_query.h" +#include "BKE_node.h" #include "BKE_screen.h" #include "BKE_workspace.h" @@ -72,6 +78,158 @@ static void screen_free_data(ID *id) MEM_SAFE_FREE(screen->tool_tip); } +static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads) +{ + if (ads != NULL) { + BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP); + } +} + +void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area) +{ + BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP); + + /* TODO this should be moved to a callback in `SpaceType`, defined in each editor's own code. + * Will be for a later round of cleanup though... */ + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + switch (sl->spacetype) { + case SPACE_VIEW3D: { + View3D *v3d = (View3D *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP); + + if (v3d->localvd) { + BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP); + } + break; + } + case SPACE_GRAPH: { + SpaceGraph *sipo = (SpaceGraph *)sl; + + screen_foreach_id_dopesheet(data, sipo->ads); + break; + } + case SPACE_PROPERTIES: { + SpaceProperties *sbuts = (SpaceProperties *)sl; + + BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP); + break; + } + case SPACE_FILE: + break; + case SPACE_ACTION: { + SpaceAction *saction = (SpaceAction *)sl; + + screen_foreach_id_dopesheet(data, &saction->ads); + BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP); + break; + } + case SPACE_IMAGE: { + SpaceImage *sima = (SpaceImage *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE); + BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE); + BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER); + break; + } + case SPACE_SEQ: { + SpaceSeq *sseq = (SpaceSeq *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER); + break; + } + case SPACE_NLA: { + SpaceNla *snla = (SpaceNla *)sl; + + screen_foreach_id_dopesheet(data, snla->ads); + break; + } + case SPACE_TEXT: { + SpaceText *st = (SpaceText *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP); + break; + } + case SPACE_SCRIPT: { + SpaceScript *scpt = (SpaceScript *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP); + break; + } + case SPACE_OUTLINER: { + SpaceOutliner *so = (SpaceOutliner *)sl; + + BKE_LIB_FOREACHID_PROCESS_ID(data, so->search_tse.id, IDWALK_CB_NOP); + + if (so->treestore != NULL) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + BKE_LIB_FOREACHID_PROCESS_ID(data, tselem->id, IDWALK_CB_NOP); + } + } + break; + } + case SPACE_NODE: { + SpaceNode *snode = (SpaceNode *)sl; + + const bool is_private_nodetree = snode->id != NULL && + ntreeFromID(snode->id) == snode->nodetree; + + BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP); + + BKE_LIB_FOREACHID_PROCESS( + data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); + + LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) { + if (path == snode->treepath.first) { + /* first nodetree in path is same as snode->nodetree */ + BKE_LIB_FOREACHID_PROCESS(data, + path->nodetree, + is_private_nodetree ? IDWALK_CB_EMBEDDED : + IDWALK_CB_USER_ONE); + } + else { + BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE); + } + + if (path->nodetree == NULL) { + break; + } + } + + BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP); + break; + } + case SPACE_CLIP: { + SpaceClip *sclip = (SpaceClip *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE); + BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE); + break; + } + default: + break; + } + } +} + +static void screen_foreach_id(ID *id, LibraryForeachIDData *data) +{ + if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { + bScreen *screen = (bScreen *)id; + + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + BKE_screen_foreach_id_screen_area(data, area); + } + } +} + IDTypeInfo IDType_ID_SCR = { .id_code = ID_SCR, .id_filter = 0, @@ -86,6 +244,7 @@ IDTypeInfo IDType_ID_SCR = { .copy_data = NULL, .free_data = screen_free_data, .make_local = NULL, + .foreach_id = screen_foreach_id, }; /* ************ Spacetype/regiontype handling ************** */ diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index a08bbf182fa..5c2d5b0087f 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -1217,6 +1217,11 @@ void BKE_sequencer_cache_cleanup_sequence(Scene *scene, struct ImBuf *BKE_sequencer_cache_get( const SeqRenderData *context, Sequence *seq, float cfra, int type, bool skip_disk_cache) { + + if (context->skip_cache || context->is_proxy_render || !seq) { + return NULL; + } + Scene *scene = context->scene; if (context->is_prefetch_render) { @@ -1314,6 +1319,10 @@ void BKE_sequencer_cache_put(const SeqRenderData *context, float cost, bool skip_disk_cache) { + if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) { + return; + } + Scene *scene = context->scene; if (context->is_prefetch_render) { @@ -1322,10 +1331,6 @@ void BKE_sequencer_cache_put(const SeqRenderData *context, seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene); } - if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) { - return; - } - /* Prevent reinserting, it breaks cache key linking. */ ImBuf *test = BKE_sequencer_cache_get(context, seq, cfra, type, true); if (test) { diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c index f00d517940a..dc75e2b9098 100644 --- a/source/blender/blenkernel/intern/seqprefetch.c +++ b/source/blender/blenkernel/intern/seqprefetch.c @@ -179,12 +179,17 @@ static bool seq_prefetch_is_cache_full(Scene *scene) return BKE_sequencer_cache_recycle_item(pfjob->scene) == false; } +static float seq_prefetch_cfra(PrefetchJob *pfjob) +{ + return pfjob->cfra + pfjob->num_frames_prefetched; +} + void BKE_sequencer_prefetch_get_time_range(Scene *scene, int *start, int *end) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); *start = pfjob->cfra; - *end = pfjob->cfra + pfjob->num_frames_prefetched; + *end = seq_prefetch_cfra(pfjob); } static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob) @@ -198,8 +203,7 @@ static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob) static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob) { - DEG_evaluate_on_framechange( - pfjob->bmain_eval, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched); + DEG_evaluate_on_framechange(pfjob->bmain_eval, pfjob->depsgraph, seq_prefetch_cfra(pfjob)); } static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob) @@ -347,7 +351,7 @@ static bool seq_prefetch_do_skip_frame(Scene *scene) { Editing *ed = scene->ed; PrefetchJob *pfjob = seq_prefetch_job_get(scene); - float cfra = pfjob->cfra + pfjob->num_frames_prefetched; + float cfra = seq_prefetch_cfra(pfjob); Sequence *seq_arr[MAXSEQ + 1]; int count = BKE_sequencer_get_shown_sequences(ed->seqbasep, cfra, 0, seq_arr); SeqRenderData *ctx = &pfjob->context_cpy; @@ -403,18 +407,37 @@ static bool seq_prefetch_do_skip_frame(Scene *scene) return false; } +static bool seq_prefetch_need_suspend(PrefetchJob *pfjob) +{ + return seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain) || + (seq_prefetch_cfra(pfjob) >= pfjob->scene->r.efra); +} + +static void seq_prefetch_do_suspend(PrefetchJob *pfjob) +{ + BLI_mutex_lock(&pfjob->prefetch_suspend_mutex); + while (seq_prefetch_need_suspend(pfjob) && + (pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !pfjob->stop) { + pfjob->waiting = true; + BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex); + seq_prefetch_update_area(pfjob); + } + pfjob->waiting = false; + BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex); +} + static void *seq_prefetch_frames(void *job) { PrefetchJob *pfjob = (PrefetchJob *)job; - while (pfjob->cfra + pfjob->num_frames_prefetched <= pfjob->scene->r.efra) { + while (seq_prefetch_cfra(pfjob) <= pfjob->scene->r.efra) { pfjob->scene_eval->ed->prefetch_job = NULL; seq_prefetch_update_depsgraph(pfjob); AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id); BKE_animsys_evaluate_animdata(&pfjob->context_cpy.scene->id, adt, - pfjob->cfra + pfjob->num_frames_prefetched, + seq_prefetch_cfra(pfjob), ADT_RECALC_ALL, false); @@ -431,26 +454,17 @@ static void *seq_prefetch_frames(void *job) continue; } - ImBuf *ibuf = BKE_sequencer_give_ibuf( - &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0); + ImBuf *ibuf = BKE_sequencer_give_ibuf(&pfjob->context_cpy, seq_prefetch_cfra(pfjob), 0); BKE_sequencer_cache_free_temp_cache( - pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched); + pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob)); IMB_freeImBuf(ibuf); - /* suspend thread */ - BLI_mutex_lock(&pfjob->prefetch_suspend_mutex); - while ((seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain)) && - pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && !pfjob->stop) { - pfjob->waiting = true; - BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex); - seq_prefetch_update_area(pfjob); - } - pfjob->waiting = false; - BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex); + /* Suspend thread if there is nothing to be prefetched. */ + seq_prefetch_do_suspend(pfjob); /* Avoid "collision" with main thread, but make sure to fetch at least few frames */ if (pfjob->num_frames_prefetched > 5 && - (pfjob->cfra + pfjob->num_frames_prefetched - pfjob->scene->r.cfra) < 2) { + (seq_prefetch_cfra(pfjob) - pfjob->scene->r.cfra) < 2) { break; } @@ -463,7 +477,7 @@ static void *seq_prefetch_frames(void *job) } BKE_sequencer_cache_free_temp_cache( - pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched); + pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob)); pfjob->running = false; pfjob->scene_eval->ed->prefetch_job = NULL; @@ -520,10 +534,12 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa seq_prefetch_resume(scene); /* conditions to start: * prefetch enabled, prefetch not running, not scrubbing, - * not playing and rendering-expensive footage, cache storage enabled, has strips to render + * not playing and rendering-expensive footage, cache storage enabled, has strips to render, + * not rendering, not doing modal transform - important, see D7820. */ if ((ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !running && !scrubbing && - !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips) { + !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips && + !G.is_rendering && !G.moving) { seq_prefetch_start(context, cfra); } diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index a14db79ffc6..954dca0f679 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1910,9 +1910,10 @@ static bool seq_proxy_get_fname(Editing *ed, static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra) { char name[PROXY_MAXFILE]; - IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size); - int size_flags; StripProxy *proxy = seq->strip->proxy; + const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size; + const IMB_Proxy_Size psize_flag = seq_rendersize_to_proxysize(psize); + int size_flags; Editing *ed = context->scene->ed; StripAnim *sanim; @@ -1923,7 +1924,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c size_flags = proxy->build_size_flags; /* only use proxies, if they are enabled (even if present!) */ - if (psize == IMB_PROXY_NONE || (size_flags & psize) == 0) { + if (psize_flag == IMB_PROXY_NONE || (size_flags & psize_flag) == 0) { return NULL; } diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index b4cfa7cf0ef..d5ba345928b 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -18,6 +18,8 @@ * \ingroup bke */ +#include <iostream> + #include "MEM_guardedalloc.h" #include "DNA_ID.h" @@ -46,6 +48,7 @@ #include "BLT_translation.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" static void simulation_init_data(ID *id) { @@ -87,13 +90,13 @@ static void simulation_free_data(ID *id) } } -void *BKE_simulation_add(Main *bmain, const char *name) +static void simulation_foreach_id(ID *id, LibraryForeachIDData *data) { - Simulation *simulation = (Simulation *)BKE_libblock_alloc(bmain, ID_SIM, name, 0); - - simulation_init_data(&simulation->id); - - return simulation; + Simulation *simulation = (Simulation *)id; + if (simulation->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree); + } } IDTypeInfo IDType_ID_SIM = { @@ -110,8 +113,20 @@ IDTypeInfo IDType_ID_SIM = { /* copy_data */ simulation_copy_data, /* free_data */ simulation_free_data, /* make_local */ nullptr, + /* foreach_id */ simulation_foreach_id, }; -void BKE_simulation_data_update(Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene)) +void *BKE_simulation_add(Main *bmain, const char *name) +{ + Simulation *simulation = (Simulation *)BKE_libblock_alloc(bmain, ID_SIM, name, 0); + + simulation_init_data(&simulation->id); + + return simulation; +} + +void BKE_simulation_data_update(Depsgraph *UNUSED(depsgraph), + Scene *UNUSED(scene), + Simulation *UNUSED(simulation)) { } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 5500918428f..e8f31594cc0 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -127,6 +127,7 @@ IDTypeInfo IDType_ID_SO = { .copy_data = sound_copy_data, .free_data = sound_free_data, .make_local = NULL, + .foreach_id = NULL, }; #ifdef WITH_AUDASPACE diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c index 1f7cb225fc7..fe1dd3835fd 100644 --- a/source/blender/blenkernel/intern/subdiv.c +++ b/source/blender/blenkernel/intern/subdiv.c @@ -38,6 +38,18 @@ #include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" +/* =================----====--===== MODULE ==========================------== */ + +void BKE_subdiv_init() +{ + openSubdiv_init(); +} + +void BKE_subdiv_exit() +{ + openSubdiv_cleanup(); +} + /* ========================== CONVERSION HELPERS ============================ */ eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth) diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index c21d640a4c1..7a0a5645b80 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -71,18 +71,13 @@ #include "CCGSubSurf.h" -#ifdef WITH_OPENSUBDIV -# include "opensubdiv_capi.h" -#endif - /* assumes MLoop's are laid out 4 for each poly, in order */ #define USE_LOOP_LAYOUT_FAST static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, - DerivedMesh *dm, - bool use_gpu_backend); + DerivedMesh *dm); /// static void *arena_alloc(CCGAllocatorHDL a, int numBytes) @@ -404,82 +399,6 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, return 1; } -#ifdef WITH_OPENSUBDIV -static void UNUSED_FUNCTION(set_subsurf_osd_ccg_uv)(CCGSubSurf *ss, - DerivedMesh *dm, - DerivedMesh *result, - int layer_index) -{ - CCGFace **faceMap; - MTFace *tf; - MLoopUV *mluv; - CCGFaceIterator fi; - int index, gridSize, gridFaces, totface, x, y, S; - MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index); - /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with - * just tface except applying the modifier then looses subsurf UV */ - MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index); - MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index); - - if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) { - return; - } - - ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index); - - /* get some info from CCGSubSurf */ - totface = ccgSubSurf_getNumFaces(ss); - gridSize = ccgSubSurf_getGridSize(ss); - gridFaces = gridSize - 1; - - /* make a map from original faces to CCGFaces */ - faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv"); - for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); - ccgFaceIterator_next(&fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(&fi); - faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f; - } - - /* load coordinates from uvss into tface */ - tf = tface; - mluv = mloopuv; - for (index = 0; index < totface; index++) { - CCGFace *f = faceMap[index]; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - const int delta[4][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; - float uv[4][2]; - int i; - for (i = 0; i < 4; i++) { - const int dx = delta[i][0], dy = delta[i][1]; - const float grid_u = ((float)(x + dx)) / (gridSize - 1), - grid_v = ((float)(y + dy)) / (gridSize - 1); - ccgSubSurf_evaluatorFVarUV(ss, index, S, grid_u, grid_v, uv[i]); - } - if (tf) { - copy_v2_v2(tf->uv[0], uv[0]); - copy_v2_v2(tf->uv[1], uv[1]); - copy_v2_v2(tf->uv[2], uv[2]); - copy_v2_v2(tf->uv[3], uv[3]); - tf++; - } - if (mluv) { - copy_v2_v2(mluv[0].uv, uv[0]); - copy_v2_v2(mluv[1].uv, uv[1]); - copy_v2_v2(mluv[2].uv, uv[2]); - copy_v2_v2(mluv[3].uv, uv[3]); - mluv += 4; - } - } - } - } - } - MEM_freeN(faceMap); -} -#endif /* WITH_OPENSUBDIV */ - static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n) { CCGSubSurf *uvss; @@ -564,16 +483,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh * static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int layer_index) { -#ifdef WITH_OPENSUBDIV - if (!ccgSubSurf_needGrids(ss)) { - /* GPU backend is used, no need to evaluate UVs on CPU. */ - /* TODO(sergey): Think of how to support edit mode of UVs. */ - } - else -#endif - { - set_subsurf_legacy_uv(ss, dm, result, layer_index); - } + set_subsurf_legacy_uv(ss, dm, result, layer_index); } /* face weighting */ @@ -763,40 +673,13 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss, #endif } -#ifdef WITH_OPENSUBDIV -static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm) -{ - ccgSubSurf_initFullSync(ss); - ccgSubSurf_prepareTopologyRefiner(ss, dm); - ccgSubSurf_processSync(ss); -} -#endif /* WITH_OPENSUBDIV */ - static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, float (*vertexCos)[3], int use_flat_subdiv, - bool use_subdiv_uvs) + bool UNUSED(use_subdiv_uvs)) { -#ifndef WITH_OPENSUBDIV - UNUSED_VARS(use_subdiv_uvs); -#endif - -#ifdef WITH_OPENSUBDIV - /* Reset all related descriptors if actual mesh topology changed or if - * other evaluation-related settings changed. - */ - if (!ccgSubSurf_needGrids(ss)) { - /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */ - ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs); - ccgSubSurf_checkTopologyChanged(ss, dm); - ss_sync_osd_from_derivedmesh(ss, dm); - } - else -#endif - { - ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv); - } + ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv); } /***/ @@ -850,13 +733,6 @@ static void UNUSED_FUNCTION(ccgDM_getMinMax)(DerivedMesh *dm, float r_min[3], fl int i, edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - ccgSubSurf_getMinMax(ccgdm->ss, r_min, r_max); - return; - } -#endif - CCG_key_top_level(&key, ss); if (!ccgSubSurf_getNumVerts(ss)) { @@ -1642,11 +1518,9 @@ static void ccgDM_release(DerivedMesh *dm) } MEM_freeN(ccgdm->edgeFlags); MEM_freeN(ccgdm->faceFlags); - if (ccgdm->useGpuBackend == false) { - MEM_freeN(ccgdm->vertMap); - MEM_freeN(ccgdm->edgeMap); - MEM_freeN(ccgdm->faceMap); - } + MEM_freeN(ccgdm->vertMap); + MEM_freeN(ccgdm->edgeMap); + MEM_freeN(ccgdm->faceMap); BLI_mutex_end(&ccgdm->loops_cache_lock); BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock); @@ -2417,76 +2291,44 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss)); } -/* Fill in only geometry arrays needed for the GPU tessellation. */ -static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm, DerivedMesh *dm) -{ - const int totface = dm->getNumPolys(dm); - MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); - int index; - DMFlagMat *faceFlags = ccgdm->faceFlags; - - for (index = 0; index < totface; index++) { - faceFlags->flag = mpoly ? mpoly[index].flag : 0; - faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0; - faceFlags++; - } - - /* TODO(sergey): Fill in edge flags. */ -} - -static CCGDerivedMesh *getCCGDerivedMesh( - CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, DerivedMesh *dm, bool use_gpu_backend) +static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, + int drawInteriorEdges, + int useSubsurfUv, + DerivedMesh *dm) { -#ifdef WITH_OPENSUBDIV - const int totedge = dm->getNumEdges(dm); - const int totface = dm->getNumPolys(dm); -#else const int totedge = ccgSubSurf_getNumEdges(ss); const int totface = ccgSubSurf_getNumFaces(ss); -#endif CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); - if (use_gpu_backend == false) { - BLI_assert(totedge == ccgSubSurf_getNumEdges(ss)); - BLI_assert(totface == ccgSubSurf_getNumFaces(ss)); - DM_from_template(&ccgdm->dm, - dm, - DM_TYPE_CCGDM, - ccgSubSurf_getNumFinalVerts(ss), - ccgSubSurf_getNumFinalEdges(ss), - 0, - ccgSubSurf_getNumFinalFaces(ss) * 4, - ccgSubSurf_getNumFinalFaces(ss)); + BLI_assert(totedge == ccgSubSurf_getNumEdges(ss)); + BLI_assert(totface == ccgSubSurf_getNumFaces(ss)); + DM_from_template(&ccgdm->dm, + dm, + DM_TYPE_CCGDM, + ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + 0, + ccgSubSurf_getNumFinalFaces(ss) * 4, + ccgSubSurf_getNumFinalFaces(ss)); - CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData); + CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData); - ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), - "reverseFaceMap"); + ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), + "reverseFaceMap"); - create_ccgdm_maps(ccgdm, ss); - } - else { - DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, 0, 0, 0, 0, dm->getNumPolys(dm)); - CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, 0, 0, dm->getNumPolys(dm)); - } + create_ccgdm_maps(ccgdm, ss); set_default_ccgdm_callbacks(ccgdm); ccgdm->ss = ss; ccgdm->drawInteriorEdges = drawInteriorEdges; ccgdm->useSubsurfUv = useSubsurfUv; - ccgdm->useGpuBackend = use_gpu_backend; /* CDDM hack. */ ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags"); ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags"); - if (use_gpu_backend == false) { - set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0); - } - else { - set_ccgdm_gpu_geometry(ccgdm, dm); - } + set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0); ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss); ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss); @@ -2502,21 +2344,6 @@ static CCGDerivedMesh *getCCGDerivedMesh( /***/ -static bool subsurf_use_gpu_backend(SubsurfFlags flags) -{ -#ifdef WITH_OPENSUBDIV - /* Use GPU backend if it's a last modifier in the stack - * and user chose to use any of the OSD compute devices, - * but also check if GPU has all needed features. - */ - return (flags & SUBSURF_USE_GPU_BACKEND) != 0 && - (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE); -#else - (void)flags; - return false; -#endif -} - struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, struct SubsurfModifierData *smd, const struct Scene *scene, @@ -2527,7 +2354,6 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0; const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE); const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); - const bool use_gpu_backend = subsurf_use_gpu_backend(flags); const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY); CCGDerivedMesh *result; @@ -2546,11 +2372,8 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS); -#ifdef WITH_OPENSUBDIV - ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend); -#endif ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); + result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm); } else if (flags & SUBSURF_USE_RENDER_PARAMS) { /* Do not use cache in render mode. */ @@ -2567,7 +2390,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, false); + result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); result->freeSS = 1; } @@ -2600,32 +2423,15 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm, false); + result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm); } else { CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS; CCGSubSurf *prevSS = NULL; if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) { -#ifdef WITH_OPENSUBDIV - /* With OpenSubdiv enabled we always tries to re-use previous - * subsurf structure in order to save computation time since - * re-creation is rather a complicated business. - * - * TODO(sergey): There was a good reason why final calculation - * used to free entirely cached subsurf structure. reason of - * this is to be investigated still to be sure we don't have - * regressions here. - */ - if (use_gpu_backend) { - prevSS = smd->mCache; - } - else -#endif - { - ccgSubSurf_free(smd->mCache); - smd->mCache = NULL; - } + ccgSubSurf_free(smd->mCache); + smd->mCache = NULL; } if (flags & SUBSURF_ALLOC_PAINT_MASK) { @@ -2633,12 +2439,9 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, } ss = _getSubSurf(prevSS, levels, 3, ccg_flags); -#ifdef WITH_OPENSUBDIV - ccgSubSurf_setSkipGrids(ss, use_gpu_backend); -#endif ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); + result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); if (flags & SUBSURF_IS_FINAL_CALC) { smd->mCache = ss; @@ -2710,26 +2513,10 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3]) bool subsurf_has_edges(DerivedMesh *dm) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - return true; - } -#else - (void)ccgdm; -#endif return dm->getNumEdges(dm) != 0; } bool subsurf_has_faces(DerivedMesh *dm) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - return true; - } -#else - (void)ccgdm; -#endif return dm->getNumPolys(dm) != 0; } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 3cdf3b40ce3..527b54a1aa2 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -206,6 +206,7 @@ IDTypeInfo IDType_ID_TXT = { .copy_data = text_copy_data, .free_data = text_free_data, .make_local = NULL, + .foreach_id = NULL, }; /***/ diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 629c01ec298..dcaa9082026 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -713,7 +713,7 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf) */ const size_t size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float); grayscale->channels = 1; - if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) { + if ((grayscale->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) { grayscale->mall |= IB_rectfloat; grayscale->flags |= IB_rectfloat; @@ -741,7 +741,7 @@ static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image) ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0); size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float); ibuf->channels = float_image->channels; - if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) { + if ((ibuf->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) { ibuf->mall |= IB_rectfloat; ibuf->flags |= IB_rectfloat; diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 9e636c0ee8b..26c5810aefa 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -21,6 +21,7 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_volume_types.h" @@ -442,26 +443,6 @@ static void volume_init_data(ID *id) BKE_volume_init_grids(volume); } -void BKE_volume_init_grids(Volume *volume) -{ -#ifdef WITH_OPENVDB - if (volume->runtime.grids == NULL) { - volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector); - } -#else - UNUSED_VARS(volume); -#endif -} - -void *BKE_volume_add(Main *bmain, const char *name) -{ - Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0); - - volume_init_data(&volume->id); - - return volume; -} - static void volume_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, @@ -483,18 +464,6 @@ static void volume_copy_data(Main *UNUSED(bmain), #endif } -Volume *BKE_volume_copy(Main *bmain, const Volume *volume) -{ - Volume *volume_copy; - BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy); - return volume_copy; -} - -static void volume_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - static void volume_free_data(ID *id) { Volume *volume = (Volume *)id; @@ -506,6 +475,14 @@ static void volume_free_data(ID *id) #endif } +static void volume_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Volume *volume = (Volume *)id; + for (int i = 0; i < volume->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, volume->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_VO = { /* id_code */ ID_VO, /* id_filter */ FILTER_ID_VO, @@ -519,9 +496,37 @@ IDTypeInfo IDType_ID_VO = { /* init_data */ volume_init_data, /* copy_data */ volume_copy_data, /* free_data */ volume_free_data, - /* make_local */ volume_make_local, + /* make_local */ nullptr, + /* foreach_id */ volume_foreach_id, }; +void BKE_volume_init_grids(Volume *volume) +{ +#ifdef WITH_OPENVDB + if (volume->runtime.grids == NULL) { + volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector); + } +#else + UNUSED_VARS(volume); +#endif +} + +void *BKE_volume_add(Main *bmain, const char *name) +{ + Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0); + + volume_init_data(&volume->id); + + return volume; +} + +Volume *BKE_volume_copy(Main *bmain, const Volume *volume) +{ + Volume *volume_copy; + BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy); + return volume_copy; +} + /* Sequence */ static int volume_sequence_frame(const Depsgraph *depsgraph, const Volume *volume) diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index c65d55785c1..4625fd76293 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -32,6 +32,7 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -65,6 +66,15 @@ static void workspace_free_data(ID *id) MEM_SAFE_FREE(workspace->status_text); } +static void workspace_foreach_id(ID *id, LibraryForeachIDData *data) +{ + WorkSpace *workspace = (WorkSpace *)id; + + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { + BKE_LIB_FOREACHID_PROCESS(data, layout->screen, IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_WS = { .id_code = ID_WS, .id_filter = FILTER_ID_WS, @@ -79,6 +89,7 @@ IDTypeInfo IDType_ID_WS = { .copy_data = NULL, .free_data = workspace_free_data, .make_local = NULL, + .foreach_id = workspace_foreach_id, }; /** \name Internal Utils @@ -209,7 +220,7 @@ WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain) /* set an active screen-layout for each possible window/workspace combination */ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { - BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first); + BKE_workspace_active_layout_set(hook, workspace, workspace->layouts.first); } return hook; @@ -414,6 +425,10 @@ WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook) } void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) { + if (hook->active == workspace) { + return; + } + hook->active = workspace; if (workspace) { WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent( @@ -424,13 +439,47 @@ void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) } } +/** + * Get the layout that is active for \a hook (which is the visible layout for the active workspace + * in \a hook). + */ WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) { return hook->act_layout; } -void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout) + +/** + * Get the layout to be activated should \a workspace become or be the active workspace in \a hook. + */ +WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceInstanceHook *hook, + const WorkSpace *workspace) +{ + /* If the workspace is active, the active layout can be returned, no need for a lookup. */ + if (hook->active == workspace) { + return hook->act_layout; + } + + /* Inactive workspace */ + return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook); +} + +/** + * \brief Activate a layout + * + * Sets \a layout as active for \a workspace when activated through or already active in \a hook. + * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of + * \a hook too. See #BKE_workspace_active_set(). + * + * \a workspace does not need to be active for this. + * + * WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer. + */ +void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, + WorkSpace *workspace, + WorkSpaceLayout *layout) { hook->act_layout = layout; + workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout); } bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) @@ -443,12 +492,7 @@ void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, { /* we need to find the WorkspaceLayout that wraps this screen */ WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen); - BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout); -} - -ListBase *BKE_workspace_layouts_get(WorkSpace *workspace) -{ - return &workspace->layouts; + BKE_workspace_active_layout_set(hook, workspace, layout); } const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout) @@ -466,22 +510,5 @@ bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout) { return layout->screen; } -void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen) -{ - layout->screen = screen; -} - -WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(const WorkSpaceInstanceHook *hook, - const WorkSpace *workspace) -{ - return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook); -} -void BKE_workspace_hook_layout_for_workspace_set(WorkSpaceInstanceHook *hook, - WorkSpace *workspace, - WorkSpaceLayout *layout) -{ - hook->act_layout = layout; - workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout); -} /** \} */ diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 16e56200131..724c4ab93b2 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -606,7 +606,10 @@ static AVStream *alloc_video_stream(FFMpegContext *context, c->gop_size = context->ffmpeg_gop_size; c->max_b_frames = context->ffmpeg_max_b_frames; - if (context->ffmpeg_crf >= 0) { + if (context->ffmpeg_type == FFMPEG_WEBM && context->ffmpeg_crf == 0) { + ffmpeg_dict_set_int(&opts, "lossless", 1); + } + else if (context->ffmpeg_crf >= 0) { ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf); } else { diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h index b9cb32a310e..603be115b35 100644 --- a/source/blender/blenlib/BLI_assert.h +++ b/source/blender/blenlib/BLI_assert.h @@ -69,7 +69,13 @@ extern "C" { # endif /* _BLI_ASSERT_ABORT */ # ifdef WITH_ASSERT_ABORT -# define _BLI_ASSERT_ABORT abort +# ifdef __GNUC__ +/* Cast to remove 'noreturn' attribute since this suppresses missing return statements, + * allowing changes to debug builds to accidentally to break release builds. */ +# define _BLI_ASSERT_ABORT ((void (*)(void))(*(((void **)abort)))) +# else +# define _BLI_ASSERT_ABORT abort +# endif # else # define _BLI_ASSERT_ABORT() (void)0 # endif diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index af28e826e84..d46c02a961c 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -436,6 +436,7 @@ MINLINE void normal_short_to_float_v3(float r[3], const short n[3]); MINLINE void normal_float_to_short_v3(short r[3], const float n[3]); MINLINE void normal_float_to_short_v4(short r[4], const float n[4]); +void minmax_v4v4_v4(float min[4], float max[4], const float vec[4]); void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]); void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]); diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 64dfdc2ad25..a4a855c354b 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -237,6 +237,82 @@ BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *setti * Only here for code to be removed. */ int BLI_task_parallel_thread_id(const TaskParallelTLS *tls); +/* Task Graph Scheduling */ +/* Task Graphs can be used to create a forest of directional trees and schedule work to any tree. + * The nodes in the graph can be run in separate threads. + * + * +---- [root] ----+ + * | | + * v v + * [node_1] +---- [node_2] ----+ + * | | + * v v + * [node_3] [node_4] + * + * TaskGraph *task_graph = BLI_task_graph_create(); + * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL); + * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); + * + * BLI_task_graph_edge_create(root, node_1); + * BLI_task_graph_edge_create(root, node_2); + * BLI_task_graph_edge_create(node_2, node_3); + * BLI_task_graph_edge_create(node_2, node_4); + * + * Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but + * it is supported to start the chain of tasks anywhere in the forest or tree. When a node + * completes, the execution flow is forwarded via the created edges. + * When a child node has multiple parents the child node will be triggered once for each parent. + * + * BLI_task_graph_node_push_work(root); + * + * In this example After `root` is finished, `node_1` and `node_2` will be started. + * Only after `node_2` is finished `node_3` and `node_4` will be started. + * + * After scheduling work we need to wait until all the tasks have been finished. + * + * BLI_task_graph_work_and_wait(); + * + * When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by + * the graph and are freed task_data will only be freed if a free_func was given. + * + * BLI_task_graph_free(task_graph); + * + * Work can enter a tree on any node. Normally this would be the root_node. + * A `task_graph` can be reused, but the caller needs to make sure the task_data is reset. + * + * ** Task-Data ** + * + * Typically you want give a task data to work on. + * Task data can be shared with other nodes, but be carefull not to free the data multiple times. + * Task data is freed when calling `BLI_task_graph_free`. + * + * MyData *task_data = MEM_callocN(sizeof(MyData), __func__); + * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN); + * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); + * + */ +struct TaskGraph; +struct TaskNode; + +typedef void (*TaskGraphNodeRunFunction)(void *__restrict task_data); +typedef void (*TaskGraphNodeFreeFunction)(void *task_data); + +struct TaskGraph *BLI_task_graph_create(void); +void BLI_task_graph_work_and_wait(struct TaskGraph *task_graph); +void BLI_task_graph_free(struct TaskGraph *task_graph); +struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph, + TaskGraphNodeRunFunction run, + void *task_data, + TaskGraphNodeFreeFunction free_func); +bool BLI_task_graph_node_push_work(struct TaskNode *task_node); +void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index c199417017b..03fe27c10ed 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -58,9 +58,6 @@ void BLI_threadpool_clear(struct ListBase *threadbase); void BLI_threadpool_end(struct ListBase *threadbase); int BLI_thread_is_main(void); -void BLI_threaded_malloc_begin(void); -void BLI_threaded_malloc_end(void); - /* System Information */ int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */ diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index 9f887513816..f402f47c357 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -140,7 +140,7 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet { VectorSet(const VectorSet &other) : m_array(other.m_array) { m_elements = this->allocate_elements_array(m_array.slots_usable()); - copy_n(other.m_elements, m_array.slots_set(), m_elements); + uninitialized_copy_n(other.m_elements, m_array.slots_set(), m_elements); } VectorSet(VectorSet &&other) : m_array(std::move(other.m_array)), m_elements(other.m_elements) diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 18d58cdcaf3..7757b838afe 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -119,6 +119,7 @@ set(SRC intern/string_utf8.c intern/string_utils.c intern/system.c + intern/task_graph.cc intern/task_iterator.c intern/task_pool.cc intern/task_range.cc @@ -138,7 +139,6 @@ set(SRC intern/list_sort_impl.h - BLI_asan.h BLI_alloca.h BLI_allocator.hh BLI_args.h @@ -148,6 +148,7 @@ set(SRC BLI_array_store.h BLI_array_store_utils.h BLI_array_utils.h + BLI_asan.h BLI_assert.h BLI_astar.h BLI_bitmap.h diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c index 6ecadeecec5..83866f766df 100644 --- a/source/blender/blenlib/intern/boxpack_2d.c +++ b/source/blender/blenlib/intern/boxpack_2d.c @@ -705,7 +705,7 @@ void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase LISTBASE_FOREACH_MUTABLE (FixedSizeBoxPack *, box, boxes) { LISTBASE_FOREACH (FixedSizeBoxPack *, space, &spaces) { /* Skip this space if it's too small. */ - if (box->w > space->w || box->h > space->w) { + if (box->w > space->w || box->h > space->h) { continue; } diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 2ad9b53ba3d..1b388dcf11f 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -360,7 +360,7 @@ MINLINE int divide_floor_i(int a, int b) } /** - * Integer division that ceils the result, instead of flooring like normal C division. + * Integer division that returns the ceiling, instead of flooring like normal C division. */ MINLINE uint divide_ceil_u(uint a, uint b) { diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index a26824bd2b5..e7c1fc8c2d9 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -4220,7 +4220,19 @@ static float mean_value_half_tan_v2(const struct Float2_Len *d_curr, void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3]) { - const float eps = 1e-5f; /* take care, low values cause [#36105] */ + /* Before starting to calculate the weight, we need to figure out the floating point precision we + * can expect from the supplied data. */ + float max_value = 0; + + for (int i = 0; i < n; i++) { + max_value = max_ff(max_value, fabsf(v[i][0] - co[0])); + max_value = max_ff(max_value, fabsf(v[i][1] - co[1])); + max_value = max_ff(max_value, fabsf(v[i][2] - co[2])); + } + + /* These to values we derived by empirically testing different values that works for the test + * files in D7772. */ + const float eps = 16.0f * FLT_EPSILON * max_value; const float eps_sq = eps * eps; const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ @@ -4293,8 +4305,20 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2]) { - const float eps = 1e-5f; /* take care, low values cause [#36105] */ + /* Before starting to calculate the weight, we need to figure out the floating point precision we + * can expect from the supplied data. */ + float max_value = 0; + + for (int i = 0; i < n; i++) { + max_value = max_ff(max_value, fabsf(v[i][0] - co[0])); + max_value = max_ff(max_value, fabsf(v[i][1] - co[1])); + } + + /* These to values we derived by empirically testing different values that works for the test + * files in D7772. */ + const float eps = 16.0f * FLT_EPSILON * max_value; const float eps_sq = eps * eps; + const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ float totweight = 0.0f; diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 9009f73a62f..6ec7c960d6b 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -949,6 +949,35 @@ void print_vn(const char *str, const float v[], const int n) printf("\n"); } +void minmax_v4v4_v4(float min[4], float max[4], const float vec[4]) +{ + if (min[0] > vec[0]) { + min[0] = vec[0]; + } + if (min[1] > vec[1]) { + min[1] = vec[1]; + } + if (min[2] > vec[2]) { + min[2] = vec[2]; + } + if (min[3] > vec[3]) { + min[3] = vec[3]; + } + + if (max[0] < vec[0]) { + max[0] = vec[0]; + } + if (max[1] < vec[1]) { + max[1] = vec[1]; + } + if (max[2] < vec[2]) { + max[2] = vec[2]; + } + if (max[3] < vec[3]) { + max[3] = vec[3]; + } +} + void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]) { if (min[0] > vec[0]) { diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 87536ea8116..fbfb258693b 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -55,6 +55,7 @@ # include "utfconv.h" # include <direct.h> # include <io.h> +# include <shobjidl_core.h> # include <stdbool.h> #else # include <pwd.h> @@ -226,12 +227,18 @@ size_t BLI_file_size(const char *path) return stats.st_size; } +/* Return file attributes. Apple version of this function is defined in storage_apple.mm */ #ifndef __APPLE__ eFileAttributes BLI_file_attributes(const char *path) { int ret = 0; # ifdef WIN32 + + if (BLI_path_extension_check(path, ".lnk")) { + return FILE_ATTR_ALIAS; + } + WCHAR wline[FILE_MAXDIR]; if (conv_utf_8_to_16(path, wline, ARRAY_SIZE(wline)) != 0) { return ret; @@ -284,15 +291,52 @@ eFileAttributes BLI_file_attributes(const char *path) } #endif -/** - * Returns the target path of a file-based redirection, like Mac Alias or Win32 Shortcut file. - */ +/* Return alias/shortcut file target. Apple version is defined in storage_apple.mm */ #ifndef __APPLE__ -bool BLI_file_alias_target(char UNUSED(target[FILE_MAXDIR]), const char *UNUSED(filepath)) +bool BLI_file_alias_target(char target[FILE_MAXDIR], const char *filepath) { - /* TODO: Find target in Win32 Shortcut - Shell Link (.lnk) file. - * Format: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/ */ +# ifdef WIN32 + if (!BLI_path_extension_check(filepath, ".lnk")) { + return false; + } + + IShellLinkW *Shortcut = NULL; + bool success = false; + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + HRESULT hr = CoCreateInstance( + &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID *)&Shortcut); + if (SUCCEEDED(hr)) { + IPersistFile *PersistFile; + hr = Shortcut->lpVtbl->QueryInterface(Shortcut, &IID_IPersistFile, (LPVOID *)&PersistFile); + if (SUCCEEDED(hr)) { + WCHAR path_utf16[FILE_MAXDIR] = {0}; + if (conv_utf_8_to_16(filepath, path_utf16, ARRAY_SIZE(path_utf16)) == 0) { + hr = PersistFile->lpVtbl->Load(PersistFile, path_utf16, STGM_READ); + if (SUCCEEDED(hr)) { + hr = Shortcut->lpVtbl->Resolve(Shortcut, 0, SLR_NO_UI | SLR_UPDATE); + if (SUCCEEDED(hr)) { + wchar_t target_utf16[FILE_MAXDIR] = {0}; + hr = Shortcut->lpVtbl->GetPath(Shortcut, target_utf16, FILE_MAXDIR, NULL, 0); + if (SUCCEEDED(hr)) { + success = (conv_utf_16_to_8(target_utf16, target, FILE_MAXDIR) == 0); + } + } + PersistFile->lpVtbl->Release(PersistFile); + } + } + } + Shortcut->lpVtbl->Release(Shortcut); + } + + return (success && target[0]); +# endif + +# ifdef __linux__ + UNUSED_VARS(target, filepath); + /* File-based redirection not supported. */ return false; +# endif } #endif diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc new file mode 100644 index 00000000000..4f112c5b2c8 --- /dev/null +++ b/source/blender/blenlib/intern/task_graph.cc @@ -0,0 +1,166 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bli + * + * Task graph. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_task.h" + +#include <memory> +#include <vector> + +#ifdef WITH_TBB +/* Quiet top level deprecation message, unrelated to API usage here. */ +# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 +# include <tbb/flow_graph.h> +# include <tbb/tbb.h> +#endif + +/* Task Graph */ +struct TaskGraph { +#ifdef WITH_TBB + tbb::flow::graph tbb_graph; +#endif + std::vector<std::unique_ptr<TaskNode>> nodes; + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskGraph") +#endif +}; + +/* TaskNode - a node in the task graph. */ +struct TaskNode { + /* TBB Node. */ +#ifdef WITH_TBB + tbb::flow::continue_node<tbb::flow::continue_msg> tbb_node; +#endif + /* Successors to execute after this task, for serial execution fallback. */ + std::vector<TaskNode *> successors; + + /* User function to be executed with given task data. */ + TaskGraphNodeRunFunction run_func; + void *task_data; + /* Optional callback to free task data along with the graph. If task data + * is shared between nodes, only a single task node should free the data. */ + TaskGraphNodeFreeFunction free_func; + + TaskNode(TaskGraph *task_graph, + TaskGraphNodeRunFunction run_func, + void *task_data, + TaskGraphNodeFreeFunction free_func) + : +#ifdef WITH_TBB + tbb_node(task_graph->tbb_graph, + tbb::flow::unlimited, + std::bind(&TaskNode::run, this, std::placeholders::_1)), +#endif + run_func(run_func), + task_data(task_data), + free_func(free_func) + { +#ifndef WITH_TBB + UNUSED_VARS(task_graph); +#endif + } + + TaskNode(const TaskNode &other) = delete; + TaskNode &operator=(const TaskNode &other) = delete; + + ~TaskNode() + { + if (task_data && free_func) { + free_func(task_data); + } + } + +#ifdef WITH_TBB + tbb::flow::continue_msg run(const tbb::flow::continue_msg UNUSED(input)) + { + tbb::this_task_arena::isolate([this] { run_func(task_data); }); + return tbb::flow::continue_msg(); + } +#endif + + void run_serial() + { + run_func(task_data); + for (TaskNode *successor : successors) { + successor->run_serial(); + } + } + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskNode") +#endif +}; + +TaskGraph *BLI_task_graph_create(void) +{ + return new TaskGraph(); +} + +void BLI_task_graph_free(TaskGraph *task_graph) +{ + delete task_graph; +} + +void BLI_task_graph_work_and_wait(TaskGraph *task_graph) +{ +#ifdef WITH_TBB + task_graph->tbb_graph.wait_for_all(); +#else + UNUSED_VARS(task_graph); +#endif +} + +struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph, + TaskGraphNodeRunFunction run, + void *user_data, + TaskGraphNodeFreeFunction free_func) +{ + TaskNode *task_node = new TaskNode(task_graph, run, user_data, free_func); + task_graph->nodes.push_back(std::unique_ptr<TaskNode>(task_node)); + return task_node; +} + +bool BLI_task_graph_node_push_work(struct TaskNode *task_node) +{ +#ifdef WITH_TBB + if (BLI_task_scheduler_num_threads() > 1) { + return task_node->tbb_node.try_put(tbb::flow::continue_msg()); + } +#endif + + task_node->run_serial(); + return true; +} + +void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node) +{ +#ifdef WITH_TBB + if (BLI_task_scheduler_num_threads() > 1) { + tbb::flow::make_edge(from_node->tbb_node, to_node->tbb_node); + return; + } +#endif + + from_node->successors.push_back(to_node); +} diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc index 670787697a3..cf328ec407c 100644 --- a/source/blender/blenlib/intern/task_pool.cc +++ b/source/blender/blenlib/intern/task_pool.cc @@ -364,14 +364,6 @@ static void background_task_pool_free(TaskPool *pool) static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, TaskPriority priority) { - /* Ensure malloc will go fine from threads, - * - * This is needed because we could be in main thread here - * and malloc could be non-thread safe at this point because - * no other jobs are running. - */ - BLI_threaded_malloc_begin(); - const bool use_threads = BLI_task_scheduler_num_threads() > 1 && type != TASK_POOL_NO_THREADS; /* Background task pool uses regular TBB scheduling if available. Only when @@ -475,8 +467,6 @@ void BLI_task_pool_free(TaskPool *pool) BLI_mutex_end(&pool->user_mutex); MEM_freeN(pool); - - BLI_threaded_malloc_end(); } void BLI_task_pool_push(TaskPool *pool, diff --git a/source/blender/blenlib/intern/task_range.cc b/source/blender/blenlib/intern/task_range.cc index 55de35f0060..67d8960434e 100644 --- a/source/blender/blenlib/intern/task_range.cc +++ b/source/blender/blenlib/intern/task_range.cc @@ -128,7 +128,6 @@ void BLI_task_parallel_range(const int start, else { parallel_for(range, task); } - return; } #endif diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index f535798f86d..be43c27e945 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -104,7 +104,6 @@ static void *thread_tls_data; * BLI_threadpool_end(&lb); * ************************************************ */ -static SpinLock _malloc_lock; static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t _image_draw_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t _viewer_lock = PTHREAD_MUTEX_INITIALIZER; @@ -132,21 +131,9 @@ typedef struct ThreadSlot { int avail; } ThreadSlot; -static void BLI_lock_malloc_thread(void) -{ - BLI_spin_lock(&_malloc_lock); -} - -static void BLI_unlock_malloc_thread(void) -{ - BLI_spin_unlock(&_malloc_lock); -} - void BLI_threadapi_init(void) { mainid = pthread_self(); - - BLI_spin_init(&_malloc_lock); if (numaAPI_Initialize() == NUMAAPI_SUCCESS) { is_numa_available = true; } @@ -154,7 +141,6 @@ void BLI_threadapi_init(void) void BLI_threadapi_exit(void) { - BLI_spin_end(&_malloc_lock); } /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c) @@ -185,8 +171,6 @@ void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int t unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1); if (level == 0) { - MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread); - #ifdef USE_APPLE_OMP_FIX /* workaround for Apple gcc 4.2.1 omp vs background thread bug, * we copy gomp thread local storage pointer to setting it again @@ -313,11 +297,6 @@ void BLI_threadpool_end(ListBase *threadbase) } BLI_freelistN(threadbase); } - - unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1); - if (level == 0) { - MEM_set_lock_callback(NULL, NULL); - } } /* System Information */ @@ -811,24 +790,6 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue) pthread_mutex_unlock(&queue->mutex); } -/* ************************************************ */ - -void BLI_threaded_malloc_begin(void) -{ - unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1); - if (level == 0) { - MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread); - } -} - -void BLI_threaded_malloc_end(void) -{ - unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1); - if (level == 0) { - MEM_set_lock_callback(NULL, NULL); - } -} - /* **** Special functions to help performance on crazy NUMA setups. **** */ #if 0 /* UNUSED */ diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index adf7db0267e..1309b3e3c33 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -428,41 +428,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, * but oldmain itself shall *never* be 'transferred' to new mainlist! */ BLI_assert(old_mainlist.first == oldmain); - if (bfd && old_mainlist.first != old_mainlist.last) { - /* Even though directly used libs have been already moved to new main, - * indirect ones have not. - * This is a bit annoying, but we have no choice but to keep them all for now - - * means some now unused data may remain in memory, but think we'll have to live with it. */ - Main *libmain, *libmain_next; - Main *newmain = bfd->main; - ListBase new_mainlist = {newmain, newmain}; - - for (libmain = oldmain->next; libmain; libmain = libmain_next) { - libmain_next = libmain->next; - /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL - * parent to detect indirect-linked ones. */ - if (libmain->curlib && (libmain->curlib->parent != NULL)) { - BLI_remlink(&old_mainlist, libmain); - BLI_addtail(&new_mainlist, libmain); - } - else { -#ifdef PRINT_DEBUG - printf("Dropped Main for lib: %s\n", libmain->curlib->id.name); -#endif - } - } - /* In any case, we need to move all lib data-blocks themselves - those are - * 'first level data', getting rid of them would imply updating spaces & co - * to prevent invalid pointers access. */ - BLI_movelisttolist(&newmain->libraries, &oldmain->libraries); - - blo_join_main(&new_mainlist); - } - -#if 0 - printf("Remaining mains/libs in oldmain: %d\n", BLI_listbase_count(&fd->old_mainlist) - 1); -#endif - /* That way, libs (aka mains) we did not reuse in new undone/redone state * will be cleared together with oldmain... */ blo_join_main(&old_mainlist); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1ee9de3796a..db63091ce36 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -692,7 +692,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab /* Important, consistency with main ID reading code from read_libblock(). */ lib->id.us = ID_FAKE_USERS(lib); - /* Matches lib_link_library(). */ + /* Matches direct_link_library(). */ id_us_ensure_real(&lib->id); BLI_strncpy(lib->name, filepath, sizeof(lib->name)); @@ -3416,11 +3416,6 @@ static void lib_link_nladata_strips(FileData *fd, ID *id, ListBase *list) /* reassign the counted-reference to action */ strip->act = newlibadr(fd, id->lib, strip->act); - - /* fix action id-root (i.e. if it comes from a pre 2.57 .blend file) */ - if ((strip->act) && (strip->act->idroot == 0)) { - strip->act->idroot = GS(id->name); - } } } @@ -3515,14 +3510,6 @@ static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt) adt->action = newlibadr(fd, id->lib, adt->action); adt->tmpact = newlibadr(fd, id->lib, adt->tmpact); - /* fix action id-roots (i.e. if they come from a pre 2.57 .blend file) */ - if ((adt->action) && (adt->action->idroot == 0)) { - adt->action->idroot = GS(id->name); - } - if ((adt->tmpact) && (adt->tmpact->idroot == 0)) { - adt->tmpact->idroot = GS(id->name); - } - /* link drivers */ lib_link_fcurves(fd, id, &adt->drivers); @@ -3593,15 +3580,11 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file) static void lib_link_workspaces(FileData *fd, Main *bmain, WorkSpace *workspace) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); ID *id = (ID *)workspace; - id_us_ensure_real(id); - - for (WorkSpaceLayout *layout = layouts->first, *layout_next; layout; layout = layout_next) { + LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout, &workspace->layouts) { layout->screen = newlibadr(fd, id->lib, layout->screen); - layout_next = layout->next; if (layout->screen) { if (ID_IS_LINKED(id)) { layout->screen->winid = 0; @@ -3621,16 +3604,14 @@ static void lib_link_workspaces(FileData *fd, Main *bmain, WorkSpace *workspace) static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main *main) { - link_list(fd, BKE_workspace_layouts_get(workspace)); + link_list(fd, &workspace->layouts); link_list(fd, &workspace->hook_layout_relations); link_list(fd, &workspace->owner_ids); link_list(fd, &workspace->tools); LISTBASE_FOREACH (WorkSpaceDataRelation *, relation, &workspace->hook_layout_relations) { - /* data from window - need to access through global oldnew-map */ relation->parent = newglobadr(fd, relation->parent); - relation->value = newdataadr(fd, relation->value); } @@ -3638,11 +3619,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main * when reading windows, so have to update windows after/when reading workspaces. */ for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - WorkSpaceLayout *act_layout = newdataadr( - fd, BKE_workspace_active_layout_get(win->workspace_hook)); - if (act_layout) { - BKE_workspace_active_layout_set(win->workspace_hook, act_layout); - } + win->workspace_hook->act_layout = newdataadr(fd, win->workspace_hook->act_layout); } } @@ -3653,6 +3630,8 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main } workspace->status_text = NULL; + + id_us_ensure_real(&workspace->id); } static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id) @@ -3898,23 +3877,23 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) } #if 0 - if (ntree->previews) { - bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews"); - bNodeInstanceHashIterator iter; - - NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { - bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter); - if (preview) { - bNodePreview* new_preview = newimaadr(fd, preview); - if (new_preview) { - bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); - BKE_node_instance_hash_insert(new_previews, key, new_preview); - } - } - } - BKE_node_instance_hash_free(ntree->previews, NULL); - ntree->previews = new_previews; - } + if (ntree->previews) { + bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews"); + bNodeInstanceHashIterator iter; + + NODE_INSTANCE_HASH_ITER(iter, ntree->previews) { + bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter); + if (preview) { + bNodePreview* new_preview = newimaadr(fd, preview); + if (new_preview) { + bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); + BKE_node_instance_hash_insert(new_previews, key, new_preview); + } + } + } + BKE_node_instance_hash_free(ntree->previews, NULL); + ntree->previews = new_previews; + } #else /* XXX TODO */ ntree->previews = NULL; @@ -4364,10 +4343,10 @@ static void direct_link_text(FileData *fd, Text *text) text->compiled = NULL; #if 0 - if (text->flags & TXT_ISEXT) { - BKE_text_reload(text); - } - /* else { */ + if (text->flags & TXT_ISEXT) { + BKE_text_reload(text); + } + /* else { */ #endif link_list(fd, &text->lines); @@ -5355,7 +5334,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob) * some leaked memory rather then crashing immediately * while bad this _is_ an exceptional case - campbell */ #if 0 - BKE_pose_free(ob->pose); + BKE_pose_free(ob->pose); #else MEM_freeN(ob->pose); #endif @@ -5832,15 +5811,15 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob) else if (md->type == eModifierType_Collision) { CollisionModifierData *collmd = (CollisionModifierData *)md; #if 0 - // TODO: CollisionModifier should use pointcache - // + have proper reset events before enabling this - collmd->x = newdataadr(fd, collmd->x); - collmd->xnew = newdataadr(fd, collmd->xnew); - collmd->mfaces = newdataadr(fd, collmd->mfaces); - - collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x"); - collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew"); - collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v"); + // TODO: CollisionModifier should use pointcache + // + have proper reset events before enabling this + collmd->x = newdataadr(fd, collmd->x); + collmd->xnew = newdataadr(fd, collmd->xnew); + collmd->mfaces = newdataadr(fd, collmd->mfaces); + + collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x"); + collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew"); + collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v"); #endif collmd->x = NULL; @@ -7594,10 +7573,10 @@ static void direct_link_area(FileData *fd, ScrArea *area) * so sacrifice a few old files for now to avoid crashes with new files! * committed: r28002 */ #if 0 - sima->gpd = newdataadr(fd, sima->gpd); - if (sima->gpd) { - direct_link_gpencil(fd, sima->gpd); - } + sima->gpd = newdataadr(fd, sima->gpd); + if (sima->gpd) { + direct_link_gpencil(fd, sima->gpd); + } #endif } else if (sl->spacetype == SPACE_NODE) { @@ -7628,10 +7607,10 @@ static void direct_link_area(FileData *fd, ScrArea *area) * simple return NULL here (sergey) */ #if 0 - if (sseq->gpd) { - sseq->gpd = newdataadr(fd, sseq->gpd); - direct_link_gpencil(fd, sseq->gpd); - } + if (sseq->gpd) { + sseq->gpd = newdataadr(fd, sseq->gpd); + direct_link_gpencil(fd, sseq->gpd); + } #endif sseq->scopes.reference_ibuf = NULL; sseq->scopes.zebra_ibuf = NULL; @@ -8253,23 +8232,9 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; - ARegion *region; v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL); v3d->ob_center = restore_pointer_by_name(id_map, (ID *)v3d->ob_center, USER_REAL); - - /* Free render engines for now. */ - ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : - &sl->regionbase; - for (region = regionbase->first; region; region = region->next) { - if (region->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = region->regiondata; - if (rv3d && rv3d->render_engine) { - RE_engine_free(rv3d->render_engine); - rv3d->render_engine = NULL; - } - } - } } else if (sl->spacetype == SPACE_GRAPH) { SpaceGraph *sipo = (SpaceGraph *)sl; @@ -8332,11 +8297,11 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, sima->iuser.scene = NULL; #if 0 - /* Those are allocated and freed by space code, no need to handle them here. */ - MEM_SAFE_FREE(sima->scopes.waveform_1); - MEM_SAFE_FREE(sima->scopes.waveform_2); - MEM_SAFE_FREE(sima->scopes.waveform_3); - MEM_SAFE_FREE(sima->scopes.vecscope); + /* Those are allocated and freed by space code, no need to handle them here. */ + MEM_SAFE_FREE(sima->scopes.waveform_1); + MEM_SAFE_FREE(sima->scopes.waveform_2); + MEM_SAFE_FREE(sima->scopes.waveform_3); + MEM_SAFE_FREE(sima->scopes.vecscope); #endif sima->scopes.ok = 0; @@ -8487,9 +8452,7 @@ void blo_lib_link_restore(Main *oldmain, for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { lib_link_workspace_layout_restore(id_map, newmain, layout); } } @@ -8637,11 +8600,12 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) newmain->curlib = lib; lib->parent = NULL; + + id_us_ensure_real(&lib->id); } -static void lib_link_library(FileData *UNUSED(fd), Main *UNUSED(bmain), Library *lib) +static void lib_link_library(FileData *UNUSED(fd), Main *UNUSED(bmain), Library *UNUSED(lib)) { - id_us_ensure_real(&lib->id); } /* Always call this once you have loaded new library data to set the relative paths correctly @@ -8709,8 +8673,8 @@ static void direct_link_speaker(FileData *fd, Speaker *spk) direct_link_animdata(fd, spk->adt); #if 0 - spk->sound = newdataadr(fd, spk->sound); - direct_link_sound(fd, spk->sound); + spk->sound = newdataadr(fd, spk->sound); + direct_link_sound(fd, spk->sound); #endif } @@ -9584,12 +9548,12 @@ static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *all while (bhead && bhead->code == DATA) { void *data; #if 0 - /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ - short* sp = fd->filesdna->structs[bhead->SDNAnr]; - char* tmp = malloc(100); - allocname = fd->filesdna->types[sp[0]]; - strcpy(tmp, allocname); - data = read_struct(fd, bhead, tmp); + /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ + short* sp = fd->filesdna->structs[bhead->SDNAnr]; + char* tmp = malloc(100); + allocname = fd->filesdna->types[sp[0]]; + strcpy(tmp, allocname); + data = read_struct(fd, bhead, tmp); #else data = read_struct(fd, bhead, allocname); #endif @@ -9696,7 +9660,8 @@ static void read_libblock_undo_restore_identical( BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0); BLI_assert(id_old != NULL); - id_old->tag = tag; + /* Some tags need to be preserved here. */ + id_old->tag = tag | (id_old->tag & LIB_TAG_EXTRAUSER); id_old->lib = main->curlib; id_old->us = ID_FAKE_USERS(id_old); /* Do not reset id->icon_id here, memory allocated for it remains valid. */ @@ -9794,7 +9759,7 @@ static bool read_libblock_undo_restore( } /* Restore local datablocks. */ - DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid); + DEBUG_PRINTF("UNDO: read %s (uuid %u) -> ", id->name, id->session_uuid); ID *id_old = NULL; const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; @@ -10115,6 +10080,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports) do_versions_after_linking_260(main); do_versions_after_linking_270(main); do_versions_after_linking_280(main, reports); + do_versions_after_linking_290(main, reports); do_versions_after_linking_cycles(main); main->is_locked_for_linking = false; @@ -10662,7 +10628,7 @@ static BHead *find_previous_lib(FileData *fd, BHead *bhead) static BHead *find_bhead(FileData *fd, void *old) { #if 0 - BHead* bhead; + BHead* bhead; #endif struct BHeadSort *bhs, bhs_s; @@ -10682,11 +10648,11 @@ static BHead *find_bhead(FileData *fd, void *old) } #if 0 - for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { - if (bhead->old == old) { - return bhead; - } - } + for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { + if (bhead->old == old) { + return bhead; + } + } #endif return NULL; @@ -10817,9 +10783,9 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) /* Commented because this can print way too much. */ #if 0 - if (G.debug & G_DEBUG) { - printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name); - } + if (G.debug & G_DEBUG) { + printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name); + } #endif } @@ -11707,9 +11673,7 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout)); } } @@ -12693,9 +12657,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) /* Does this library have any more linked data-blocks we need to read? */ if (has_linked_ids_to_read(mainptr)) { #if 0 - printf("Reading linked data-blocks from %s (%s)\n", - mainptr->curlib->id.name, - mainptr->curlib->name); + printf("Reading linked data-blocks from %s (%s)\n", + mainptr->curlib->id.name, + mainptr->curlib->name); #endif /* Open file if it has not been done yet. */ diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 55abbe703de..f698d642e33 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -205,7 +205,8 @@ void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Mai void do_versions_after_linking_250(struct Main *bmain); void do_versions_after_linking_260(struct Main *bmain); void do_versions_after_linking_270(struct Main *bmain); -void do_versions_after_linking_280(struct Main *bmain, ReportList *reports); +void do_versions_after_linking_280(struct Main *bmain, struct ReportList *reports); +void do_versions_after_linking_290(struct Main *bmain, struct ReportList *reports); void do_versions_after_linking_cycles(struct Main *bmain); #endif diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 62cda5d8feb..eaeef0d52c1 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -61,6 +61,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_anim_data.h" #include "BKE_anim_visualization.h" #include "BKE_armature.h" #include "BKE_colortools.h" @@ -2352,4 +2353,32 @@ void do_versions_after_linking_250(Main *bmain) } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 258, 0)) { + /* Some very old (original comments claim pre-2.57) versioning that was wrongly done in + * lib-linking code... Putting it here just to be sure (this is also checked at runtime anyway + * by `action_idcode_patch_check`). */ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + AnimData *adt = BKE_animdata_from_id(id); + if (adt != NULL) { + /* Fix actions' id-roots (i.e. if they come from a pre 2.57 .blend file). */ + if ((adt->action) && (adt->action->idroot == 0)) { + adt->action->idroot = GS(id->name); + } + if ((adt->tmpact) && (adt->tmpact->idroot == 0)) { + adt->tmpact->idroot = GS(id->name); + } + + LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) { + LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) { + if ((nla_strip->act) && (nla_strip->act->idroot == 0)) { + nla_strip->act->idroot = GS(id->name); + } + } + } + } + } + FOREACH_MAIN_ID_END; + } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 70b69d7799b..de8391de6c8 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -257,7 +257,7 @@ static void do_version_workspaces_after_lib_link(Main *bmain) win->workspace_hook = BKE_workspace_instance_hook_create(bmain); BKE_workspace_active_set(win->workspace_hook, workspace); - BKE_workspace_active_layout_set(win->workspace_hook, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); /* Move scene and view layer to window. */ Scene *scene = screen->scene; @@ -1737,144 +1737,6 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) } } - if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) { - /* Patch old grease pencil modifiers material filter. */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { - switch (md->type) { - case eGpencilModifierType_Array: { - ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Color: { - ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Hook: { - HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Lattice: { - LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Mirror: { - MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Multiply: { - MultiplyGpencilModifierData *gpmd = (MultiplyGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Noise: { - NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Offset: { - OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Opacity: { - OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Simplify: { - SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Smooth: { - SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Subdiv: { - SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Texture: { - TextureGpencilModifierData *gpmd = (TextureGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - case eGpencilModifierType_Thick: { - ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; - if (gpmd->materialname[0] != '\0') { - gpmd->material = BLI_findstring( - &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); - gpmd->materialname[0] = '\0'; - } - break; - } - default: - break; - } - } - } - } - /** * Versioning code until next subversion bump goes here. * @@ -3040,8 +2902,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | - V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | - V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS; + V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS; } } } diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 3b7e7c21b28..6574c983b09 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -25,6 +25,9 @@ #include "DNA_brush_types.h" #include "DNA_genfile.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_collection.h" @@ -38,6 +41,161 @@ /* Make preferences read-only, use versioning_userdef.c. */ #define U (*((const UserDef *)&U)) +void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) +{ + if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) { + /* Patch old grease pencil modifiers material filter. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { + switch (md->type) { + case eGpencilModifierType_Array: { + ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Color: { + ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Hook: { + HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Lattice: { + LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Mirror: { + MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Multiply: { + MultiplyGpencilModifierData *gpmd = (MultiplyGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Noise: { + NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Offset: { + OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Opacity: { + OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Simplify: { + SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Smooth: { + SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Subdiv: { + SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Texture: { + TextureGpencilModifierData *gpmd = (TextureGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + case eGpencilModifierType_Thick: { + ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; + if (gpmd->materialname[0] != '\0') { + gpmd->material = BLI_findstring( + &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2); + gpmd->materialname[0] = '\0'; + } + break; + } + default: + break; + } + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - #blo_do_versions_290 in this file. + * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + } +} + void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) { UNUSED_VARS(fd); @@ -85,6 +243,18 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 290, 4)) { + /* Clear old deprecated bitflag from edit weights modifiers, we now use it for something else. + */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_WeightVGEdit) { + md->flag &= ~MOD_WVG_EDIT_WEIGHTS_NORMALIZE; + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 9d3b44f8447..57c9ca16693 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -202,6 +202,8 @@ static void blo_update_defaults_screen(bScreen *screen, if (v3d->shading.background_type != V3D_SHADING_BACKGROUND_VIEWPORT) { copy_v3_fl(v3d->shading.background_color, 0.05f); } + /* Disable Curve Normals. */ + v3d->overlay.edit_flag &= ~V3D_OVERLAY_EDIT_CU_NORMALS; } else if (area->spacetype == SPACE_CLIP) { SpaceClip *sclip = area->spacedata.first; @@ -249,8 +251,7 @@ static void blo_update_defaults_screen(bScreen *screen, void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_template) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { if (layout->screen) { blo_update_defaults_screen(layout->screen, app_template, workspace->id.name + 2); } @@ -269,7 +270,7 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat /* For Sculpting template. */ if (STREQ(workspace->id.name + 2, "Sculpting")) { - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { bScreen *screen = layout->screen; if (screen) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { @@ -487,8 +488,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) { - WorkSpaceLayout *layout = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, - workspace); + WorkSpaceLayout *layout = BKE_workspace_active_layout_for_workspace_get( + win->workspace_hook, workspace); /* Name all screens by their workspaces (avoids 'Default.###' names). */ /* Default only has one window. */ if (layout->screen) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index f01cc14a284..c7d9fbf7268 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -3800,11 +3800,9 @@ static void write_cachefile(WriteData *wd, CacheFile *cache_file, const void *id static void write_workspace(WriteData *wd, WorkSpace *workspace, const void *id_address) { - ListBase *layouts = BKE_workspace_layouts_get(workspace); - writestruct_at_address(wd, ID_WS, WorkSpace, 1, id_address, workspace); write_iddata(wd, &workspace->id); - writelist(wd, DATA, WorkSpaceLayout, layouts); + writelist(wd, DATA, WorkSpaceLayout, &workspace->layouts); writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations); writelist(wd, DATA, wmOwnerID, &workspace->owner_ids); writelist(wd, DATA, bToolRef, &workspace->tools); @@ -3928,6 +3926,11 @@ static void write_libraries(WriteData *wd, Main *main) if (main->curlib && main->curlib->packedfile) { found_one = true; } + else if (wd->use_memfile) { + /* When writing undo step we always write all existing libraries, makes reading undo step + * much easier when dealing with purely indirectly used libraries. */ + found_one = true; + } else { found_one = false; while (!found_one && tot--) { @@ -4015,12 +4018,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) fg.globalf = G.f; BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename)); - sprintf(subvstr, "%4d", BLENDER_SUBVERSION); + sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION); memcpy(fg.subvstr, subvstr, 4); - fg.subversion = BLENDER_SUBVERSION; - fg.minversion = BLENDER_MINVERSION; - fg.minsubversion = BLENDER_MINSUBVERSION; + fg.subversion = BLENDER_FILE_SUBVERSION; + fg.minversion = BLENDER_FILE_MIN_VERSION; + fg.minsubversion = BLENDER_FILE_MIN_SUBVERSION; #ifdef WITH_BUILDINFO { extern unsigned long build_commit_timestamp; @@ -4074,7 +4077,7 @@ static bool write_file_handle(Main *mainvar, "BLENDER%c%c%.3d", (sizeof(void *) == 8) ? '-' : '_', (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v', - BLENDER_VERSION); + BLENDER_FILE_VERSION); mywrite(wd, buf, 12); @@ -4149,6 +4152,11 @@ static bool write_file_handle(Main *mainvar, memcpy(id_buffer, id, idtype_struct_size); ((ID *)id_buffer)->tag = 0; + /* Those listbase data change everytime we add/remove an ID, and also often when renaming + * one (due to re-sorting). This avoids generating a lot of false 'is changed' detections + * between undo steps. */ + ((ID *)id_buffer)->prev = NULL; + ((ID *)id_buffer)->next = NULL; switch ((ID_Type)GS(id->name)) { case ID_WM: diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index de32d7881b0..b8508f7e12c 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -893,6 +893,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh j = bm_to_mesh_shape_layer_index_from_kb(bm, currkey); cd_shape_offset = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, j); + if (cd_shape_offset < 0) { + /* The target Mesh has more shapekeys than the BMesh. */ + continue; + } fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data"); oldkey = currkey->data; diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 255a52971bb..04cdc0020d9 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -122,6 +122,11 @@ static BMO_FlagSet bmo_enum_falloff_type[] = { {0, NULL}, }; +/* Quiet 'enum-conversion' warning. */ +#define BM_FACE ((int)BM_FACE) +#define BM_EDGE ((int)BM_EDGE) +#define BM_VERT ((int)BM_VERT) + /* * Vertex Smooth. * @@ -2074,6 +2079,10 @@ static BMOpDefine bmo_symmetrize_def = { /* clang-format on */ +#undef BM_FACE +#undef BM_EDGE +#undef BM_VERT + const BMOpDefine *bmo_opdefines[] = { &bmo_average_vert_facedata_def, &bmo_beautify_fill_def, diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index 64950411fed..e000b253000 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -1568,6 +1568,41 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, } /** + * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates. + */ +float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + const float epsilon_sq, + float r_normal[3]) +{ + const int i_prev = BM_elem_index_get(l->prev->v); + const int i_next = BM_elem_index_get(l->next->v); + const int i = BM_elem_index_get(l->v); + + float v1[3], v2[3], v_tmp[3]; + sub_v3_v3v3(v1, vertexCos[i_prev], vertexCos[i]); + sub_v3_v3v3(v2, vertexCos[i_next], vertexCos[i]); + + const float fac = ((v2[0] == 0.0f) ? + ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : + v1[1] / v2[1]) : + v1[0] / v2[0]); + + mul_v3_v3fl(v_tmp, v2, fac); + sub_v3_v3(v_tmp, v1); + if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) { + /* Not co-linear, we can compute cross-product and normalize it into normal. */ + cross_v3_v3v3(r_normal, v1, v2); + return normalize_v3(r_normal); + } + else { + copy_v3_v3(r_normal, normal_fallback); + return 0.0f; + } +} + +/** * #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon. * * Since this doesn't scale based on triangle size, fixed value works well. @@ -1577,6 +1612,15 @@ float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal); } +float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + float r_normal[3]) + +{ + return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal); +} + /** * \brief BM_loop_calc_face_normal * diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index aaf8191c5db..7e07059d4d8 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -142,6 +142,16 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL( float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + const float epsilon_sq, + float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l, + const float normal_fallback[3], + float const (*vertexCos)[3], + float r_normal[3]) ATTR_NONNULL(); + void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]); void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]); diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 64687ac154c..d661859c8e3 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1393,16 +1393,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2; BMFace *f; float vec[3], mat[4][4], phi, phid; - float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); - float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); - float depth = BMO_slot_float_get(op->slots_in, "depth"); + const float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); + const float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); + const float depth_half = 0.5f * BMO_slot_float_get(op->slots_in, "depth"); int segs = BMO_slot_int_get(op->slots_in, "segments"); const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs"); - int a; if (!segs) { return; @@ -1413,16 +1412,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) phid = 2.0f * (float)M_PI / segs; phi = 0; - depth *= 0.5f; if (cap_ends) { vec[0] = vec[1] = 0.0f; - vec[2] = -depth; + vec[2] = -depth_half; mul_m4_v3(mat, vec); cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); vec[0] = vec[1] = 0.0f; - vec[2] = depth; + vec[2] = depth_half; mul_m4_v3(mat, vec); cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); @@ -1431,23 +1429,26 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BMO_vert_flag_enable(bm, cent2, VERT_MARK); } - for (a = 0; a < segs; a++, phi += phid) { + const int side_faces_len = segs - 1; + BMFace **side_faces = MEM_mallocN(sizeof(*side_faces) * side_faces_len, __func__); + + for (int i = 0; i < segs; i++, phi += phid) { vec[0] = dia1 * sinf(phi); vec[1] = dia1 * cosf(phi); - vec[2] = -depth; + vec[2] = -depth_half; mul_m4_v3(mat, vec); v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); vec[0] = dia2 * sinf(phi); vec[1] = dia2 * cosf(phi); - vec[2] = depth; + vec[2] = depth_half; mul_m4_v3(mat, vec); v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_vert_flag_enable(bm, v1, VERT_MARK); BMO_vert_flag_enable(bm, v2, VERT_MARK); - if (a) { + if (i) { if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { @@ -1466,6 +1467,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (calc_uvs) { BMO_face_flag_enable(bm, f, FACE_MARK); } + side_faces[i - 1] = f; } else { firstv1 = v1; @@ -1476,10 +1478,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) lastv2 = v2; } - if (!a) { - return; - } - if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { @@ -1503,11 +1501,38 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset); } + /* Collapse vertices at the first end. */ + if (dia1 == 0.0f) { + if (cap_ends) { + BM_vert_kill(bm, cent1); + } + for (int i = 0; i < side_faces_len; i++) { + f = side_faces[i]; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + BM_edge_collapse(bm, l->prev->e, l->prev->v, true, true); + } + } + + /* Collapse vertices at the second end. */ + if (dia2 == 0.0f) { + if (cap_ends) { + BM_vert_kill(bm, cent2); + } + for (int i = 0; i < side_faces_len; i++) { + f = side_faces[i]; + BMLoop *l = BM_FACE_FIRST_LOOP(f); + BM_edge_collapse(bm, l->next->e, l->next->v, true, true); + } + } + if (!cap_tris) { BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); } - BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.0000005 * depth); + if (side_faces != NULL) { + MEM_freeN(side_faces); + } + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index d1ddceb00b0..720eb34bda7 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -4167,6 +4167,10 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv) if (bv->vmesh->count != 3) { return 0; } + + /* Only use the tri-corner special case if the offset is the same for every edge. */ + float offset = bv->edges[0].offset_l; + totang = 0.0f; for (i = 0; i < bv->edgecount; i++) { e = &bv->edges[i]; @@ -4178,6 +4182,11 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv) else if (absang >= 3.0f * (float)M_PI_4) { return -1; } + + if (e->is_bev && !compare_ff(e->offset_l, offset, BEVEL_EPSILON)) { + return -1; + } + totang += ang; } if (in_plane_e != bv->edgecount - 3) { diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c index 0331ca476dd..713a68969e5 100644 --- a/source/blender/bmesh/tools/bmesh_path.c +++ b/source/blender/bmesh/tools/bmesh_path.c @@ -225,7 +225,7 @@ static void edgetag_add_adjacent(HeapSimple *heap, /* unlike vert/face, stepping faces disables scanning connected edges * and only steps over faces (selecting a ring of edges instead of a loop) */ - if (params->use_step_face == false) { + if (params->use_step_face == false || e_a->l == NULL) { BMIter viter; BMVert *v; diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp index 7a34c84827e..ee1bb0739b9 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp @@ -570,15 +570,15 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd, zspan.zofsy = 0.0f; /* the buffers */ - rectz = (float *)MEM_mapallocN(sizeof(float) * xsize * ysize, "zbuf accum"); + rectz = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "zbuf accum"); zspan.rectz = (int *)rectz; - rectmove = (char *)MEM_mapallocN(xsize * ysize, "rectmove"); - rectdraw = (DrawBufPixel *)MEM_mapallocN(sizeof(DrawBufPixel) * xsize * ysize, "rect draw"); + rectmove = (char *)MEM_callocN(xsize * ysize, "rectmove"); + rectdraw = (DrawBufPixel *)MEM_callocN(sizeof(DrawBufPixel) * xsize * ysize, "rect draw"); zspan.rectdraw = rectdraw; - rectweight = (float *)MEM_mapallocN(sizeof(float) * xsize * ysize, "rect weight"); - rectmax = (float *)MEM_mapallocN(sizeof(float) * xsize * ysize, "rect max"); + rectweight = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect weight"); + rectmax = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect max"); /* debug... check if PASS_VECTOR_MAX still is in buffers */ dvec1 = vecbufrect; @@ -597,7 +597,7 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd, float minspeed = (float)nbd->minspeed; float minspeedsq = minspeed * minspeed; - minvecbufrect = (float *)MEM_mapallocN(4 * sizeof(float) * xsize * ysize, "minspeed buf"); + minvecbufrect = (float *)MEM_callocN(4 * sizeof(float) * xsize * ysize, "minspeed buf"); dvec1 = vecbufrect; dvec2 = minvecbufrect; @@ -623,7 +623,7 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd, } /* make vertex buffer with averaged speed and zvalues */ - rectvz = (float *)MEM_mapallocN(4 * sizeof(float) * (xsize + 1) * (ysize + 1), "vertices"); + rectvz = (float *)MEM_callocN(4 * sizeof(float) * (xsize + 1) * (ysize + 1), "vertices"); dvz = rectvz; for (y = 0; y <= ysize; y++) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 44ddd9522e0..9230fa19c32 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -83,6 +83,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_layer.h" +#include "BKE_light.h" #include "BKE_mask.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -1402,7 +1403,11 @@ void DepsgraphNodeBuilder::build_armature(bArmature *armature) build_animdata(&armature->id); build_parameters(&armature->id); /* Make sure pose is up-to-date with armature updates. */ - add_operation_node(&armature->id, NodeType::ARMATURE, OperationCode::ARMATURE_EVAL); + bArmature *armature_cow = (bArmature *)get_cow_id(&armature->id); + add_operation_node(&armature->id, + NodeType::ARMATURE, + OperationCode::ARMATURE_EVAL, + function_bind(BKE_armature_refresh_layer_used, _1, armature_cow)); build_armature_bones(&armature->bonebase); } @@ -1437,6 +1442,12 @@ void DepsgraphNodeBuilder::build_light(Light *lamp) build_parameters(&lamp->id); /* light's nodetree */ build_nodetree(lamp->nodetree); + + Light *lamp_cow = get_cow_datablock(lamp); + add_operation_node(&lamp->id, + NodeType::SHADING, + OperationCode::LIGHT_UPDATE, + function_bind(BKE_light_eval, _1, lamp_cow)); } void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) @@ -1570,6 +1581,7 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture) return; } /* Texture itself. */ + add_id_node(&texture->id); build_idproperties(texture->id.properties); build_animdata(&texture->id); build_parameters(&texture->id); @@ -1755,10 +1767,13 @@ void DepsgraphNodeBuilder::build_simulation(Simulation *simulation) build_animdata(&simulation->id); build_parameters(&simulation->id); + Simulation *simulation_cow = get_cow_datablock(simulation); + Scene *scene_cow = get_cow_datablock(scene_); + add_operation_node(&simulation->id, NodeType::SIMULATION, OperationCode::SIMULATION_EVAL, - function_bind(BKE_simulation_data_update, _1, get_cow_datablock(scene_))); + function_bind(BKE_simulation_data_update, _1, scene_cow, simulation_cow)); } void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h index c3c90e5aae4..df8b295f5bb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h @@ -28,7 +28,7 @@ namespace DEG { struct RootPChanMap { - /* ctor and dtor - Create and free the internal map respectively. */ + /* Constructor and destructor - Create and free the internal map respectively. */ RootPChanMap(); ~RootPChanMap(); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index ae90ad8a281..c98aab51654 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2245,14 +2245,20 @@ void DepsgraphRelationBuilder::build_light(Light *lamp) build_idproperties(lamp->id.properties); build_animdata(&lamp->id); build_parameters(&lamp->id); + + ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); + /* light's nodetree */ if (lamp->nodetree != nullptr) { build_nodetree(lamp->nodetree); - ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters"); build_nested_nodetree(&lamp->id, lamp->nodetree); } + + /* For allowing drivers on lamp properties. */ + ComponentKey shading_key(&lamp->id, NodeType::SHADING); + add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters"); } void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) @@ -2422,6 +2428,11 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture) ComponentKey animation_key(&texture->id, NodeType::ANIMATION); add_relation(animation_key, texture_key, "Datablock Animation"); } + + if (BKE_image_user_id_has_animation(&texture->id)) { + ComponentKey image_animation_key(&texture->id, NodeType::IMAGE_ANIMATION); + add_relation(image_animation_key, texture_key, "Datablock Image Animation"); + } } void DepsgraphRelationBuilder::build_image(Image *image) diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 2381076161f..91bd0117f6c 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -172,6 +172,8 @@ const char *operationCodeAsString(OperationCode opcode) return "SHADING"; case OperationCode::MATERIAL_UPDATE: return "MATERIAL_UPDATE"; + case OperationCode::LIGHT_UPDATE: + return "LIGHT_UPDATE"; case OperationCode::WORLD_UPDATE: return "WORLD_UPDATE"; /* Movie clip. */ diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index 865a25d2124..6b14e6af02f 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -170,6 +170,7 @@ enum class OperationCode { /* Shading. ------------------------------------------------------------- */ SHADING, MATERIAL_UPDATE, + LIGHT_UPDATE, WORLD_UPDATE, /* Batch caches. -------------------------------------------------------- */ diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index b90f0fba20a..d9f7a3acae0 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -425,4 +425,6 @@ if(WITH_XR_OPENXR) add_definitions(-DWITH_XR_OPENXR) endif() +add_definitions(${GL_DEFINITIONS}) + blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 9816632c0c3..3350c512b17 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -402,7 +402,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_uniform_vec3(grp, "screen_vecs", DRW_viewport_screenvecs_get(), 2); DRW_shgroup_uniform_float_copy( grp, "sphere_size", scene_eval->eevee.gi_cubemap_draw_size * 0.5f); /* TODO (fclem) get rid of those UBO. */ @@ -427,7 +427,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_vec3(shgrp, "increment_x", egrid->increment_x, 1); DRW_shgroup_uniform_vec3(shgrp, "increment_y", egrid->increment_y, 1); DRW_shgroup_uniform_vec3(shgrp, "increment_z", egrid->increment_z, 1); - DRW_shgroup_uniform_vec3(shgrp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_uniform_vec3(shgrp, "screen_vecs", DRW_viewport_screenvecs_get(), 2); DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex); DRW_shgroup_uniform_float_copy( shgrp, "sphere_size", scene_eval->eevee.gi_irradiance_draw_size * 0.5f); diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 3f4008eb8b9..4f334812a8e 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -145,7 +145,7 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } else { GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); - txl->sss_accum = NULL; + DRW_TEXTURE_FREE_SAFE(txl->sss_accum); } } else { @@ -154,11 +154,11 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb); GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); + DRW_TEXTURE_FREE_SAFE(txl->sss_accum); effects->sss_stencil = NULL; effects->sss_blur = NULL; effects->sss_irradiance = NULL; effects->sss_radius = NULL; - txl->sss_accum = NULL; } } diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index ad90c52b08e..83bd4fcf8d2 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -486,8 +486,7 @@ static bool eevee_volume_object_mesh_init(Scene *scene, ModifierData *md = NULL; /* Smoke Simulation */ - if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && + if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) && ((FluidModifierData *)md)->domain != NULL) { FluidModifierData *mmd = (FluidModifierData *)md; diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 7dddbd07623..6e636e4dc93 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -215,7 +215,7 @@ static void external_draw_scene_do(void *vedata) return; } - RenderEngine *engine = RE_engine_create_ex(engine_type, true); + RenderEngine *engine = RE_engine_create(engine_type); engine->tile_x = scene->r.tilex; engine->tile_y = scene->r.tiley; engine_type->view_update(engine, draw_ctx->evil_C, draw_ctx->depsgraph); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 50e4e8d2ec4..4f586a1e9f3 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -292,7 +292,7 @@ void GPENCIL_cache_init(void *ved) grp = DRW_shgroup_create(sh, psl->merge_depth_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx); DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1); - DRW_shgroup_uniform_vec4(grp, "gpModelMatrix[0]", pd->object_bound_mat[0], 4); + DRW_shgroup_uniform_vec4(grp, "gpModelMatrix", pd->object_bound_mat[0], 4); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index e2606473d07..1e75f6dd5bb 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -317,7 +317,7 @@ vec2 safe_normalize_len(vec2 v, out float len) } } -float stroke_thickness_modulate(float thickness) +float stroke_thickness_modulate(float thickness, out float opacity) { /* Modify stroke thickness by object and layer factors.-*/ thickness *= thicknessScale; @@ -333,6 +333,11 @@ float stroke_thickness_modulate(float thickness) /* World space point size. */ thickness *= thicknessWorldScale * ProjectionMatrix[1][1] * sizeViewport.y; } + /* To avoid aliasing artifact, we clamp the line thickness and reduce its opacity. */ + float min_thickness = gl_Position.w * 1.3; + opacity = smoothstep(0.0, gl_Position.w * 1.0, thickness); + thickness = max(min_thickness, thickness); + return thickness; } @@ -414,8 +419,9 @@ void stroke_vertex() vec2 line = safe_normalize_len(ss2 - ss1, line_len); vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2)); + float small_line_opacity; float thickness = abs((use_curr) ? thickness1 : thickness2); - thickness = stroke_thickness_modulate(thickness); + thickness = stroke_thickness_modulate(thickness, small_line_opacity); finalUvs = vec2(x, y) * 0.5 + 0.5; strokeHardeness = decode_hardness(use_curr ? hardness1 : hardness2); @@ -473,8 +479,8 @@ void stroke_vertex() float miter_dot = dot(miter_tan, line_adj); /* Break corners after a certain angle to avoid really thick corners. */ const float miter_limit = 0.5; /* cos(60°) */ - bool miter_break = (miter_dot < miter_limit) || is_stroke_start || is_stroke_end; - miter_tan = (miter_break) ? line : (miter_tan / miter_dot); + bool miter_break = (miter_dot < miter_limit); + miter_tan = (miter_break || is_stroke_start || is_stroke_end) ? line : (miter_tan / miter_dot); vec2 miter = rotate_90deg(miter_tan); @@ -487,7 +493,7 @@ void stroke_vertex() /* Reminder: we packed the cap flag into the sign of stength and thickness sign. */ if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) || - miter_break) { + (miter_break && !is_stroke_start && !is_stroke_end)) { screen_ofs += line * x; } @@ -505,7 +511,7 @@ void stroke_vertex() vec4 stroke_col = MATERIAL(m).stroke_color; float mix_tex = MATERIAL(m).stroke_texture_mix; - color_output(stroke_col, vert_col, vert_strength, mix_tex); + color_output(stroke_col, vert_col, vert_strength * small_line_opacity, mix_tex); matFlag = MATERIAL(m).flag & ~GP_FILL_FLAGS; # endif diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl index 8c2032f834a..d81c6f4fe0b 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl @@ -99,8 +99,10 @@ void main() discard; } + vec2 fb_size = max(vec2(textureSize(gpSceneDepthTexture, 0).xy), + vec2(textureSize(gpMaskTexture, 0).xy)); + vec2 uvs = gl_FragCoord.xy / fb_size; /* Manual depth test */ - vec2 uvs = gl_FragCoord.xy / vec2(textureSize(gpSceneDepthTexture, 0).xy); float scene_depth = texture(gpSceneDepthTexture, uvs).r; if (gl_FragCoord.z > scene_depth) { discard; diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl index c6cfee5ef2d..225601eb9ba 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl @@ -2,4 +2,4 @@ void main() { gpencil_vertex(); -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 624eef8fa47..a538b7ffd5f 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -137,9 +137,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) && draw_ctx->object_pose != NULL; - - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD; - DRW_PASS_CREATE(psl->armature_transp_ps, state | pd->clipping_state); + DRWState state; if (pd->armature.do_pose_fade_geom) { state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; @@ -163,17 +161,21 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get(); OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i]; - DRWPass **p_armature_ps = &psl->armature_ps[i]; cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__); cb->custom_shapes_transp_ghash = BLI_ghash_ptr_new(__func__); + DRWPass **p_armature_ps = &psl->armature_ps[i]; DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0; state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH; DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state); - DRWPass *armature_ps = *p_armature_ps; + DRWPass **p_armature_trans_ps = &psl->armature_transp_ps[i]; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD; + DRW_PASS_CREATE(*p_armature_trans_ps, state | pd->clipping_state); + DRWPass *armature_transp_ps = *p_armature_trans_ps; + #define BUF_INSTANCE DRW_shgroup_call_buffer_instance #define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES) @@ -231,7 +233,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); - grp = DRW_shgroup_create(sh, psl->armature_transp_ps); + grp = DRW_shgroup_create(sh, armature_transp_ps); DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); } @@ -270,7 +272,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata) format = formats->instance_bone_envelope_distance; sh = OVERLAY_shader_armature_envelope(false); - grp = DRW_shgroup_create(sh, psl->armature_transp_ps); + grp = DRW_shgroup_create(sh, armature_transp_ps); DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); @@ -2255,7 +2257,7 @@ void OVERLAY_armature_draw(OVERLAY_Data *vedata) { OVERLAY_PassList *psl = vedata->psl; - DRW_draw_pass(psl->armature_transp_ps); + DRW_draw_pass(psl->armature_transp_ps[0]); DRW_draw_pass(psl->armature_ps[0]); } @@ -2264,6 +2266,7 @@ void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata) OVERLAY_PassList *psl = vedata->psl; if (psl->armature_bone_select_ps == NULL || DRW_state_is_select()) { + DRW_draw_pass(psl->armature_transp_ps[1]); DRW_draw_pass(psl->armature_ps[1]); } } @@ -2285,6 +2288,7 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata) GPU_framebuffer_clear_depth(fbl->overlay_line_in_front_fb, 1.0f); } + DRW_draw_pass(psl->armature_transp_ps[1]); DRW_draw_pass(psl->armature_ps[1]); } } diff --git a/source/blender/draw/engines/overlay/overlay_background.c b/source/blender/draw/engines/overlay/overlay_background.c index f1ffa9035e0..f52ae691a35 100644 --- a/source/blender/draw/engines/overlay/overlay_background.c +++ b/source/blender/draw/engines/overlay/overlay_background.c @@ -71,15 +71,16 @@ void OVERLAY_background_cache_init(OVERLAY_Data *vedata) } else { switch (UI_GetThemeValue(TH_BACKGROUND_TYPE)) { - case TH_BACKGROUND_SINGLE_COLOR: - background_type = BG_SOLID; - break; case TH_BACKGROUND_GRADIENT_LINEAR: background_type = BG_GRADIENT; break; case TH_BACKGROUND_GRADIENT_RADIAL: background_type = BG_RADIAL; break; + default: + case TH_BACKGROUND_SINGLE_COLOR: + background_type = BG_SOLID; + break; } } diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c index 6456d6868a5..9a79c78c996 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_curve.c +++ b/source/blender/draw/engines/overlay/overlay_edit_curve.c @@ -36,7 +36,8 @@ void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata) GPUShader *sh; DRWState state; - pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0; + pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE; + pd->edit_curve.handle_display = v3d->overlay.handle_display; pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length; /* Run Twice for in-front passes. */ @@ -62,11 +63,13 @@ void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata) pd->edit_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles); + DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); sh = OVERLAY_shader_edit_curve_point(); pd->edit_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps); DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles); + DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); } } diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c index 3de0155d6e0..c4d020adc11 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_text.c +++ b/source/blender/draw/engines/overlay/overlay_edit_text.c @@ -38,7 +38,8 @@ void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata) GPUShader *sh; DRWState state; - pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0; + pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE; + pd->edit_curve.handle_display = v3d->overlay.handle_display; pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length; /* Run Twice for in-front passes. */ diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index e875f2c8291..61337ac8d1d 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -46,6 +46,8 @@ static void OVERLAY_engine_init(void *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); const RegionView3D *rv3d = draw_ctx->rv3d; const View3D *v3d = draw_ctx->v3d; + const Scene *scene = draw_ctx->scene; + const ToolSettings *ts = scene->toolsettings; if (!stl->pd) { /* Alloc transient pointers */ @@ -77,6 +79,15 @@ static void OVERLAY_engine_init(void *vedata) pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES; } + if (ts->sculpt) { + if (ts->sculpt->flags & SCULPT_HIDE_FACE_SETS) { + pd->overlay.sculpt_mode_face_sets_opacity = 0.0f; + } + if (ts->sculpt->flags & SCULPT_HIDE_MASK) { + pd->overlay.sculpt_mode_mask_opacity = 0.0f; + } + } + pd->use_in_front = (v3d->shading.type <= OB_SOLID) || BKE_scene_uses_blender_workbench(draw_ctx->scene); pd->wireframe_mode = (v3d->shading.type == OB_WIRE); @@ -235,7 +246,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) const bool renderable = DRW_object_is_renderable(ob); const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx); const bool in_edit_mode = overlay_object_is_edit_mode(pd, ob); - const bool in_particle_edit_mode = ob->mode == OB_MODE_PARTICLE_EDIT; + const bool in_particle_edit_mode = (ob->mode == OB_MODE_PARTICLE_EDIT) && + (pd->ctx_mode == CTX_MODE_PARTICLE); const bool in_paint_mode = (ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT); const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL) && diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index af54e524445..71efc6b8d03 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -65,6 +65,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) OVERLAY_PassList *psl = vedata->psl; OVERLAY_TextureList *txl = vedata->txl; OVERLAY_PrivateData *pd = vedata->stl->pd; + const bool is_select = DRW_state_is_select(); DRWState state_blend = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->extra_blend_ps, state_blend | pd->clipping_state); @@ -108,7 +109,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) /* Sorted by shader to avoid state changes during render. */ { format = formats->instance_extra; - sh = OVERLAY_shader_extra(); + sh = OVERLAY_shader_extra(is_select); grp = DRW_shgroup_create(sh, extra_ps); DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); @@ -179,7 +180,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) cb->groundline = BUF_INSTANCE(grp, format, DRW_cache_groundline_get()); } { - sh = OVERLAY_shader_extra_wire(false); + sh = OVERLAY_shader_extra_wire(false, is_select); grp = DRW_shgroup_create(sh, extra_ps); DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); @@ -188,7 +189,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) cb->extra_lines = BUF_LINE(grp, formats->wire_extra); } { - sh = OVERLAY_shader_extra_wire(true); + sh = OVERLAY_shader_extra_wire(true, is_select); cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps); DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); @@ -768,10 +769,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z; DRWShadingGroup *grp = DRW_shgroup_create_sub(vedata->stl->pd->extra_grid_grp); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[0]", instdata.mat[0]); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[1]", instdata.mat[1]); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[2]", instdata.mat[2]); - DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[3]", instdata.mat[3]); + DRW_shgroup_uniform_vec4_array_copy(grp, "gridModelMatrix", instdata.mat, 4); DRW_shgroup_call_procedural_points(grp, NULL, cell_count); } break; diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c index c592f11a855..be3510967b6 100644 --- a/source/blender/draw/engines/overlay/overlay_image.c +++ b/source/blender/draw/engines/overlay/overlay_image.c @@ -287,6 +287,9 @@ static void image_camera_background_matrix_get(const Camera *cam, translate[3][0] = bgpic->offset[0]; translate[3][1] = bgpic->offset[1]; translate[3][2] = cam_corners[0][2]; + if (cam->type == CAM_ORTHO) { + mul_v2_fl(translate[3], cam->ortho_scale); + } /* These lines are for keeping 2.80 behavior and could be removed to keep 2.79 behavior. */ translate[3][0] *= min_ff(1.0f, cam_aspect); translate[3][1] /= max_ff(1.0f, cam_aspect) * (image_aspect / cam_aspect); diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 0c29fe9d2e4..ed0a9cf6981 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -54,7 +54,7 @@ typedef struct OVERLAY_PassList { DRWPass *antialiasing_ps; DRWPass *armature_ps[2]; DRWPass *armature_bone_select_ps; - DRWPass *armature_transp_ps; + DRWPass *armature_transp_ps[2]; DRWPass *background_ps; DRWPass *clipping_frustum_ps; DRWPass *edit_curve_wire_ps[2]; @@ -253,8 +253,9 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *particle_shapes_grp; DRWShadingGroup *pointcloud_dots_grp; DRWShadingGroup *sculpt_mask_grp; - DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */ - DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */ + DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */ + DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */ + DRWShadingGroup *wires_hair_grp[2][2]; /* With and without coloring. */ DRWShadingGroup *wires_sculpt_grp[2]; DRWView *view_default; @@ -296,6 +297,7 @@ typedef struct OVERLAY_PrivateData { } antialiasing; struct { bool show_handles; + int handle_display; } edit_curve; struct { int ghost_ob; @@ -588,9 +590,9 @@ GPUShader *OVERLAY_shader_edit_mesh_skin_root(void); GPUShader *OVERLAY_shader_edit_mesh_vert(void); GPUShader *OVERLAY_shader_edit_particle_strand(void); GPUShader *OVERLAY_shader_edit_particle_point(void); -GPUShader *OVERLAY_shader_extra(void); +GPUShader *OVERLAY_shader_extra(bool is_select); GPUShader *OVERLAY_shader_extra_groundline(void); -GPUShader *OVERLAY_shader_extra_wire(bool use_object); +GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select); GPUShader *OVERLAY_shader_extra_loose_point(void); GPUShader *OVERLAY_shader_extra_point(void); GPUShader *OVERLAY_shader_facing(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 59f388df4e3..0610b8397a1 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -164,8 +164,10 @@ typedef struct OVERLAY_Shaders { GPUShader *edit_particle_strand; GPUShader *edit_particle_point; GPUShader *extra; + GPUShader *extra_select; GPUShader *extra_groundline; GPUShader *extra_wire[2]; + GPUShader *extra_wire_select; GPUShader *extra_point; GPUShader *extra_lightprobe_grid; GPUShader *extra_loose_point; @@ -797,23 +799,24 @@ GPUShader *OVERLAY_shader_edit_particle_point(void) return sh_data->edit_particle_point; } -GPUShader *OVERLAY_shader_extra(void) +GPUShader *OVERLAY_shader_extra(bool is_select) { const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->extra) { - sh_data->extra = GPU_shader_create_from_arrays({ + GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra; + if (!*sh) { + *sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, datatoc_extra_vert_glsl, NULL}, .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, + .defs = (const char *[]){sh_cfg->def, (is_select) ? "#define SELECT_EDGES\n" : NULL, NULL}, }); } - return sh_data->extra; + return *sh; } GPUShader *OVERLAY_shader_extra_grid(void) @@ -855,12 +858,13 @@ GPUShader *OVERLAY_shader_extra_groundline(void) return sh_data->extra_groundline; } -GPUShader *OVERLAY_shader_extra_wire(bool use_object) +GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select) { const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->extra_wire[use_object]) { + GPUShader **sh = (is_select) ? &sh_data->extra_wire_select : &sh_data->extra_wire[use_object]; + if (!*sh) { char colorids[1024]; /* NOTE: define all ids we need here. */ BLI_snprintf(colorids, @@ -875,7 +879,7 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object) TH_TRANSFORM, TH_WIRE, TH_CAMERA_PATH); - sh_data->extra_wire[use_object] = GPU_shader_create_from_arrays({ + *sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl, @@ -884,11 +888,12 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object) .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_wire_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg->def, colorids, + (is_select) ? "#define SELECT_EDGES\n" : "", (use_object) ? "#define OBJECT_WIRE \n" : NULL, NULL}, }); } - return sh_data->extra_wire[use_object]; + return *sh; } GPUShader *OVERLAY_shader_extra_loose_point(void) diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index 99ff7f67d49..cb36f0ed326 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -21,15 +21,18 @@ */ #include "DNA_mesh_types.h" +#include "DNA_particle_types.h" #include "DNA_view3d_types.h" #include "DNA_volume_types.h" #include "BKE_curve.h" #include "BKE_displist.h" +#include "BKE_duplilist.h" #include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_object.h" #include "BKE_paint.h" +#include "BKE_particle.h" #include "BLI_hash.h" @@ -95,16 +98,24 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color); DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color); + DRW_shgroup_uniform_bool_copy(grp, "isHair", false); pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f); + + pd->wires_hair_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); + /* TODO(fclem) texture ref persist */ + DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); + DRW_shgroup_uniform_bool_copy(grp, "isHair", true); + DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); } pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass); DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); DRW_shgroup_uniform_bool_copy(grp, "useColoring", false); + DRW_shgroup_uniform_bool_copy(grp, "isHair", false); } if (is_material_shmode) { @@ -112,19 +123,50 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) for (int use_coloring = 0; use_coloring < 2; use_coloring++) { pd->wires_grp[1][use_coloring] = pd->wires_grp[0][use_coloring]; pd->wires_all_grp[1][use_coloring] = pd->wires_all_grp[0][use_coloring]; + pd->wires_hair_grp[1][use_coloring] = pd->wires_hair_grp[0][use_coloring]; } pd->wires_sculpt_grp[1] = pd->wires_sculpt_grp[0]; psl->wireframe_xray_ps = NULL; } } +static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, ParticleSystem *psys) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0; + + Object *dupli_parent = DRW_object_get_dupli_parent(ob); + DupliObject *dupli_object = DRW_object_get_dupli(ob); + + float dupli_mat[4][4]; + if ((dupli_parent != NULL) && (dupli_object != NULL)) { + if (dupli_object->type & OB_DUPLICOLLECTION) { + copy_m4_m4(dupli_mat, dupli_parent->obmat); + } + else { + copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + invert_m4(dupli_mat); + mul_m4_m4m4(dupli_mat, ob->obmat, dupli_mat); + } + } + else { + unit_m4(dupli_mat); + } + + struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL); + + const bool use_coloring = true; + DRWShadingGroup *shgrp = DRW_shgroup_create_sub(pd->wires_hair_grp[is_xray][use_coloring]); + DRW_shgroup_uniform_vec4_array_copy(shgrp, "hairDupliMatrix", dupli_mat, 4); + DRW_shgroup_call_no_cull(shgrp, hairs, ob); +} + void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, Object *ob, OVERLAY_DupliData *dupli, bool init_dupli) { - OVERLAY_Data *data = vedata; - OVERLAY_PrivateData *pd = data->stl->pd; + OVERLAY_PrivateData *pd = vedata->stl->pd; const DRWContextState *draw_ctx = DRW_context_state_get(); const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES) != 0; const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0; @@ -134,6 +176,19 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, const bool use_wire = !is_mesh_verts_only && ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)); + if (use_wire && pd->wireframe_mode && ob->particlesystem.first) { + for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) { + if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { + continue; + } + ParticleSettings *part = psys->part; + const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + if (draw_as == PART_DRAW_PATH) { + wireframe_hair_cache_populate(vedata, ob, psys); + } + } + } + if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); float *color; diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl index b444b3b0fec..306fbb473ee 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl @@ -4,10 +4,15 @@ #define EVEN_U_BIT 1 << 4 #define COLOR_SHIFT 5 +/* Keep the same value in `handle_display` in `DNA_view3d_types.h` */ +#define CURVE_HANDLE_SELECTED 0 +#define CURVE_HANDLE_ALL 1 + layout(lines) in; layout(triangle_strip, max_vertices = 10) out; uniform bool showCurveHandles; +uniform int curveHandleDisplay; flat in int vertFlag[]; @@ -46,6 +51,17 @@ void main() } bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERT_SELECTED) != 0); + bool handle_selected = (showCurveHandles && + (((vertFlag[1] | vertFlag[0]) & HANDLE_SELECTED) != 0)); + + /* If handle type is only selected and the edge is not selected, don't show. */ + if ((curveHandleDisplay != CURVE_HANDLE_ALL) && (!handle_selected)) { + /* Nurbs must show the handles always. */ + bool is_u_segment = (((vertFlag[1] ^ vertFlag[0]) & EVEN_U_BIT) != 0); + if (!is_u_segment) { + return; + } + } vec4 inner_color; if (color_id == 0) { diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl index 6fa4576ae71..b1e1c0879a5 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl @@ -2,7 +2,11 @@ /* Keep the same value of `BEZIER_HANDLE` in `draw_cache_imp_curve.c` */ #define BEZIER_HANDLE 1 << 3 +/* Keep the same value in `handle_display` in `DNA_view3d_types.h` */ +#define CURVE_HANDLE_SELECTED 0 + uniform bool showCurveHandles; +uniform int curveHandleDisplay; in vec3 pos; in int data; @@ -32,7 +36,12 @@ void main() world_clip_planes_calc_clip_distance(world_pos); #endif - if (!showCurveHandles && ((data & BEZIER_HANDLE) != 0)) { + bool show_handle = showCurveHandles; + if ((curveHandleDisplay == CURVE_HANDLE_SELECTED) && ((data & HANDLE_SELECTED) == 0)) { + show_handle = false; + } + + if (!show_handle && ((data & BEZIER_HANDLE) != 0)) { /* We set the vertex at the camera origin to generate 0 fragments. */ gl_Position = vec4(0.0, 0.0, -3e36, 0.0); } diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl index 035fab1040e..2168d8065fc 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl @@ -221,6 +221,13 @@ void main() /* Convert to screen position [0..sizeVp]. */ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +#ifdef SELECT_EDGES + /* HACK: to avoid loosing sub pixel object in selections, we add a bit of randomness to the + * wire to at least create one fragment that will pass the occlusion query. */ + /* TODO(fclem) Limit this workaround to selection. It's not very noticeable but still... */ + gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0); +#endif + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl index 474f3254389..0fbf9ba8137 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl @@ -17,6 +17,13 @@ void main() vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); +#ifdef SELECT_EDGES + /* HACK: to avoid loosing sub pixel object in selections, we add a bit of randomness to the + * wire to at least create one fragment that will pass the occlusion query. */ + /* TODO(fclem) Limit this workaround to selection. It's not very noticeable but still... */ + gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0); +#endif + stipple_coord = stipple_start = screen_position(gl_Position); #ifdef OBJECT_WIRE @@ -34,6 +41,10 @@ void main() } #endif +#ifdef SELECT_EDGES + finalColor.a = 0.0; /* No Stipple */ +#endif + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 7e71f4ae587..f7467aa3bf4 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -4,6 +4,8 @@ uniform bool useColoring; uniform bool isTransform; uniform bool isObjectColor; uniform bool isRandomColor; +uniform bool isHair; +uniform vec4 hairDupliMatrix[4]; in vec3 pos; in vec3 nor; @@ -103,9 +105,16 @@ void main() { bool no_attr = all(equal(nor, vec3(0))); vec3 wnor = no_attr ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor)); - vec3 wpos = point_object_to_world(pos); + if (isHair) { + mat4 obmat = mat4( + hairDupliMatrix[0], hairDupliMatrix[1], hairDupliMatrix[2], hairDupliMatrix[3]); + + wpos = (obmat * vec4(pos, 1.0)).xyz; + wnor = -normalize(mat3(obmat) * nor); + } + bool is_persp = (ProjectionMatrix[3][3] == 0.0); vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz; diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c index 08ec0038755..bb7c947a0b9 100644 --- a/source/blender/draw/engines/select/select_engine.c +++ b/source/blender/draw/engines/select/select_engine.c @@ -307,9 +307,6 @@ static void select_draw_scene(void *vedata) return; } - /* dithering and AA break color coding, so disable */ - glDisable(GL_DITHER); - DRW_view_set_active(stl->g_data->view_faces); if (!DRW_pass_is_empty(psl->depth_only_pass)) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl index e6bc4c7bbc6..a4d81393dbc 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl @@ -26,6 +26,10 @@ void curvature_compute(vec2 uv, if ((object_up != object_down) || (object_right != object_left)) { return; } + /* Avoid shading background pixels. */ + if ((object_up == object_right) && (object_right == 0u)) { + return; + } float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g; float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl index 6f99739f259..e45f7a7b9e3 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -24,11 +24,17 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling) { - vec2 tex_size = vec2(textureSize(image, 0).xy); /* TODO(fclem) We could do the same with sampler objects. * But this is a quick workaround instead of messing with the GPUTexture itself. */ - vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; - return texture(image, uv); + if (nearest_sampling) { + /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */ + vec2 tex_size = vec2(textureSize(image, 0).xy); + ivec2 uv = ivec2(floor(coord * tex_size) + 0.5); + return texelFetch(image, uv, 0); + } + else { + return texture(image, coord); + } } vec4 workbench_sample_texture_array(sampler2DArray tile_array, @@ -36,7 +42,6 @@ vec4 workbench_sample_texture_array(sampler2DArray tile_array, vec2 coord, bool nearest_sampling) { - vec2 tex_size = vec2(textureSize(tile_array, 0).xy); vec3 uv = vec3(coord, 0); if (!node_tex_tile_lookup(uv, tile_array, tile_data)) @@ -44,8 +49,15 @@ vec4 workbench_sample_texture_array(sampler2DArray tile_array, /* TODO(fclem) We could do the same with sampler objects. * But this is a quick workaround instead of messing with the GPUTexture itself. */ - uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; - return texture(tile_array, uv); + if (nearest_sampling) { + /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */ + vec3 tex_size = vec3(textureSize(tile_array, 0)); + uv.xy = floor(uv.xy * tex_size.xy) + 0.5; + return texelFetch(tile_array, ivec3(uv), 0); + } + else { + return texture(tile_array, uv); + } } uniform sampler2DArray imageTileArray; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl index 58becb03290..b77e168889f 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl @@ -15,4 +15,4 @@ void main() /* Make this fragment occlude any fragment that will try to * render over it in the normal passes. */ gl_FragDepth = 0.0; -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index 81f6e651be0..41ef516ee4d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -128,4 +128,4 @@ float get_shadow(vec3 N) float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor); shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul; return shadow_mix + world_data.shadow_add; -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c index d2bd653a656..cb8eb7d1e92 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c @@ -19,7 +19,7 @@ /** \file * \ingroup draw_engine * - * Anti-aliasing: + * Anti-Aliasing: * * We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution. * diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 024b71c5db9..d3585b02b7d 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -532,6 +532,10 @@ void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value); void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value); void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value); +void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, + const char *name, + const float (*value)[4], + int arraysize); bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index 401f5c76a02..cbb5f5f06ff 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -105,6 +105,14 @@ typedef struct MeshRenderData { BMEditMesh *edit_bmesh; BMesh *bm; EditMeshData *edit_data; + + /* For deformed edit-mesh data. */ + /* Use for #ME_WRAPPER_TYPE_BMESH. */ + const float (*bm_vert_coords)[3]; + const float (*bm_vert_normals)[3]; + const float (*bm_poly_normals)[3]; + const float (*bm_poly_centers)[3]; + int *v_origindex, *e_origindex, *p_origindex; int crease_ofs; int bweight_ofs; @@ -151,9 +159,24 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final); mr->bm = me->edit_mesh->bm; mr->edit_bmesh = me->edit_mesh; - mr->edit_data = me->runtime.edit_data; mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage; - bool use_mapped = !do_uvedit && mr->me && !mr->me->runtime.is_original; + mr->edit_data = mr->me->runtime.edit_data; + + if (mr->edit_data) { + EditMeshData *emd = mr->edit_data; + if (emd->vertexCos) { + BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd); + BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd); + } + + mr->bm_vert_coords = mr->edit_data->vertexCos; + mr->bm_vert_normals = mr->edit_data->vertexNos; + mr->bm_poly_normals = mr->edit_data->polyNos; + mr->bm_poly_centers = mr->edit_data->polyCos; + } + + bool has_mdata = (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA); + bool use_mapped = has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original; int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE; @@ -184,7 +207,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, /* Seems like the mesh_eval_final do not have the right origin indices. * Force not mapped in this case. */ - if (do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) { + if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) { // mr->edit_bmesh = NULL; mr->extract_type = MR_EXTRACT_MESH; } @@ -311,12 +334,23 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, /* Use bmface->no instead. */ } if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { + + const float(*vert_coords)[3] = NULL; + const float(*vert_normals)[3] = NULL; + const float(*poly_normals)[3] = NULL; + + if (mr->edit_data && mr->edit_data->vertexCos) { + vert_coords = mr->bm_vert_coords; + vert_normals = mr->bm_vert_normals; + poly_normals = mr->bm_poly_normals; + } + mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__); int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(mr->bm, - NULL, - NULL, - NULL, + vert_coords, + vert_normals, + poly_normals, is_auto_smooth, split_angle, mr->loop_normals, @@ -396,6 +430,42 @@ BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx) NULL; } +BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_coords)[3] = mr->bm_vert_coords; + if (vert_coords != NULL) { + return vert_coords[BM_elem_index_get(eve)]; + } + else { + UNUSED_VARS(mr); + return eve->co; + } +} + +BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve) +{ + const float(*vert_normals)[3] = mr->bm_vert_normals; + if (vert_normals != NULL) { + return vert_normals[BM_elem_index_get(eve)]; + } + else { + UNUSED_VARS(mr); + return eve->co; + } +} + +BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa) +{ + const float(*poly_normals)[3] = mr->bm_poly_normals; + if (poly_normals != NULL) { + return poly_normals[BM_elem_index_get(efa)]; + } + else { + UNUSED_VARS(mr); + return efa->no; + } +} + /** \} */ /* ---------------------------------------------------------------------- */ @@ -1480,7 +1550,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) BMVert *eve; int v; BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) { - data->packed_nor[v] = GPU_normal_convert_i10_v3(eve->no); + data->packed_nor[v] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve)); } } else { @@ -1492,14 +1562,11 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_pos_nor_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *_data) +static void extract_pos_nor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) { MeshExtract_PosNor_Data *data = _data; PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, loop->v->co); + copy_v3_v3(vert->pos, bm_vert_co_get(mr, loop->v)); vert->nor = data->packed_nor[BM_elem_index_get(loop->v)]; BMFace *efa = loop->f; vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; @@ -1536,8 +1603,8 @@ static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge int l = mr->loop_len + e * 2; MeshExtract_PosNor_Data *data = _data; PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert[0].pos, eed->v1->co); - copy_v3_v3(vert[1].pos, eed->v2->co); + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)]; vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)]; } @@ -1561,7 +1628,7 @@ static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert int l = mr->loop_len + mr->edge_loose_len * 2 + v; MeshExtract_PosNor_Data *data = _data; PosNorLoop *vert = data->vbo_data + l; - copy_v3_v3(vert->pos, eve->co); + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); vert->nor = data->packed_nor[BM_elem_index_get(eve)]; } @@ -1627,10 +1694,10 @@ static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop * normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]); } else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->v->no); + normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_vert_no_get(mr, loop->v)); } else { - normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->f->no); + normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_face_no_get(mr, loop->f)); } } @@ -1704,10 +1771,10 @@ static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loo ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]); } else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->v->no); + ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v)); } else { - ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->f->no); + ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, loop->f)); } BMFace *efa = loop->f; ((GPUPackedNormal *)data)[l].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; @@ -1915,7 +1982,10 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool if (mr->extract_type == MR_EXTRACT_BMESH) { BMesh *bm = mr->bm; for (int v = 0; v < mr->vert_len; v++) { - copy_v3_v3(orco[v], BM_vert_at_index(bm, v)->co); + const BMVert *eve = BM_vert_at_index(bm, v); + /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords. + * not the distorted ones. */ + copy_v3_v3(orco[v], eve->co); } } else { @@ -2301,14 +2371,14 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_edge_fac_loop_bmesh(const MeshRenderData *UNUSED(mr), - int l, - BMLoop *loop, - void *_data) +static void extract_edge_fac_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) { MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; if (BM_edge_is_manifold(loop->e)) { - float ratio = loop_edge_factor_get(loop->f->no, loop->v->co, loop->v->no, loop->next->v->co); + float ratio = loop_edge_factor_get(bm_face_no_get(mr, loop->f), + bm_vert_co_get(mr, loop->v), + bm_vert_no_get(mr, loop->v), + bm_vert_co_get(mr, loop->next->v)); data->vbo_data[l] = ratio * 253 + 1; } else { @@ -3133,7 +3203,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf) return data; } -static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr), +static void extract_stretch_angle_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data) @@ -3150,8 +3220,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr), BMLoop *l_next_tmp = loop; luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); - compute_normalize_edge_vectors( - auv, av, luv->uv, luv_next->uv, l_tmp->v->co, l_next_tmp->v->co); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, l_tmp->v), + bm_vert_co_get(mr, l_next_tmp->v)); /* Save last edge. */ copy_v2_v2(last_auv, auv[1]); copy_v3_v3(last_av, av[1]); @@ -3167,7 +3241,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr), else { luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs); luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); - compute_normalize_edge_vectors(auv, av, luv->uv, luv_next->uv, loop->v->co, l_next->v->co); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, loop->v), + bm_vert_co_get(mr, l_next->v)); } edituv_get_stretch_angle(auv, av, data->vbo_data + l); } @@ -3307,7 +3386,7 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang) if (mr->extract_type == MR_EXTRACT_BMESH) { int l = 0; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - float fac = angle_normalized_v3v3(f->no, dir) / (float)M_PI; + float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI; fac = overhang_remap(fac, min, max, minmax_irange); for (int i = 0; i < f->len; i++, l++) { r_overhang[l] = fac; @@ -3385,7 +3464,11 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) for (int i = 0; i < mr->tri_len; i++) { BMLoop **ltri = looptris[i]; const int index = BM_elem_index_get(ltri[0]->f); - const float *cos[3] = {ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co}; + const float *cos[3] = { + bm_vert_co_get(mr, ltri[0]->v), + bm_vert_co_get(mr, ltri[1]->v), + bm_vert_co_get(mr, ltri[2]->v), + }; float ray_co[3]; float ray_no[3]; @@ -3398,7 +3481,8 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL); if (f_hit && dist < face_dists[index]) { - float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); + float angle_fac = fabsf( + dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit))); angle_fac = 1.0f - angle_fac; angle_fac = angle_fac * angle_fac * angle_fac; angle_fac = 1.0f - angle_fac; @@ -3603,8 +3687,17 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) BMesh *bm = em->bm; BMFace *f; + if (mr->bm_vert_coords != NULL) { + BKE_editmesh_cache_ensure_poly_normals(em, mr->edit_data); + + /* Most likely this is already valid, ensure just in case. + * Needed for #BM_loop_calc_face_normal_safe_vcos. */ + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + } + int l = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + int p = 0; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, p) { float fac = -1.0f; if (f->len > 3) { @@ -3613,13 +3706,23 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) fac = 0.0f; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { + const float *no_face; float no_corner[3]; - BM_loop_calc_face_normal_safe(l_iter, no_corner); + if (mr->bm_vert_coords != NULL) { + no_face = mr->bm_poly_normals[p]; + BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner); + } + else { + no_face = f->no; + BM_loop_calc_face_normal_safe(l_iter, no_corner); + } + /* simple way to detect (what is most likely) concave */ - if (dot_v3v3(f->no, no_corner) < 0.0f) { + if (dot_v3v3(no_face, no_corner) < 0.0f) { negate_v3(no_corner); } - fac = max_ff(fac, angle_normalized_v3v3(f->no, no_corner)); + fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner)); + } while ((l_iter = l_iter->next) != l_first); fac *= 2.0f; } @@ -3842,14 +3945,14 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf) return vbo->data; } -static void extract_fdots_pos_loop_bmesh(const MeshRenderData *UNUSED(mr), +static void extract_fdots_pos_loop_bmesh(const MeshRenderData *mr, int UNUSED(l), BMLoop *loop, void *data) { float(*center)[3] = (float(*)[3])data; float w = 1.0f / (float)loop->f->len; - madd_v3_v3fl(center[BM_elem_index_get(loop->f)], loop->v->co, w); + madd_v3_v3fl(center[BM_elem_index_get(loop->f)], bm_vert_co_get(mr, loop->v), w); } static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr, @@ -3928,7 +4031,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void * nor[f].w = NOR_AND_FLAG_HIDDEN; } else { - nor[f] = GPU_normal_convert_i10_v3(efa->no); + nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); /* Select / Active Flag. */ nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : @@ -3946,7 +4049,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void * nor[f].w = NOR_AND_FLAG_HIDDEN; } else { - nor[f] = GPU_normal_convert_i10_v3(efa->no); + nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); /* Select / Active Flag. */ nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : @@ -4171,7 +4274,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf) const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs); if (vs->flag & MVERT_SKIN_ROOT) { vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f; - copy_v3_v3(vbo_data->local_pos, eve->co); + copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve)); vbo_data++; root_len++; } diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index de0cd027ece..daa46252331 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -208,6 +208,7 @@ enum { VFLAG_EDGE_SEAM = 1 << 4, VFLAG_EDGE_SHARP = 1 << 5, VFLAG_EDGE_FREESTYLE = 1 << 6, + VFLAG_HANDLE_SELECTED = 1 << 7, /* Beware to not go over 1 << 7 (it's a byte flag) * (see gpu_shader_edit_mesh_overlay_geom.glsl) */ }; diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 72ee7fe17c1..c6112994b65 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -685,14 +685,20 @@ static void curve_create_edit_curves_nor(CurveRenderData *rdata, GPUVertBuf *vbo BLI_assert(vbo_len_used == verts_len_capacity); } -static char beztriple_vflag_get( - CurveRenderData *rdata, char flag, char col_id, int v_idx, int nu_id, bool handle_point) +static char beztriple_vflag_get(CurveRenderData *rdata, + char flag, + char col_id, + int v_idx, + int nu_id, + bool handle_point, + const bool handle_selected) { char vflag = 0; SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED); SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE); SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB); SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE); + SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_HANDLE_SELECTED); /* handle color id */ vflag |= col_id << COLOR_SHIFT; return vflag; @@ -754,11 +760,13 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) { const BezTriple *bezt = nu->bezt; const BPoint *bp = nu->bp; + if (bezt) { for (int a = 0; a < nu->pntsu; a++, bezt++) { if (bezt->hide == true) { continue; } + const bool handle_selected = BEZT_ISSEL_ANY(bezt); if (elbp_verts) { GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 0); @@ -771,9 +779,9 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata, } if (vbo_data) { const char vflag[3] = { - beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id, true), - beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id, false), - beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id, true), + beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id, true, handle_selected), + beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id, false, handle_selected), + beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id, true, handle_selected), }; for (int j = 0; j < 3; j++) { GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used + j, &vflag[j]); @@ -1034,7 +1042,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob) } if (DRW_vbo_requested(cache->ordered.loop_pos_nor) || - DRW_vbo_requested(cache->ordered.loop_uv)) { + DRW_vbo_requested(cache->ordered.loop_uv) || DRW_vbo_requested(cache->ordered.loop_tan)) { DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan( lb, cache->ordered.loop_pos_nor, cache->ordered.loop_uv, cache->ordered.loop_tan); } diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index 62ce34fe556..ee148e0934d 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -291,7 +291,7 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts, vert->u_stroke = pt->uv_fac; vert->stroke_id = gps->runtime.stroke_start; vert->point_id = v; - vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0 : -1.0); + vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f); /* Tag endpoint material to -1 so they get discarded by vertex shader. */ vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GP_MATERIAL_BUFFER_LEN); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 649bcd7bbaa..237c7bddfad 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -96,11 +96,25 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c cd_used->edit_uv = 1; } +BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) +{ + switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_MDATA: + return &me->ldata; + break; + case ME_WRAPPER_TYPE_BMESH: + return &me->edit_mesh->bm->ldata; + break; + } + + BLI_assert(0); + return &me->ldata; +} + static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; - + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { cd_used->uv |= (1 << layer); @@ -110,8 +124,7 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; - + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { cd_used->uv |= (1 << layer); @@ -121,8 +134,7 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; - + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); if (layer != -1) { cd_used->vcol |= (1 << layer); @@ -134,7 +146,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, int gpumat_array_len) { const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; - const CustomData *cd_ldata = &me_final->ldata; + const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final); /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -302,7 +314,7 @@ static void drw_mesh_weight_state_extract(Object *ob, wstate->alert_mode = ts->weightuser; if (paint_mode && ts->multipaint) { - /* Multipaint needs to know all selected bones, not just the active group. + /* Multi-paint needs to know all selected bones, not just the active group. * This is actually a relatively expensive operation, but caching would be difficult. */ wstate->defgroup_sel = BKE_object_defgroup_selected_get( ob, wstate->defgroup_len, &wstate->defgroup_sel_count); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index ed7c72ac116..27de7cc1c7c 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -240,10 +240,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[0]", dupli_mat[0]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[1]", dupli_mat[1]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[2]", dupli_mat[2]); - DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[3]", dupli_mat[3]); + DRW_shgroup_uniform_vec4_array_copy(shgrp, "hairDupliMatrix", dupli_mat, 4); DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index a387c60ca73..bdef6d50db8 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -63,11 +63,11 @@ #include "ED_space_api.h" #include "ED_view3d.h" -#include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_matrix.h" +#include "GPU_state.h" #include "GPU_uniformbuffer.h" #include "GPU_viewport.h" diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 95b204ac004..aa401bcffa5 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -436,6 +436,24 @@ void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, c drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1); } +void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup, + const char *name, + const float (*value)[4], + int arraysize) +{ + int location = GPU_shader_get_uniform_ensure(shgroup->shader, name); + + if (location == -1) { + /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + // BLI_assert(0); + return; + } + + for (int i = 0; i < arraysize; i++) { + drw_shgroup_uniform_create_ex(shgroup, location + i, DRW_UNIFORM_FLOAT_COPY, &value[i], 4, 1); + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -2000,7 +2018,10 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass) } } /* To be sorted a shgroup needs to have at least one draw command. */ - BLI_assert(handle != 0); + /* FIXME(fclem) In some case, we can still have empty shading group to sort. However their + * final order is not well defined. + * (see T76730 & D7729). */ + // BLI_assert(handle != 0); DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle); diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 7eac082a9e1..0d6527421d0 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -241,6 +241,9 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) WM_jobs_timer(wm_job, 0.1, NC_MATERIAL | ND_SHADING_DRAW, 0); WM_jobs_delay_start(wm_job, 0.1); WM_jobs_callbacks(wm_job, drw_deferred_shader_compilation_exec, NULL, NULL, NULL); + + G.is_break = false; + WM_jobs_start(wm, wm_job); } diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl index 9dfd48cc21a..a479a87e14b 100644 --- a/source/blender/draw/intern/shaders/common_globals_lib.glsl +++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl @@ -140,3 +140,4 @@ layout(std140) uniform globalsBlock #define EDGE_SEAM (1 << 4) #define EDGE_SHARP (1 << 5) #define EDGE_FREESTYLE (1 << 6) +#define HANDLE_SELECTED (1 << 7) diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 5f3b876efaf..d3d00fc44f2 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -432,7 +432,6 @@ int join_armature_exec(bContext *C, wmOperator *op) ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); - BKE_armature_refresh_layer_used(arm); DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -689,9 +688,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) /* 5) restore original conditions */ ED_armature_to_edit(ob_old->data); - ED_armature_edit_refresh_layer_used(ob_old->data); - BKE_armature_refresh_layer_used(ob_new->data); /* parents tips remain selected when connected children are removed. */ ED_armature_edit_deselect_all(ob_old); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index daab945c106..0cd3afc9cf9 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -906,8 +906,6 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op) RNA_boolean_set_array(&ptr, "layers", layers); if (prev_ob != ob) { - BKE_armature_refresh_layer_used(ob->data); - /* Note, notifier might evolve. */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE); diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 481282d6df3..d9621dba730 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -1239,51 +1239,60 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso return OPERATOR_FINISHED; } -/* common code for defining RNA properties */ -/* TODO: Skip save on these? */ +/** + * Common code for defining RNA properties. + */ static void pose_slide_opdef_properties(wmOperatorType *ot) { - RNA_def_float_percentage(ot->srna, - "percentage", - 0.5f, - 0.0f, - 1.0f, - "Percentage", - "Weighting factor for which keyframe is favored more", - 0.0, - 1.0); - - RNA_def_int(ot->srna, - "prev_frame", - 0, - MINAFRAME, - MAXFRAME, - "Previous Keyframe", - "Frame number of keyframe immediately before the current frame", - 0, - 50); - RNA_def_int(ot->srna, - "next_frame", - 0, - MINAFRAME, - MAXFRAME, - "Next Keyframe", - "Frame number of keyframe immediately after the current frame", - 0, - 50); - - RNA_def_enum(ot->srna, - "channels", - prop_channels_types, - PS_TFM_ALL, - "Channels", - "Set of properties that are affected"); - RNA_def_enum(ot->srna, - "axis_lock", - prop_axis_lock_types, - 0, - "Axis Lock", - "Transform axis to restrict effects to"); + PropertyRNA *prop; + + prop = RNA_def_float_percentage(ot->srna, + "percentage", + 0.5f, + 0.0f, + 1.0f, + "Percentage", + "Weighting factor for which keyframe is favored more", + 0.0, + 1.0); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_int(ot->srna, + "prev_frame", + 0, + MINAFRAME, + MAXFRAME, + "Previous Keyframe", + "Frame number of keyframe immediately before the current frame", + 0, + 50); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_int(ot->srna, + "next_frame", + 0, + MINAFRAME, + MAXFRAME, + "Next Keyframe", + "Frame number of keyframe immediately after the current frame", + 0, + 50); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_enum(ot->srna, + "channels", + prop_channels_types, + PS_TFM_ALL, + "Channels", + "Set of properties that are affected"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, + "axis_lock", + prop_axis_lock_types, + 0, + "Axis Lock", + "Transform axis to restrict effects to"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ------------------------------------ */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index d6256f67066..4d783396888 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4923,7 +4923,7 @@ bool ED_curve_editnurb_select_pick( } } else { - BKE_nurbList_flag_set(editnurb, 0); + BKE_nurbList_flag_set(editnurb, SELECT, false); if (bezt) { @@ -5635,7 +5635,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) const float mval[2] = {UNPACK2(event->mval)}; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - vc.bmain, vc.scene, 0, vc.region, vc.v3d); + vc.scene, 0, vc.region, vc.v3d); ED_transform_snap_object_project_view3d( snap_context, diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index 91d5ea58361..bacdd5b69b5 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -138,7 +138,7 @@ Nurb *ED_curve_add_nurbs_primitive( copy_v3_v3(zvec, rv3d->viewinv[2]); } - BKE_nurbList_flag_set(editnurb, 0); + BKE_nurbList_flag_set(editnurb, SELECT, false); /* these types call this function to return a Nurb */ if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) { @@ -521,7 +521,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/curve/editcurve_query.c b/source/blender/editors/curve/editcurve_query.c index 0b15d9e55b9..132f7e58e71 100644 --- a/source/blender/editors/curve/editcurve_query.c +++ b/source/blender/editors/curve/editcurve_query.c @@ -44,8 +44,13 @@ /** \name Cursor Picking API * \{ */ -static void ED_curve_pick_vert__do_closest( - void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) +static void ED_curve_pick_vert__do_closest(void *userData, + Nurb *nu, + BPoint *bp, + BezTriple *bezt, + int beztindex, + bool handles_visible, + const float screen_co[2]) { struct { BPoint *bp; @@ -64,6 +69,8 @@ static void ED_curve_pick_vert__do_closest( flag = bp->f1; } else { + BLI_assert(handles_visible || beztindex == 1); + if (beztindex == 0) { flag = bezt->f1; } @@ -92,6 +99,8 @@ static void ED_curve_pick_vert__do_closest( data->hpoint = bezt ? beztindex : 0; data->is_changed = true; } + + UNUSED_VARS_NDEBUG(handles_visible); } bool ED_curve_pick_vert(ViewContext *vc, diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index 9cf61d02677..9294bc6e91b 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -590,8 +590,8 @@ static int de_select_all_exec(bContext *C, wmOperator *op) changed = ED_curve_deselect_all(cu->editnurb); break; case SEL_INVERT: - changed = ED_curve_select_swap( - cu->editnurb, (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0); + changed = ED_curve_select_swap(cu->editnurb, + v3d->overlay.handle_display == CURVE_HANDLE_NONE); break; } @@ -772,7 +772,7 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op)) if (last == bp) { direction = 1 - direction; - BKE_nurbList_flag_set(editnurb, 0); + BKE_nurbList_flag_set(editnurb, SELECT, false); } last = bp; @@ -826,8 +826,10 @@ static int select_next_exec(bContext *C, wmOperator *UNUSED(op)) for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); select_adjacent_cp(editnurb, 1, 0, SELECT); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -861,8 +863,10 @@ static int select_previous_exec(bContext *C, wmOperator *UNUSED(op)) for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); select_adjacent_cp(editnurb, -1, 0, SELECT); + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -1392,6 +1396,7 @@ static int select_nth_exec(bContext *C, wmOperator *op) if (ed_curve_select_nth(obedit->data, &op_params) == true) { changed = true; + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt index 68a204c04a7..1f3edf31b19 100644 --- a/source/blender/editors/gizmo_library/CMakeLists.txt +++ b/source/blender/editors/gizmo_library/CMakeLists.txt @@ -53,6 +53,7 @@ set(SRC gizmo_types/dial3d_gizmo.c gizmo_types/move3d_gizmo.c gizmo_types/primitive3d_gizmo.c + gizmo_types/snap3d_gizmo.c ) set(LIB diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c index 374b7b1f6a2..db57a33f543 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c @@ -382,7 +382,7 @@ static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) switch (area->spacetype) { case SPACE_VIEW3D: { inter->snap_context_v3d = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); + CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); break; } default: diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c new file mode 100644 index 00000000000..1fdf1160d09 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -0,0 +1,564 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file snap3d_gizmo.c + * \ingroup edgizmolib + * + * \name Snap Gizmo + * + * 3D Gizmo + * + * \brief Snap gizmo which exposes the location, normal and index in the props. + */ + +#include "BLI_math.h" + +#include "DNA_scene_types.h" + +#include "BKE_context.h" + +#include "GPU_immediate.h" +#include "GPU_state.h" + +#include "ED_gizmo_library.h" +#include "ED_screen.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "UI_resources.h" /* icons */ + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "DEG_depsgraph_query.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm.h" + +/* own includes */ +#include "../gizmo_geometry.h" +#include "../gizmo_library_intern.h" + +typedef struct SnapGizmo3D { + wmGizmo gizmo; + PropertyRNA *prop_prevpoint; + PropertyRNA *prop_location; + PropertyRNA *prop_normal; + PropertyRNA *prop_elem_index; + PropertyRNA *prop_snap_force; + + /* We could have other snap contexts, for now only support 3D view. */ + SnapObjectContext *snap_context_v3d; + int mval[2]; + short snap_elem; + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + wmKeyMap *keymap; + int snap_on; + bool invert_snap; +#endif + int use_snap_override; +} SnapGizmo3D; + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK +static bool invert_snap(const wmGizmo *gz, const wmWindowManager *wm, const wmEvent *event) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + wmKeyMap *keymap = WM_keymap_active(wm, gizmo_snap->keymap); + if (!keymap) { + return false; + } + + int snap_on = gizmo_snap->snap_on; + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + if (kmi->flag & KMI_INACTIVE) { + continue; + } + + if (kmi->propvalue == snap_on) { + if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) || + (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) || + (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) || + ((kmi->type == EVT_OSKEY) && event->oskey)) { + return true; + } + } + } + return false; +} +#endif + +/* -------------------------------------------------------------------- */ +/** \name ED_gizmo_library specific API + * \{ */ + +void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d, + const float loc_prev[3], + const float loc_curr[3], + const float normal[3], + const uchar color_line[4], + const uchar color_point[4], + const short snap_elem_type) +{ + if (!loc_prev && !loc_curr) { + return; + } + + float view_inv[4][4]; + copy_m4_m4(view_inv, rv3d->viewinv); + + /* The size of the circle is larger than the vertex size. + * This prevents a drawing overlaps the other. */ + float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (loc_curr) { + immUniformColor4ubv(color_point); + imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos); + + /* draw normal if needed */ + if (normal) { + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, loc_curr); + immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]); + immEnd(); + } + } + + if (loc_prev) { + /* Draw an "X" indicating where the previous snap point is. + * This is useful for indicating perpendicular snap. */ + + /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */ + float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4]; + + /* Multiply by 0.75f so that the final size of the "X" is close to that of + * the circle. + * (A closer value is 0.7071f, but we don't need to be exact here). */ + float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev); + + mul_v3_v3fl(vx, view_inv[0], x_size); + mul_v3_v3fl(vy, view_inv[1], x_size); + + add_v3_v3v3(v1, vx, vy); + sub_v3_v3v3(v2, vx, vy); + negate_v3_v3(v3, v1); + negate_v3_v3(v4, v2); + + add_v3_v3(v1, loc_prev); + add_v3_v3(v2, loc_prev); + add_v3_v3(v3, loc_prev); + add_v3_v3(v4, loc_prev); + + immUniformColor4ubv(color_line); + immBegin(GPU_PRIM_LINES, 4); + immVertex3fv(pos, v3); + immVertex3fv(pos, v1); + immVertex3fv(pos, v4); + immVertex3fv(pos, v2); + immEnd(); + + if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + /* Dashed line. */ + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + immUniform1f("dash_width", 6.0f * U.pixelsize); + immUniform1f("dash_factor", 1.0f / 4.0f); + immUniformColor4ubv(color_line); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, loc_prev); + immVertex3fv(pos, loc_curr); + immEnd(); + } + } + + immUnbindProgram(); +} + +SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene, + const ARegion *region, + const View3D *v3d, + wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + if (gizmo_snap->snap_context_v3d == NULL) { + gizmo_snap->snap_context_v3d = ED_transform_snap_object_context_create_view3d( + scene, 0, region, v3d); + } + return gizmo_snap->snap_context_v3d; +} + +bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + return gizmo_snap->invert_snap; +} +void ED_gizmotypes_snap_3d_toggle_set(wmGizmo *gz, bool enable) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + gizmo_snap->use_snap_override = (int)enable; +} + +void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + gizmo_snap->use_snap_override = -1; +} + +short ED_gizmotypes_snap_3d_update(wmGizmo *gz, + struct Depsgraph *depsgraph, + const ARegion *region, + const View3D *v3d, + const wmWindowManager *wm, + const float mval_fl[2], + float r_loc[3], + float r_nor[3]) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + Scene *scene = DEG_get_input_scene(depsgraph); + float co[3], no[3]; + short snap_elem = 0; + int snap_elem_index[3] = {-1, -1, -1}; + int index = -1; + + if (gizmo_snap->use_snap_override != -1) { + if (gizmo_snap->use_snap_override == false) { + gizmo_snap->snap_elem = 0; + return 0; + } + } + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + if (wm && wm->winactive) { + gizmo_snap->invert_snap = invert_snap(gz, wm, wm->winactive->eventstate); + } + + if (gizmo_snap->use_snap_override == -1) { + const ToolSettings *ts = scene->toolsettings; + if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) { + gizmo_snap->snap_elem = 0; + return 0; + } + } +#else + UNUSED_VARS(wm); +#endif + + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements"); + int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); + if (gz_prop->prop != gizmo_snap->prop_snap_force) { + int snap_elements_force = RNA_property_enum_get(gz->ptr, gizmo_snap->prop_snap_force); + snap_elements |= snap_elements_force; + } + snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR); + + if (snap_elements) { + float prev_co[3] = {0.0f}; + if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) { + RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_co); + } + else { + snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR; + } + + float dist_px = 12.0f * U.pixelsize; + + ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz); + snap_elem = ED_transform_snap_object_project_view3d_ex(gizmo_snap->snap_context_v3d, + depsgraph, + snap_elements, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = true, + .use_occlusion_test = true, + }, + mval_fl, + prev_co, + &dist_px, + co, + no, + &index, + NULL, + NULL); + } + + if (snap_elem == 0) { + RegionView3D *rv3d = region->regiondata; + ED_view3d_win_to_3d(v3d, region, rv3d->ofs, mval_fl, co); + zero_v3(no); + } + else if (snap_elem == SCE_SNAP_MODE_VERTEX) { + snap_elem_index[0] = index; + } + else if (snap_elem & + (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + snap_elem_index[1] = index; + } + else if (snap_elem == SCE_SNAP_MODE_FACE) { + snap_elem_index[2] = index; + } + + gizmo_snap->snap_elem = snap_elem; + RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_location, co); + RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_normal, no); + RNA_property_int_set_array(gz->ptr, gizmo_snap->prop_elem_index, snap_elem_index); + + if (r_loc) { + copy_v3_v3(r_loc, co); + } + if (r_nor) { + copy_v3_v3(r_nor, no); + } + + return snap_elem; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name GIZMO_GT_snap_3d + * \{ */ + +static void gizmo_snap_setup(wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + + /* For quick access to the props. */ + gizmo_snap->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point"); + gizmo_snap->prop_location = RNA_struct_find_property(gz->ptr, "location"); + gizmo_snap->prop_normal = RNA_struct_find_property(gz->ptr, "normal"); + gizmo_snap->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index"); + gizmo_snap->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force"); + + gizmo_snap->use_snap_override = -1; + + /* Prop fallback. */ + WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1); + + /* Flags. */ + gz->flag |= WM_GIZMO_NO_TOOLTIP; +} + +static void gizmo_snap_draw(const bContext *C, wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + if (gizmo_snap->snap_elem == 0) { + return; + } + + ARegion *region = CTX_wm_region(C); + RegionView3D *rv3d = region->regiondata; + + /* Ideally, we shouldn't assign values here. + * But `test_select` is not called during navigation. + * And `snap_elem` is not really useful in this case. */ + if ((rv3d->rflag & RV3D_NAVIGATING) || + (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) { + gizmo_snap->snap_elem = 0; + return; + } + + float location[3], prev_point_stack[3], *prev_point = NULL; + uchar color_line[4], color_point[4]; + + RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_location, location); + + UI_GetThemeColor3ubv(TH_TRANSFORM, color_line); + color_line[3] = 128; + + rgba_float_to_uchar(color_point, gz->color); + + if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) { + RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_point_stack); + prev_point = prev_point_stack; + } + + GPU_line_smooth(false); + + GPU_line_width(1.0f); + ED_gizmotypes_snap_3d_draw_util( + rv3d, prev_point, location, NULL, color_line, color_point, gizmo_snap->snap_elem); +} + +static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2]) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + wmWindowManager *wm = CTX_wm_manager(C); + const bool invert = invert_snap(gz, wm, wm->winactive->eventstate); + if (gizmo_snap->invert_snap == invert && gizmo_snap->mval[0] == mval[0] && + gizmo_snap->mval[1] == mval[1]) { + /* Performance, do not update. */ + return gizmo_snap->snap_elem ? 0 : -1; + } + gizmo_snap->invert_snap = invert; +#else + if (gizmo_snap->mval[0] == mval[0] && gizmo_snap->mval[1] == mval[1]) { + /* Performance, do not update. */ + return gizmo_snap->snap_elem ? 0 : -1; + } +#endif + copy_v2_v2_int(gizmo_snap->mval, mval); + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK + if (gizmo_snap->keymap == NULL) { + gizmo_snap->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); + gizmo_snap->snap_on = -1; + RNA_enum_value_from_id(gizmo_snap->keymap->modal_items, "SNAP_ON", &gizmo_snap->snap_on); + } +#endif + + ARegion *region = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + const float mval_fl[2] = {UNPACK2(mval)}; + short snap_elem = ED_gizmotypes_snap_3d_update( + gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, mval_fl, NULL, NULL); + + if (snap_elem) { + ED_region_tag_redraw_editor_overlays(region); + return 0; + } + + return -1; +} + +static int gizmo_snap_modal(bContext *UNUSED(C), + wmGizmo *UNUSED(gz), + const wmEvent *UNUSED(event), + eWM_GizmoFlagTweak UNUSED(tweak_flag)) +{ + return OPERATOR_RUNNING_MODAL; +} + +static int gizmo_snap_invoke(bContext *UNUSED(C), + wmGizmo *UNUSED(gz), + const wmEvent *UNUSED(event)) +{ + return OPERATOR_RUNNING_MODAL; +} + +static void gizmo_snap_free(wmGizmo *gz) +{ + SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz; + if (gizmo_snap->snap_context_v3d) { + ED_transform_snap_object_context_destroy(gizmo_snap->snap_context_v3d); + gizmo_snap->snap_context_v3d = NULL; + } +} + +static void GIZMO_GT_snap_3d(wmGizmoType *gzt) +{ + /* identifiers */ + gzt->idname = "GIZMO_GT_snap_3d"; + + /* api callbacks */ + gzt->setup = gizmo_snap_setup; + gzt->draw = gizmo_snap_draw; + gzt->test_select = gizmo_snap_test_select; + gzt->modal = gizmo_snap_modal; + gzt->invoke = gizmo_snap_invoke; + gzt->free = gizmo_snap_free; + + gzt->struct_size = sizeof(SnapGizmo3D); + + const EnumPropertyItem *rna_enum_snap_element_items; + { + /* Get Snap Element Items enum. */ + bool free; + PointerRNA toolsettings_ptr; + RNA_pointer_create(NULL, &RNA_ToolSettings, NULL, &toolsettings_ptr); + PropertyRNA *prop = RNA_struct_find_property(&toolsettings_ptr, "snap_elements"); + RNA_property_enum_items( + NULL, &toolsettings_ptr, prop, &rna_enum_snap_element_items, NULL, &free); + + BLI_assert(free == false); + } + + /* Setup. */ + RNA_def_enum_flag(gzt->srna, + "snap_elements_force", + rna_enum_snap_element_items, + SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE, + "Snap Elements", + ""); + + RNA_def_float_vector(gzt->srna, + "prev_point", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Previous Point", + "Point that defines the location of the perpendicular snap", + FLT_MIN, + FLT_MAX); + + /* Returns. */ + RNA_def_float_vector(gzt->srna, + "location", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Location", + "Snap Point Location", + FLT_MIN, + FLT_MAX); + + RNA_def_float_vector(gzt->srna, + "normal", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Normal", + "Snap Point Normal", + FLT_MIN, + FLT_MAX); + + RNA_def_int_vector(gzt->srna, + "snap_elem_index", + 3, + NULL, + INT_MIN, + INT_MAX, + "Snap Element", + "Array index of face, edge and vert snapped", + INT_MIN, + INT_MAX); + + /* Read/Write. */ + WM_gizmotype_target_property_def(gzt, "snap_elements", PROP_ENUM, 1); +} + +void ED_gizmotypes_snap_3d(void) +{ + WM_gizmotype_append(GIZMO_GT_snap_3d); +} + +/** \} */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 4444396558b..4330a07057e 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -354,10 +354,6 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { mode = OB_MODE_PAINT_GPENCIL; - BKE_brush_gpencil_paint_presets(bmain, ts, false); - - /* Ensure Palette by default. */ - BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); } else { mode = OB_MODE_OBJECT; @@ -373,8 +369,16 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) } if (mode == OB_MODE_PAINT_GPENCIL) { - /* be sure we have brushes */ + /* Be sure we have brushes and Paint settings. + * Need Draw and Vertex (used fro Tint). */ BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); + BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint); + + BKE_brush_gpencil_paint_presets(bmain, ts, false); + + /* Ensure Palette by default. */ + BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); + Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { @@ -466,7 +470,6 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) { mode = OB_MODE_SCULPT_GPENCIL; - BKE_brush_gpencil_sculpt_presets(bmain, ts, false); } else { mode = OB_MODE_OBJECT; @@ -485,6 +488,8 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) /* be sure we have brushes */ BKE_paint_ensure(ts, (Paint **)&ts->gp_sculptpaint); BKE_paint_toolslots_brush_validate(bmain, &ts->gp_sculptpaint->paint); + + BKE_brush_gpencil_sculpt_presets(bmain, ts, false); } /* setup other modes */ @@ -572,7 +577,6 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) { mode = OB_MODE_WEIGHT_GPENCIL; - BKE_brush_gpencil_weight_presets(bmain, ts, false); } else { mode = OB_MODE_OBJECT; @@ -591,6 +595,8 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op) /* be sure we have brushes */ BKE_paint_ensure(ts, (Paint **)&ts->gp_weightpaint); BKE_paint_toolslots_brush_validate(bmain, &ts->gp_weightpaint->paint); + + BKE_brush_gpencil_weight_presets(bmain, ts, false); } /* setup other modes */ @@ -675,10 +681,6 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) /* set mode */ if (gpd->flag & GP_DATA_STROKE_VERTEXMODE) { mode = OB_MODE_VERTEX_GPENCIL; - BKE_brush_gpencil_vertex_presets(bmain, ts, false); - - /* Ensure Palette by default. */ - BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); } else { mode = OB_MODE_OBJECT; @@ -697,6 +699,11 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) /* be sure we have brushes */ BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint); BKE_paint_toolslots_brush_validate(bmain, &ts->gp_vertexpaint->paint); + + BKE_brush_gpencil_vertex_presets(bmain, ts, false); + + /* Ensure Palette by default. */ + BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C)); } /* setup other modes */ @@ -3656,7 +3663,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) int cfra_prv = INT_MIN; /* init snap context for geometry projection */ - sctx = ED_transform_snap_object_context_create_view3d(bmain, scene, 0, region, CTX_wm_view3d(C)); + sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C)); /* Go through each editable + selected stroke, adjusting each of its points one by one... */ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index a98ccb1cba6..473913c5459 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -699,16 +699,13 @@ struct GP_EditableStrokes_Iter { const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { \ if (BKE_gpencil_layer_is_editable(gpl)) { \ - bGPDframe *init_gpf_ = gpl->actframe; \ - if (is_multiedit_) { \ - init_gpf_ = gpl->frames.first; \ - } \ + bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \ BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ /* loop over strokes */ \ - for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_->strokes) { \ /* skip strokes that are invalid for current view */ \ if (ED_gpencil_stroke_can_use(C, gps) == false) \ continue; \ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 309329e4649..4e83c4fb11c 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -2071,8 +2071,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps return; } - /* Eraser mode: If no active strokes, just return. */ + /* Eraser mode: If no active strokes, add one or just return. */ if (paintmode == GP_PAINTMODE_ERASER) { + /* Eraser mode: + * 1) Add new frames to all frames that we might touch, + * 2) Ensure that p->gpf refers to the frame used for the active layer + * (to avoid problems with other tools which expect it to exist) + * + * This is done only if additive drawing is enabled. + */ bool has_layer_to_erase = false; LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) { @@ -2081,12 +2088,27 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps continue; } + /* Add a new frame if needed (and based off the active frame, + * as we need some existing strokes to erase) + * + * Note: We don't add a new frame if there's nothing there now, so + * -> If there are no frames at all, don't add one + * -> If there are no strokes in that frame, don't add a new empty frame + */ if (gpl->actframe && gpl->actframe->strokes.first) { + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); + } has_layer_to_erase = true; break; } } + /* Ensure this gets set. */ + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { + p->gpf = p->gpl->actframe; + } + if (has_layer_to_erase == false) { p->status = GP_STATUS_ERROR; return; diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index 2238d768bcd..0dfc7e0728e 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -59,8 +59,8 @@ typedef struct GpUvData { float ob_scale; float initial_length; + float initial_transform[2]; float pixel_size; /* use when mouse input is interpreted as spatial distance */ - bool is_modal; /* Arrays of original loc/rot/scale by stroke. */ float (*array_loc)[2]; @@ -140,19 +140,12 @@ static void gpencil_stroke_center(bGPDstroke *gps, float r_center[3]) } } -static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is_modal) +static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) { GpUvData *opdata; - if (is_modal) { - float zero[2] = {0.0f}; - RNA_float_set_array(op->ptr, "location", zero); - RNA_float_set(op->ptr, "rotation", 0.0f); - RNA_float_set(op->ptr, "scale", 1.0f); - } op->customdata = opdata = MEM_mallocN(sizeof(GpUvData), __func__); - opdata->is_modal = is_modal; opdata->ob = CTX_data_active_object(C); opdata->gpd = (bGPdata *)opdata->ob->data; gp_point_conversion_init(C, &opdata->gsc); @@ -164,12 +157,10 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is opdata->vinit_rotation[0] = 1.0f; opdata->vinit_rotation[1] = 0.0f; - if (is_modal) { - ARegion *region = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); - opdata->draw_handle_pixel = ED_region_draw_cb_activate( - region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); - } + opdata->draw_handle_pixel = ED_region_draw_cb_activate( + region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); /* Calc selected strokes center. */ zero_v2(opdata->mcenter); @@ -205,7 +196,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is } GP_EDITABLE_STROKES_END(gpstroke_iter); } - /* convert to 2D */ + /* Convert to 2D. */ gp_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter); return true; @@ -218,11 +209,9 @@ static void gpencil_uv_transform_exit(bContext *C, wmOperator *op) opdata = op->customdata; - if (opdata->is_modal) { - ARegion *region = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); - ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel); - } + ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel); WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT); @@ -253,66 +242,54 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) const int mode = RNA_enum_get(op->ptr, "mode"); GpUvData *opdata = op->customdata; bGPdata *gpd = opdata->gpd; + bool changed = false; /* Get actual vector. */ float vr[2]; + float mdiff[2]; + sub_v2_v2v2(vr, opdata->mouse, opdata->mcenter); normalize_v2(vr); - float location[2]; - RNA_float_get_array(op->ptr, "location", location); - - float uv_rotation = (opdata->is_modal) ? angle_signed_v2v2(opdata->vinit_rotation, vr) : - RNA_float_get(op->ptr, "rotation"); - uv_rotation *= SMOOTH_FACTOR; - - if (opdata->is_modal) { - RNA_float_set(op->ptr, "rotation", uv_rotation); - } + float uv_rotation = angle_signed_v2v2(opdata->vinit_rotation, vr); int i = 0; - /* Apply transformations to all strokes. */ - if ((mode == GP_UV_TRANSLATE) || (!opdata->is_modal)) { - float mdiff[2]; - mdiff[0] = opdata->mcenter[0] - opdata->mouse[0]; - mdiff[1] = opdata->mcenter[1] - opdata->mouse[1]; + /* Translate. */ + if (mode == GP_UV_TRANSLATE) { + + mdiff[0] = opdata->mouse[0] - opdata->initial_transform[0]; + /* Y axis is inverted. */ + mdiff[1] = (opdata->mouse[1] - opdata->initial_transform[1]) * -1.0f; /* Apply a big amount of smooth always for translate to get smooth result. */ - mul_v2_fl(mdiff, 0.006f); + mul_v2_fl(mdiff, 0.002f); + RNA_float_set_array(op->ptr, "location", mdiff); - /* Apply angle in translation. */ - mdiff[0] *= cos(uv_rotation); - mdiff[1] *= sin(uv_rotation); - if (opdata->is_modal) { - RNA_float_set_array(op->ptr, "location", mdiff); - } + GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { + if (gps->flag & GP_STROKE_SELECT) { - changed = (bool)((mdiff[0] != 0.0f) || (mdiff[1] != 0.0f)); - if (changed) { - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - if (gps->flag & GP_STROKE_SELECT) { - if (opdata->is_modal) { - add_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff); - } - else { - copy_v2_v2(gps->uv_translation, location); - } - /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gps); - i++; - } + sub_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff); + changed = true; + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + i++; } - GP_EDITABLE_STROKES_END(gpstroke_iter); } + GP_EDITABLE_STROKES_END(gpstroke_iter); } - if ((mode == GP_UV_ROTATE) || (!opdata->is_modal)) { - changed = (bool)(uv_rotation != 0.0f); + /* Rotate. */ + if (mode == GP_UV_ROTATE) { + changed |= (bool)(uv_rotation != 0.0f); + RNA_float_set(op->ptr, "rotation", uv_rotation); + if (changed) { GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { - gps->uv_rotation = (opdata->is_modal) ? opdata->array_rot[i] + uv_rotation : uv_rotation; + gps->uv_rotation = opdata->array_rot[i] - uv_rotation; + /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); i++; @@ -322,25 +299,22 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) } } - if ((mode == GP_UV_SCALE) || (!opdata->is_modal)) { - float mdiff[2]; + /* Scale. */ + if (mode == GP_UV_SCALE) { mdiff[0] = opdata->mcenter[0] - opdata->mouse[0]; mdiff[1] = opdata->mcenter[1] - opdata->mouse[1]; - float scale = (opdata->is_modal) ? - ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / - opdata->ob_scale : - RNA_float_get(op->ptr, "scale"); + float scale = ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) / + opdata->ob_scale; + scale *= SMOOTH_FACTOR; + RNA_float_set(op->ptr, "scale", scale); - if (opdata->is_modal) { - RNA_float_set(op->ptr, "scale", scale); - } + changed |= (bool)(scale != 0.0f); - changed = (bool)(scale != 0.0f); if (changed) { GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { - gps->uv_scale = (opdata->is_modal) ? opdata->array_scale[i] + scale : scale; + gps->uv_scale = opdata->array_scale[i] + scale; /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); i++; @@ -350,7 +324,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) } } - if ((!opdata->is_modal) || (changed)) { + if (changed) { /* Update cursor line. */ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, NULL); @@ -360,21 +334,6 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) return changed; } -static int gpencil_transform_fill_exec(bContext *C, wmOperator *op) -{ - if (!gpencil_uv_transform_init(C, op, false)) { - return OPERATOR_CANCELLED; - } - - if (!gpencil_uv_transform_calc(C, op)) { - gpencil_uv_transform_exit(C, op); - return OPERATOR_CANCELLED; - } - - gpencil_uv_transform_exit(C, op); - return OPERATOR_FINISHED; -} - static bool gpencil_transform_fill_poll(bContext *C) { if (!ED_operator_view3d_active(C)) { @@ -404,7 +363,7 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv float mlen[2]; float center_3d[3]; - if (!gpencil_uv_transform_init(C, op, true)) { + if (!gpencil_uv_transform_init(C, op)) { return OPERATOR_CANCELLED; } @@ -414,16 +373,22 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv opdata->mouse[1] = event->mval[1]; copy_v3_v3(center_3d, opdata->ob->loc); - mlen[0] = opdata->mcenter[0] - event->mval[0]; - mlen[1] = opdata->mcenter[1] - event->mval[1]; + mlen[0] = event->mval[0] - opdata->mcenter[0]; + mlen[1] = event->mval[1] - opdata->mcenter[1]; opdata->initial_length = len_v2(mlen); - opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; + /* Consider initial offset as zero position. */ + copy_v2fl_v2i(opdata->initial_transform, event->mval); + + /* Consider initial position as the orientation vector. */ + const int mode = RNA_enum_get(op->ptr, "mode"); + if (mode == GP_UV_ROTATE) { + opdata->vinit_rotation[0] = mlen[0]; + opdata->vinit_rotation[1] = mlen[1]; + normalize_v2(opdata->vinit_rotation); + } - /* Calc init rotation vector. */ - float mouse[2] = {event->mval[0], event->mval[1]}; - sub_v2_v2v2(opdata->vinit_rotation, mouse, opdata->mcenter); - normalize_v2(opdata->vinit_rotation); + opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; gpencil_uv_transform_calc(C, op); @@ -492,7 +457,6 @@ void GPENCIL_OT_transform_fill(wmOperatorType *ot) /* api callbacks */ ot->invoke = gpencil_transform_fill_invoke; ot->modal = gpencil_transform_fill_modal; - ot->exec = gpencil_transform_fill_exec; ot->cancel = gpencil_transform_fill_cancel; ot->poll = gpencil_transform_fill_poll; diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index 07eade23506..a1a5d65b61d 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -40,9 +40,15 @@ void ED_gizmotypes_facemap_3d(void); void ED_gizmotypes_preselect_3d(void); void ED_gizmotypes_primitive_3d(void); void ED_gizmotypes_blank_3d(void); +void ED_gizmotypes_snap_3d(void); -struct Object; +struct ARegion; struct bContext; +struct Depsgraph; +struct Object; +struct SnapObjectContext; +struct wmWindowManager; +struct View3D; struct wmGizmo; /* -------------------------------------------------------------------- */ @@ -223,8 +229,9 @@ enum { }; /* -------------------------------------------------------------------- */ -/* Gizmo Drawing Functions */ +/* Specific gizmos utils */ +/* dial3d_gizmo.c */ struct Dial3dParams { int draw_options; float angle_ofs; @@ -241,6 +248,33 @@ void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4], const bool select, struct Dial3dParams *params); +/* snap3d_gizmo.c */ +#define USE_SNAP_DETECT_FROM_KEYMAP_HACK +void ED_gizmotypes_snap_3d_draw_util(struct RegionView3D *rv3d, + const float loc_prev[3], + const float loc_curr[3], + const float normal[3], + const uchar color_line[4], + const uchar color_point[4], + const short snap_elem_type); +struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene, + const struct ARegion *region, + const struct View3D *v3d, + struct wmGizmo *gz); + +bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz); +void ED_gizmotypes_snap_3d_toggle_set(struct wmGizmo *gz, bool enable); +void ED_gizmotypes_snap_3d_toggle_clear(struct wmGizmo *gz); + +short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz, + struct Depsgraph *depsgraph, + const struct ARegion *region, + const struct View3D *v3d, + const struct wmWindowManager *wm, + const float mval_fl[2], + float r_loc[3], + float r_nor[3]); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 2dbd979564e..58364e69679 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -34,13 +34,13 @@ struct PointerRNA; struct Brush; struct GP_SpaceConversion; +struct GpRandomSettings; struct bGPDframe; struct bGPDlayer; struct bGPDspoint; struct bGPDstroke; struct bGPdata; struct tGPspoint; -struct GpRandomSettings; struct ARegion; struct Depsgraph; diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 1dc98cfee2f..3471f9dcce9 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -107,7 +107,10 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex); bool ED_node_select_check(ListBase *lb); void ED_node_select_all(ListBase *lb, int action); void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree); -void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); +void ED_node_set_active(struct Main *bmain, + struct bNodeTree *ntree, + struct bNode *node, + bool *r_active_texture_changed); void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 32e62a6436c..5adc99a8ae0 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -260,6 +260,7 @@ float ED_object_new_primitive_matrix(struct bContext *C, #define OBJECT_ADD_SIZE_MAXF 1.0e12f void ED_object_add_unit_props_size(struct wmOperatorType *ot); +void ED_object_add_unit_props_radius_ex(struct wmOperatorType *ot, float default_value); void ED_object_add_unit_props_radius(struct wmOperatorType *ot); void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode); void ED_object_add_mesh_props(struct wmOperatorType *ot); @@ -268,6 +269,7 @@ bool ED_object_add_generic_get_opts(struct bContext *C, const char view_align_axis, float loc[3], float rot[3], + float scale[3], bool *enter_editmode, unsigned short *local_view_bits, bool *is_view_aligned); diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index d3fc5174dd9..0325ad9fdba 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -29,6 +29,7 @@ extern "C" { struct Base; struct ListBase; +struct SpaceOutliner; struct bContext; bool ED_outliner_collections_editor_poll(struct bContext *C); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 43f3a578bfe..bc6a4b23609 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -347,6 +347,7 @@ bool ED_operator_info_active(struct bContext *C); bool ED_operator_console_active(struct bContext *C); bool ED_operator_object_active(struct bContext *C); +bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob); bool ED_operator_object_active_editable(struct bContext *C); bool ED_operator_object_active_editable_mesh(struct bContext *C); bool ED_operator_object_active_editable_font(struct bContext *C); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 27b7511c8a2..9969acd04b7 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -158,7 +158,7 @@ int BIF_countTransformOrientation(const struct bContext *C); #define P_CURSOR_EDIT (1 << 14) #define P_CLNOR_INVALIDATE (1 << 15) /* For properties performed when confirming the transformation. */ -#define P_POST_TRANSFORM (1 << 16) +#define P_POST_TRANSFORM (1 << 19) void Transform_Properties(struct wmOperatorType *ot, int flags); diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index b998ac87819..8feb73436a6 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -77,11 +77,8 @@ struct SnapObjectParams { }; typedef struct SnapObjectContext SnapObjectContext; -SnapObjectContext *ED_transform_snap_object_context_create(struct Main *bmain, - struct Scene *scene, - int flag); -SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Main *bmain, - struct Scene *scene, +SnapObjectContext *ED_transform_snap_object_context_create(struct Scene *scene, int flag); +SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Scene *scene, int flag, /* extra args for view3d */ const struct ARegion *region, diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 8c565536c71..f656aaf9c07 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -50,20 +50,17 @@ void ED_operatortypes_uvedit(void); void ED_keymap_uvedit(struct wmKeyConfig *keyconf); bool ED_uvedit_minmax(const struct Scene *scene, - struct Image *ima, struct Object *obedit, float min[2], float max[2]); void ED_uvedit_select_all(struct BMesh *bm); bool ED_uvedit_minmax_multi(const struct Scene *scene, - struct Image *ima, struct Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]); bool ED_uvedit_center_multi(const struct Scene *scene, - Image *ima, struct Object **objects_edit, uint objects_len, float r_cent[2], @@ -95,11 +92,7 @@ void ED_object_assign_active_image(struct Main *bmain, bool ED_uvedit_test(struct Object *obedit); /* visibility and selection */ -bool uvedit_face_visible_nolocal_ex(const struct ToolSettings *ts, struct BMFace *efa); -bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, - struct Object *obedit, - struct Image *ima, - struct BMFace *efa); +bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa); bool uvedit_face_select_test_ex(const struct ToolSettings *ts, struct BMFace *efa, const int cd_loop_uv_offset); @@ -110,11 +103,7 @@ bool uvedit_uv_select_test_ex(const struct ToolSettings *ts, struct BMLoop *l, const int cd_loop_uv_offset); -bool uvedit_face_visible_nolocal(const struct Scene *scene, struct BMFace *efa); -bool uvedit_face_visible_test(const struct Scene *scene, - struct Object *obedit, - struct Image *ima, - struct BMFace *efa); +bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa); bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, const int cd_loop_uv_offset); @@ -175,12 +164,10 @@ void uvedit_uv_select_disable(struct BMEditMesh *em, bool ED_uvedit_nearest_uv(const struct Scene *scene, struct Object *obedit, - struct Image *ima, const float co[2], float *dist_sq, float r_uv[2]); bool ED_uvedit_nearest_uv_multi(const struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 668ca3c6437..beca517f0a6 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -129,6 +129,9 @@ enum eV3DCursorOrient { void ED_view3d_background_color_get(const struct Scene *scene, const struct View3D *v3d, float r_color[3]); +bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene, + const struct Object *ob, + const struct View3D *v3d); void ED_view3d_cursor3d_position(struct bContext *C, const int mval[2], const bool use_depth, @@ -246,6 +249,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc, struct BPoint *bp, struct BezTriple *bezt, int beztindex, + bool handle_visible, const float screen_co[2]), void *userData, const eV3DProjTest clip_flag); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 8b7b0430765..c95f517b155 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -239,6 +239,8 @@ enum { #define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f) +#define UI_PANEL_BOX_STYLE_MARGIN (U.widget_unit * 0.2f) + /* but->drawflag - these flags should only affect how the button is drawn. */ /* Note: currently, these flags _are not passed_ to the widget's state() or draw() functions * (except for the 'align' ones)! @@ -1679,6 +1681,7 @@ void UI_panel_end(const struct ScrArea *area, int width, int height, bool open); + void UI_panels_scale(struct ARegion *region, float new_width); void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y); int UI_panel_size_y(const struct Panel *panel); @@ -1702,6 +1705,24 @@ void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_ struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname); +/* Polyinstantiated panels for representing a list of data. */ +struct Panel *UI_panel_add_instanced(struct ScrArea *area, + struct ARegion *region, + struct ListBase *panels, + char *panel_idname, + int list_index); +void UI_panels_free_instanced(struct bContext *C, struct ARegion *region); + +#define LIST_PANEL_UNIQUE_STR_LEN 4 +void UI_list_panel_unique_str(struct Panel *panel, char *r_name); + +void UI_panel_set_expand_from_list_data(const struct bContext *C, struct Panel *panel); + +typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname); +bool UI_panel_list_matches_data(struct ARegion *region, + struct ListBase *data, + uiListPanelIDFromDataFunc panel_idname_func); + /* Handlers * * Handlers that can be registered in regions, areas and windows for @@ -2417,6 +2438,8 @@ uiBut *UI_context_active_but_prop_get(const struct bContext *C, struct PropertyRNA **r_prop, int *r_index); void UI_context_active_but_prop_handle(struct bContext *C); +void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region); + struct wmOperator *UI_context_active_operator_get(const struct bContext *C); void UI_context_update_anim_flag(const struct bContext *C); void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index c2c27af9770..e4fb0631f06 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -68,9 +68,9 @@ set(SRC interface_region_tooltip.c interface_regions.c interface_style.c - interface_templates.c interface_template_search_menu.c interface_template_search_operator.c + interface_templates.c interface_undo.c interface_utils.c interface_widgets.c diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index 09811fab52d..32cae609395 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -124,7 +124,11 @@ bool ui_but_can_align(const uiBut *but) int ui_but_align_opposite_to_area_align_get(const ARegion *region) { - switch (RGN_ALIGN_ENUM_FROM_MASK(region->alignment)) { + const ARegion *align_region = (region->alignment & RGN_SPLIT_PREV && region->prev) ? + region->prev : + region; + + switch (RGN_ALIGN_ENUM_FROM_MASK(align_region->alignment)) { case RGN_ALIGN_TOP: return UI_BUT_ALIGN_DOWN; case RGN_ALIGN_BOTTOM: @@ -502,7 +506,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region) butal->but->drawflag |= align; butal_other->but->drawflag |= align_opp; - if (butal->dists[side]) { + if (!IS_EQF(butal->dists[side], 0.0f)) { float *delta = &butal->dists[side]; if (*butal->borders[side] < *butal_other->borders[side_opp]) { @@ -513,7 +517,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region) } co = (*butal->borders[side] += *delta); - if (butal_other->dists[side_opp]) { + if (!IS_EQF(butal_other->dists[side_opp], 0.0f)) { BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta)); *butal_other->borders[side_opp] = co; butal_other->dists[side_opp] = 0.0f; diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 7527a1e0662..ace367fd513 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -82,11 +82,13 @@ static bool eyedropper_init(bContext *C, wmOperator *op) eye->use_accum = RNA_boolean_get(op->ptr, "use_accumulate"); uiBut *but = UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index); + const enum PropertySubType prop_subtype = eye->prop ? RNA_property_subtype(eye->prop) : 0; if ((eye->ptr.data == NULL) || (eye->prop == NULL) || (RNA_property_editable(&eye->ptr, eye->prop) == false) || (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || - (RNA_property_type(eye->prop) != PROP_FLOAT)) { + (RNA_property_type(eye->prop) != PROP_FLOAT) || + (ELEM(prop_subtype, PROP_COLOR, PROP_COLOR_GAMMA) == 0)) { MEM_freeN(eye); return false; } @@ -96,7 +98,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op) float col[4]; RNA_property_float_get_array(&eye->ptr, eye->prop, col); - if (RNA_property_subtype(eye->prop) != PROP_COLOR) { + if (prop_subtype != PROP_COLOR) { Scene *scene = CTX_data_scene(C); const char *display_device; @@ -290,7 +292,10 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( { /* init */ if (eyedropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); + wmWindow *win = CTX_wm_window(C); + /* Workaround for de-activating the button clearing the cursor, see T76794 */ + UI_context_active_but_clear(C, win, CTX_wm_region(C)); + WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c index be23eacafff..24d06361c54 100644 --- a/source/blender/editors/interface/interface_eyedropper_colorband.c +++ b/source/blender/editors/interface/interface_eyedropper_colorband.c @@ -304,7 +304,10 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven { /* init */ if (eyedropper_colorband_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); + wmWindow *win = CTX_wm_window(C); + /* Workaround for de-activating the button clearing the cursor, see T76794 */ + UI_context_active_but_clear(C, win, CTX_wm_region(C)); + WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index d9c77c26941..f2217db9b7d 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -316,7 +316,10 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED { /* init */ if (datadropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); + wmWindow *win = CTX_wm_window(C); + /* Workaround for de-activating the button clearing the cursor, see T76794 */ + UI_context_active_but_clear(C, win, CTX_wm_region(C)); + WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index 907da917e75..5c85edc94a1 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -311,7 +311,10 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE { /* init */ if (depthdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); + wmWindow *win = CTX_wm_window(C); + /* Workaround for de-activating the button clearing the cursor, see T76794 */ + UI_context_active_but_clear(C, win, CTX_wm_region(C)); + WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c index 89c087855bc..276cc70f2b5 100644 --- a/source/blender/editors/interface/interface_eyedropper_driver.c +++ b/source/blender/editors/interface/interface_eyedropper_driver.c @@ -180,7 +180,10 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS { /* init */ if (driverdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); + wmWindow *win = CTX_wm_window(C); + /* Workaround for de-activating the button clearing the cursor, see T76794 */ + UI_context_active_but_clear(C, win, CTX_wm_region(C)); + WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index ebde1d54c07..eb99d044e17 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5559,7 +5559,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co } else if (but->type == UI_BTYPE_MENU) { if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) { - const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1; + const int direction = (event->type == WHEELDOWNMOUSE) ? 1 : -1; data->value = ui_but_menu_step(but, direction); @@ -8337,6 +8337,11 @@ void UI_context_active_but_prop_handle(bContext *C) } } +void UI_context_active_but_clear(bContext *C, wmWindow *win, ARegion *region) +{ + wm_event_handler_ui_cancel_ex(C, win, region, false); +} + wmOperator *UI_context_active_operator_get(const struct bContext *C) { ARegion *region_ctx = CTX_wm_region(C); @@ -8868,7 +8873,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) if (post_but) { button_activate_init(C, region, post_but, post_type); } - else { + else if (!((event->type == EVT_BUT_CANCEL) && (event->val == 1))) { /* XXX issue is because WM_event_add_mousemove(wm) is a bad hack and not reliable, * if that gets coded better this bypass can go away too. * diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 3748dbab519..6cd990ec2b0 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -105,7 +105,6 @@ extern const char ui_radial_dir_to_numpad[8]; extern const short ui_radial_dir_to_angle[8]; /* internal panel drawing defines */ -#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */ #define PNL_HEADER (UI_UNIT_Y * 1.2) /* 24 default */ /* bit button defines */ @@ -868,6 +867,7 @@ struct GPUBatch *ui_batch_roundbox_shadow_get(void); void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]); void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect); +void ui_draw_box_opaque(rcti *rect, int roundboxalign); void ui_draw_popover_back(struct ARegion *region, struct uiStyle *style, uiBlock *block, diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 04179721305..54f60a05cfd 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -39,6 +39,7 @@ #include "BLT_translation.h" +#include "DNA_screen_types.h" #include "DNA_userdef_types.h" #include "BKE_context.h" @@ -108,8 +109,14 @@ typedef struct uiHandlePanelData { int startsizex, startsizey; } uiHandlePanelData; +typedef struct PanelSort { + Panel *panel, *orig; +} PanelSort; + static int get_panel_real_size_y(const Panel *panel); static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state); +static int compare_panel(const void *a1, const void *a2); +static bool panel_type_context_poll(PanelType *panel_type, const char *context); static void panel_title_color_get(bool show_background, uchar color[4]) { @@ -235,9 +242,335 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_ return false; } +/********* Functions for instanced panels. ***********/ + +static Panel *UI_panel_add_instanced_ex( + ScrArea *area, ARegion *region, ListBase *panels, PanelType *panel_type, int list_index) +{ + Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel"); + panel->type = panel_type; + BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname)); + + panel->runtime.list_index = list_index; + + /* Add the panel's children too. Although they aren't instanced panels, we can still use this + * function to create them, as UI_panel_begin does other things we don't need to do. */ + LISTBASE_FOREACH (LinkData *, child, &panel_type->children) { + PanelType *child_type = child->data; + UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index); + } + + /* Make sure the panel is added to the end of the display-order as well. This is needed for + * loading existing files. + * + * Note: We could use special behavior to place it after the panel that starts the list of + * instanced panels, but that would add complexity that isn't needed for now. */ + int max_sortorder = 0; + LISTBASE_FOREACH (Panel *, existing_panel, panels) { + if (existing_panel->sortorder > max_sortorder) { + max_sortorder = existing_panel->sortorder; + } + } + panel->sortorder = max_sortorder + 1; + + BLI_addtail(panels, panel); + + return panel; +} + +/** + * Called in situations where panels need to be added dynamically rather than having only one panel + * corresponding to each PanelType. + */ +Panel *UI_panel_add_instanced( + ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, int list_index) +{ + ARegionType *region_type = region->type; + + PanelType *panel_type = BLI_findstring( + ®ion_type->paneltypes, panel_idname, offsetof(PanelType, idname)); + + if (panel_type == NULL) { + printf("Panel type '%s' not found.\n", panel_idname); + return NULL; + } + + return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index); +} + +/** + * Find a unique key to append to the idname for the lookup to the panel's #uiBlock. Needed for + * instanced panels, where there can be multiple with the same type and idname. + */ +void UI_list_panel_unique_str(Panel *panel, char *r_name) +{ + snprintf(r_name, LIST_PANEL_UNIQUE_STR_LEN, "%d", panel->runtime.list_index); +} + +/** + * Remove the #uiBlock corresponding to a panel. The lookup is needed because panels don't store + * a reference to their corresponding #uiBlock. + */ +static void panel_free_block(ARegion *region, Panel *panel) +{ + BLI_assert(panel->type); + + char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN]; + strncpy(block_name, panel->type->idname, BKE_ST_MAXNAME); + char unique_panel_str[LIST_PANEL_UNIQUE_STR_LEN]; + UI_list_panel_unique_str(panel, unique_panel_str); + strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN); + + LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { + if (STREQ(block->name, block_name)) { + BLI_remlink(®ion->uiblocks, block); + UI_block_free(NULL, block); + break; /* Only delete one block for this panel. */ + } + } +} + +/** + * Free a panel and it's children. + * + * \note The only panels that should need to be deleted at runtime are panels with the + * #PNL_INSTANCED flag set. + */ +static void panel_delete(ARegion *region, ListBase *panels, Panel *panel) +{ + /* Recursively delete children. */ + LISTBASE_FOREACH_MUTABLE (Panel *, child, &panel->children) { + panel_delete(region, &panel->children, child); + } + BLI_freelistN(&panel->children); + + panel_free_block(region, panel); + + BLI_remlink(panels, panel); + if (panel->activedata) { + MEM_freeN(panel->activedata); + } + MEM_freeN(panel); +} + +void UI_panels_free_instanced(bContext *C, ARegion *region) +{ + /* Delete panels with the instanced flag. */ + LISTBASE_FOREACH_MUTABLE (Panel *, panel, ®ion->panels) { + if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) { + /* Make sure the panel's handler is removed before deleting it. */ + if (panel->activedata != NULL) { + panel_activate_state(C, panel, PANEL_STATE_EXIT); + } + panel_delete(region, ®ion->panels, panel); + } + } +} + +/** + * Check if the instanced panels in the region's panels correspond to the list of data the panels + * represent. Returns false if the panels have been reordered or if the types from the list data + * don't match in any way. + * + * \param data: The list of data to check against the instanced panels. + * \param panel_idname_func: Function to find the panel type idname for each item in the data list. + * For a readability and generality, this lookup happens separately for each type of panel list. + */ +bool UI_panel_list_matches_data(ARegion *region, + ListBase *data, + uiListPanelIDFromDataFunc panel_idname_func) +{ + int data_len = BLI_listbase_count(data); + int i = 0; + Link *data_link = data->first; + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if (panel->type != NULL && panel->type->flag & PNL_INSTANCED) { + /* The panels were reordered by drag and drop. */ + if (panel->flag & PNL_INSTANCED_LIST_ORDER_CHANGED) { + return false; + } + + /* We reached the last data item before the last instanced panel. */ + if (data_link == NULL) { + return false; + } + + /* Check if the panel type matches the panel type from the data item. */ + char panel_idname[MAX_NAME]; + panel_idname_func(data_link, panel_idname); + if (!STREQ(panel_idname, panel->type->idname)) { + return false; + } + + data_link = data_link->next; + i++; + } + } + + /* If we didn't make it to the last list item, the panel list isn't complete. */ + if (i != data_len) { + return false; + } + + return true; +} + +static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *drag_panel) +{ + /* Without a type we cannot access the reorder callback. */ + if (drag_panel->type == NULL) { + return; + } + /* Don't reorder if this instanced panel doesn't support drag and drop reordering. */ + if (drag_panel->type->reorder == NULL) { + return; + } + + char *context = drag_panel->type->context; + + /* Find how many instanced panels with this context string. */ + int list_panels_len = 0; + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if (panel->type) { + if (panel_type_context_poll(panel->type, context)) { + if (panel->type->flag & PNL_INSTANCED) { + list_panels_len++; + } + } + } + } + + /* Sort the matching instanced panels by their display order. */ + PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), "instancedpanelsort"); + PanelSort *sort_index = panel_sort; + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if (panel->type) { + if (panel_type_context_poll(panel->type, context)) { + if (panel->type->flag & PNL_INSTANCED) { + sort_index->panel = MEM_dupallocN(panel); + sort_index->orig = panel; + sort_index++; + } + } + } + } + qsort(panel_sort, list_panels_len, sizeof(*panel_sort), compare_panel); + + /* Find how many of those panels are above this panel. */ + int move_to_index = 0; + for (; move_to_index < list_panels_len; move_to_index++) { + if (panel_sort[move_to_index].orig == drag_panel) { + break; + } + } + + /* Free panel sort array. */ + int i = 0; + for (sort_index = panel_sort; i < list_panels_len; i++, sort_index++) { + MEM_freeN(sort_index->panel); + } + MEM_freeN(panel_sort); + + /* Don't reorder the panel didn't change order after being dropped. */ + if (move_to_index == drag_panel->runtime.list_index) { + return; + } + + /* Set the bit to tell the interface to instanced the list. */ + drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED; + + /* Finally, move this panel's list item to the new index in its list. */ + drag_panel->type->reorder(C, drag_panel, move_to_index); +} + +/** + * Recursive implementation for #UI_panel_set_expand_from_list_data. + */ +static void panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index) +{ + bool open = (flag & (1 << *flag_index)); + if (open) { + panel->flag &= ~PNL_CLOSEDY; + } + else { + panel->flag |= PNL_CLOSEDY; + } + LISTBASE_FOREACH (Panel *, child, &panel->children) { + *flag_index = *flag_index + 1; + panel_set_expand_from_list_data_recursive(child, flag, flag_index); + } +} + +/** + * Set the expansion of the panel and its subpanels from the flag stored by the list data + * corresponding to this panel. The flag has expansion stored in each bit in depth first + * order. + */ +void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel) +{ + BLI_assert(panel->type != NULL); + BLI_assert(panel->type->flag & PNL_INSTANCED); + if (panel->type->get_list_data_expand_flag == NULL) { + /* Instanced panel doesn't support loading expansion. */ + return; + } + + short expand_flag = panel->type->get_list_data_expand_flag(C, panel); + short flag_index = 0; + panel_set_expand_from_list_data_recursive(panel, expand_flag, &flag_index); +} + +/** + * Recursive implementation for #set_panels_list_data_expand_flag. + */ +static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index) +{ + bool open = !(panel->flag & PNL_CLOSEDY); + if (open) { + *flag |= (1 << *flag_index); + } + else { + *flag &= ~(1 << *flag_index); + } + LISTBASE_FOREACH (Panel *, child, &panel->children) { + *flag_index = *flag_index + 1; + get_panel_expand_flag(child, flag, flag_index); + } +} + +/** + * Call the callback to store the panel and subpanel expansion settings in the list item that + * corresponds to this panel. + * + * \note This needs to iterate through all of the regions panels because the panel with changed + * expansion could have been the subpanel of a instanced panel, meaning it might not know + * which list item it corresponds to. + */ +static void set_panels_list_data_expand_flag(const bContext *C, ARegion *region) +{ + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + PanelType *panel_type = panel->type; + if (panel_type == NULL) { + continue; + } + + if (panel->type->flag & PNL_INSTANCED) { + short expand_flag = 0; /* Initialize to quite complaining compiler, value not used. */ + short flag_index = 0; + get_panel_expand_flag(panel, &expand_flag, &flag_index); + if (panel->type->set_list_data_expand_flag) { + panel->type->set_list_data_expand_flag(C, panel, expand_flag); + } + } + } +} + /****************************** panels ******************************/ -static void panels_collapse_all(ScrArea *area, ARegion *region, const Panel *from_panel) +static void panels_collapse_all(const bContext *C, + ScrArea *area, + ARegion *region, + const Panel *from_panel) { const bool has_category_tabs = UI_panel_category_is_visible(region); const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL; @@ -259,6 +592,15 @@ static void panels_collapse_all(ScrArea *area, ARegion *region, const Panel *fro } } } + set_panels_list_data_expand_flag(C, region); +} + +static bool panel_type_context_poll(PanelType *panel_type, const char *context) +{ + if (panel_type->context[0] && STREQ(panel_type->context, context)) { + return true; + } + return false; } Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt) @@ -568,7 +910,7 @@ static void ui_draw_aligned_panel_header( Panel *panel = block->panel; rcti hrect; int pnl_icons; - const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname; + const char *activename = panel->drawname; const bool is_subpanel = (panel->type && panel->type->parent); uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle; uchar col_title[4]; @@ -614,7 +956,6 @@ void ui_draw_aligned_panel(uiStyle *style, const bool show_background) { Panel *panel = block->panel; - rcti headrect; rctf itemrect; float color[4]; const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false; @@ -625,11 +966,19 @@ void ui_draw_aligned_panel(uiStyle *style, * can't be dragged. This may be changed in future. */ show_background); const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; + const bool draw_box_style = (panel->type && panel->type->flag & (PNL_DRAW_BOX)); + + /* Use the theme for box widgets for box-style panels. */ + uiWidgetColors *box_wcol = NULL; + if (draw_box_style) { + bTheme *btheme = UI_GetTheme(); + box_wcol = &btheme->tui.wcol_box; + } + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { if (show_background) { - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColor(panel_col); immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); @@ -638,25 +987,47 @@ void ui_draw_aligned_panel(uiStyle *style, return; } - /* calculate header rect */ - /* + 0.001f to prevent flicker due to float inaccuracy */ - headrect = *rect; - headrect.ymin = headrect.ymax; - headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f); + /* Calculate header rect with + 0.001f to prevent flicker due to float inaccuracy */ + rcti headrect = { + rect->xmin, rect->xmax, rect->ymax, rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f)}; - rcti titlerect = headrect; - if (is_subpanel) { - titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f; - } + /* Draw a panel and header backdrops with an opaque box backdrop for box style panels. */ + if (draw_box_style && !is_subpanel) { + /* Expand the top a tiny bit to give header buttons equal size above and below. */ + rcti box_rect = {rect->xmin, + rect->xmax, + (is_closed_x || is_closed_y) ? headrect.ymin : rect->ymin, + headrect.ymax + U.pixelsize}; + ui_draw_box_opaque(&box_rect, UI_CNR_ALL); - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* Mimick the border between aligned box widgets for the bottom of the header. */ + if (!(is_closed_x || is_closed_y)) { + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + GPU_blend(true); + + immUniformColor4ubv(box_wcol->outline); + immRectf(pos, rect->xmin, headrect.ymin - U.pixelsize, rect->xmax, headrect.ymin); + uchar emboss_col[4]; + UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col); + immUniformColor4ubv(emboss_col); + immRectf(pos, + rect->xmin, + headrect.ymin - U.pixelsize, + rect->xmax, + headrect.ymin - U.pixelsize - 1); + + GPU_blend(false); + immUnbindProgram(); + } + } - if (show_background && !is_subpanel) { + /* Draw the header backdrop. */ + if (show_background && !is_subpanel && !draw_box_style) { float minx = rect->xmin; float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax; float y = headrect.ymax; + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); GPU_blend(true); /* draw with background color */ @@ -674,12 +1045,10 @@ void ui_draw_aligned_panel(uiStyle *style, immEnd(); GPU_blend(false); + immUnbindProgram(); } - immUnbindProgram(); - - /* draw optional pin icon */ - +/* draw optional pin icon */ #ifdef USE_PIN_HIDDEN if (show_pin && (block->panel->flag & PNL_PIN)) #else @@ -702,6 +1071,10 @@ void ui_draw_aligned_panel(uiStyle *style, } /* horizontal title */ + rcti titlerect = headrect; + if (is_subpanel) { + titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f; + } if (is_closed_x == false) { ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background); @@ -730,9 +1103,7 @@ void ui_draw_aligned_panel(uiStyle *style, } } - /* if the panel is minimized vertically: - * (------) - */ + /* Draw panel backdrop. */ if (is_closed_y) { /* skip */ } @@ -745,11 +1116,18 @@ void ui_draw_aligned_panel(uiStyle *style, else { /* in some occasions, draw a border */ if (panel->flag & PNL_SELECT && !is_subpanel) { + float radius; if (panel->control & UI_PNL_SOLID) { UI_draw_roundbox_corner_set(UI_CNR_ALL); + radius = 8.0f; + } + else if (draw_box_style) { + UI_draw_roundbox_corner_set(UI_CNR_ALL); + radius = box_wcol->roundness * U.widget_unit; } else { UI_draw_roundbox_corner_set(UI_CNR_NONE); + radius = 0.0f; } UI_GetThemeColorShade4fv(TH_BACK, -120, color); @@ -758,18 +1136,40 @@ void ui_draw_aligned_panel(uiStyle *style, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, - 8, + radius, color); } immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - GPU_blend(true); - if (show_background) { - /* panel backdrop */ - immUniformThemeColor(panel_col); - immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + /* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier. + * Note: Sub-panels blend with panels, so they can't be opaque. */ + if (show_background && !(draw_box_style && !is_subpanel)) { + /* Draw the bottom subpanels . */ + if (draw_box_style) { + if (panel->next) { + immUniformThemeColor(panel_col); + immRectf( + pos, rect->xmin + U.pixelsize, rect->ymin, rect->xmax - U.pixelsize, rect->ymax); + } + else { + /* Change the width a little bit to line up with sides. */ + UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT); + UI_GetThemeColor4fv(panel_col, color); + UI_draw_roundbox_aa(true, + rect->xmin + U.pixelsize, + rect->ymin + U.pixelsize, + rect->xmax - U.pixelsize, + rect->ymax, + box_wcol->roundness * U.widget_unit, + color); + } + } + else { + immUniformThemeColor(panel_col); + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + } } if (panel->control & UI_PNL_SCALE) { @@ -887,10 +1287,6 @@ bool UI_panel_is_dragging(const struct Panel *panel) return data->is_drag_drop; } -typedef struct PanelSort { - Panel *panel, *orig; -} PanelSort; - /** * \note about sorting; * the sortorder has a lower value for new panels being added. @@ -1052,13 +1448,30 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co ps->panel->ofsx = 0; ps->panel->ofsy = -get_panel_size_y(ps->panel); ps->panel->ofsx += ps->panel->runtime.region_ofsx; + /* Extra margin if the panel is a box style panel. */ + if (ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX) { + ps->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; + ps->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; + } for (a = 0; a < tot - 1; a++, ps++) { psnext = ps + 1; if (align == BUT_VERTICAL) { + bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX; + bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX; psnext->panel->ofsx = ps->panel->ofsx; psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel); + /* Extra margin for box style panels. */ + if (use_box || use_box_next) { + psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; + } + if (use_box && !use_box_next) { + psnext->panel->ofsx -= UI_PANEL_BOX_STYLE_MARGIN; + } + else if (!use_box && use_box_next) { + psnext->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; + } } else { psnext->panel->ofsx = get_panel_real_ofsx(ps->panel); @@ -1137,7 +1550,7 @@ static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y) *r_y = sizey; } -static void ui_do_animate(const bContext *C, Panel *panel) +static void ui_do_animate(bContext *C, Panel *panel) { uiHandlePanelData *data = panel->activedata; ScrArea *area = CTX_wm_area(C); @@ -1156,7 +1569,15 @@ static void ui_do_animate(const bContext *C, Panel *panel) } if (fac >= 1.0f) { + /* Store before data is freed. */ + const bool is_drag_drop = data->is_drag_drop; + panel_activate_state(C, panel, PANEL_STATE_EXIT); + if (is_drag_drop) { + /* Note: doing this in #panel_activate_state would require removing const for context in many + * other places. */ + reorder_instanced_panel_list(C, region, panel); + } return; } } @@ -1322,8 +1743,8 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) return; } - dx = (event->x - data->startx) & ~(PNL_GRID - 1); - dy = (event->y - data->starty) & ~(PNL_GRID - 1); + dx = (event->x - data->startx); + dy = (event->y - data->starty); dx *= (float)BLI_rctf_size_x(®ion->v2d.cur) / (float)BLI_rcti_size_x(®ion->winrct); dy *= (float)BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->winrct); @@ -1460,6 +1881,8 @@ static void ui_panel_drag_collapse(bContext *C, } } } + /* Update the instanced panel data expand flags with the changes made here. */ + set_panels_list_data_expand_flag(C, region); } /** @@ -1588,7 +2011,7 @@ static void ui_handle_panel_header( if (ctrl) { /* Only collapse all for parent panels. */ if (block->panel->type != NULL && block->panel->type->parent == NULL) { - panels_collapse_all(area, region, block->panel); + panels_collapse_all(C, area, region, block->panel); /* reset the view - we don't want to display a view without content */ UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); @@ -1624,6 +2047,8 @@ static void ui_handle_panel_header( ui_panel_drag_collapse_handler_add(C, true); } } + + set_panels_list_data_expand_flag(C, region); } if (align) { diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c index 34ac58c1dca..1f8af7b9e6e 100644 --- a/source/blender/editors/interface/interface_region_hud.c +++ b/source/blender/editors/interface/interface_region_hud.c @@ -177,11 +177,13 @@ static void hud_region_layout(const bContext *C, ARegion *region) return; } + ScrArea *area = CTX_wm_area(C); int size_y = region->sizey; ED_region_panels_layout(C, region); - if (region->panels.first && (region->sizey != size_y)) { + if (region->panels.first && + ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y))) { int winx_new = UI_DPI_FAC * (region->sizex + 0.5f); int winy_new = UI_DPI_FAC * (region->sizey + 0.5f); View2D *v2d = ®ion->v2d; @@ -339,6 +341,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *area) } else { if (region->flag & RGN_FLAG_HIDDEN) { + /* Also forces recalculating HUD size in hud_region_layout(). */ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE; } region->flag &= ~RGN_FLAG_HIDDEN; diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c index 0a06f765c0e..2c6b09168f4 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -41,6 +41,7 @@ #include "BLI_math_matrix.h" #include "BLI_memarena.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -177,7 +178,19 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d struct MenuSearch_Context *wm_context) { struct MenuSearch_Item *item = NULL; + + /* Use override if the name is empty, this can happen with popovers. */ + const char *drawstr_override = NULL; + const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ? + strrchr(but->drawstr, UI_SEP_CHAR) : + NULL; + const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0'); + if (but->optype != NULL) { + if (drawstr_is_empty) { + drawstr_override = WM_operatortype_name(but->optype, but->opptr); + } + item = BLI_memarena_calloc(memarena, sizeof(*item)); item->type = MENU_SEARCH_TYPE_OP; @@ -189,6 +202,25 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d } else if (but->rnaprop != NULL) { const int prop_type = RNA_property_type(but->rnaprop); + + if (drawstr_is_empty) { + if (prop_type == PROP_ENUM) { + const int value_enum = (int)but->hardmax; + EnumPropertyItem enum_item; + if (RNA_property_enum_item_from_value_gettexted( + but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) { + drawstr_override = enum_item.name; + } + else { + /* Should never happen. */ + drawstr_override = "Unknown"; + } + } + else { + drawstr_override = RNA_property_ui_name(but->rnaprop); + } + } + if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) { /* Note that these buttons are not prevented, * but aren't typically used in menus. */ @@ -213,7 +245,16 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d if (item != NULL) { /* Handle shared settings. */ - item->drawstr = strdup_memarena(memarena, but->drawstr); + if (drawstr_override != NULL) { + const char *drawstr_suffix = drawstr_sep ? drawstr_sep : ""; + char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix); + item->drawstr = strdup_memarena(memarena, drawstr_alloc); + MEM_freeN(drawstr_alloc); + } + else { + item->drawstr = strdup_memarena(memarena, but->drawstr); + } + item->icon = ui_but_icon(but); item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 0e67f943ee6..9b59e4419c4 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1150,7 +1150,7 @@ static void template_ID_tabs(bContext *C, { const ARegion *region = CTX_wm_region(C); const PointerRNA active_ptr = RNA_property_pointer_get(&template->ptr, template->prop); - MenuType *mt = WM_menutype_find(menu, false); + MenuType *mt = menu ? WM_menutype_find(menu, false) : NULL; const int but_align = ui_but_align_opposite_to_area_align_get(region); const int but_height = UI_UNIT_Y * 1.1; @@ -1220,6 +1220,8 @@ static void ui_template_id(uiLayout *layout, const char *newop, const char *openop, const char *unlinkop, + /* Only respected by tabs (use_tabs). */ + const char *menu, const char *text, int flag, int prv_rows, @@ -1274,7 +1276,7 @@ static void ui_template_id(uiLayout *layout, if (template_ui->idlb) { if (use_tabs) { layout = uiLayoutRow(layout, true); - template_ID_tabs(C, layout, template_ui, type, flag, newop, unlinkop); + template_ID_tabs(C, layout, template_ui, type, flag, newop, menu); } else { layout = uiLayoutRow(layout, true); @@ -1313,6 +1315,7 @@ void uiTemplateID(uiLayout *layout, newop, openop, unlinkop, + NULL, text, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, 0, @@ -1341,6 +1344,7 @@ void uiTemplateIDBrowse(uiLayout *layout, newop, openop, unlinkop, + NULL, text, UI_ID_BROWSE | UI_ID_RENAME, 0, @@ -1372,6 +1376,7 @@ void uiTemplateIDPreview(uiLayout *layout, openop, unlinkop, NULL, + NULL, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, rows, cols, @@ -1399,6 +1404,7 @@ void uiTemplateGpencilColorPreview(uiLayout *layout, NULL, NULL, NULL, + NULL, UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE, rows, cols, @@ -1417,7 +1423,7 @@ void uiTemplateIDTabs(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *newop, - const char *unlinkop, + const char *menu, int filter) { ui_template_id(layout, @@ -1426,7 +1432,8 @@ void uiTemplateIDTabs(uiLayout *layout, propname, newop, NULL, - unlinkop, + NULL, + menu, NULL, UI_ID_BROWSE | UI_ID_RENAME, 0, diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 4706be205e1..0498b312618 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -4265,7 +4265,7 @@ static void widget_box( copy_v3_v3_uchar(old_col, wcol->inner); /* abuse but->hsv - if it's non-zero, use this color as the box's background */ - if (but->col[3]) { + if (but != NULL && but->col[3]) { wcol->inner[0] = but->col[0]; wcol->inner[1] = but->col[1]; wcol->inner[2] = but->col[2]; @@ -5021,6 +5021,30 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect) } /** + * Uses the widget base drawing and colors from from the box widget, but ensures an opaque + * inner color. + */ +void ui_draw_box_opaque(rcti *rect, int roundboxalign) +{ + uiWidgetType *wt = widget_type(UI_WTYPE_BOX); + + /* Alpha blend with the region's background color to force an opaque background. */ + uiWidgetColors *wcol = &wt->wcol; + wt->state(wt, 0, 0); + float background[4]; + UI_GetThemeColor4fv(TH_BACK, background); + float new_inner[4]; + rgba_uchar_to_float(new_inner, wcol->inner); + new_inner[0] = (new_inner[0] * new_inner[3]) + (background[0] * (1.0f - new_inner[3])); + new_inner[1] = (new_inner[1] * new_inner[3]) + (background[1] * (1.0f - new_inner[3])); + new_inner[2] = (new_inner[2] * new_inner[3]) + (background[2] * (1.0f - new_inner[3])); + new_inner[3] = 1.0f; + rgba_float_to_uchar(wcol->inner, new_inner); + + wt->custom(NULL, wcol, rect, 0, roundboxalign); +} + +/** * Similar to 'widget_menu_back', however we can't use the widget preset system * because we need to pass in the original location so we know where to show the arrow. */ diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c index 17a95ba3fff..36213f919a3 100644 --- a/source/blender/editors/interface/view2d_draw.c +++ b/source/blender/editors/interface/view2d_draw.c @@ -40,6 +40,7 @@ #include "GPU_immediate.h" #include "GPU_matrix.h" +#include "GPU_state.h" #include "WM_api.h" @@ -196,7 +197,19 @@ static void draw_parallel_lines(const ParallelLinesSet *lines, GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + if (U.pixelsize > 1.0f) { + float viewport[4]; + GPU_viewport_size_get_f(viewport); + + immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + immUniform2fv("viewportSize", &viewport[2]); + /* -1.0f offset here is because the line is too fat due to the builtin antialiasing. + * TODO make a variant or a uniform to toggle it off. */ + immUniform1f("lineWidth", U.pixelsize - 1.0f); + } + else { + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + } immUniformColor3ubv(color); immBegin(GPU_PRIM_LINES, steps * 2); diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 1484dcfa92d..3c426e5d2b1 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -59,6 +59,7 @@ static Object *make_prim_init(bContext *C, const char *idname, const float loc[3], const float rot[3], + const float scale[3], ushort local_view_bits, MakePrimitiveData *r_creation_data) { @@ -76,6 +77,13 @@ static Object *make_prim_init(bContext *C, ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); + if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) { + float scale_half[3]; + copy_v3_v3(scale_half, scale); + mul_v3_fl(scale_half, 0.5f); + rescale_m4(r_creation_data->mat, scale_half); + } + return obedit; } @@ -112,9 +120,16 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -164,15 +179,22 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), + loc, + rot, + scale, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -237,9 +259,16 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) cap_tri = (cap_end == 2); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); + em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -294,7 +323,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); @@ -303,11 +332,13 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, + scale, local_view_bits, &creation_data); em = BKE_editmesh_from_object(obedit); @@ -368,7 +399,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); @@ -377,9 +408,15 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), + loc, + rot, + scale, + local_view_bits, + &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -447,9 +484,15 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -514,10 +557,16 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL); + ED_object_add_generic_get_opts( + C, op, 'Y', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, local_view_bits, &creation_data); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), + loc, + rot, + NULL, + local_view_bits, + &creation_data); dia = RNA_float_get(op->ptr, "size") / 2.0f; mul_mat3_m4_fl(creation_data.mat, dia); @@ -567,15 +616,21 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); - obedit = make_prim_init( - C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, local_view_bits, &creation_data); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); + obedit = make_prim_init(C, + CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), + loc, + rot, + scale, + local_view_bits, + &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -629,17 +684,19 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3]; + float loc[3], rot[3], scale[3]; bool enter_editmode; ushort local_view_bits; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); - ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL); + ED_object_add_generic_get_opts( + C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, + scale, local_view_bits, &creation_data); em = BKE_editmesh_from_object(obedit); diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index eed2cbcce39..739bc5bdf7c 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -224,7 +224,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "add_solidify")) { ED_object_modifier_add( op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify); - SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findny_name( + SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findby_name( new_ob, "mask_extract_solidify"); if (sfmd) { sfmd->offset = -0.05f; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index a26003d78ed..b5346a9061a 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1647,14 +1647,13 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, void EDBM_project_snap_verts( bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em) { - Main *bmain = CTX_data_main(C); BMIter iter; BMVert *eve; ED_view3d_init_mats_rv3d(obedit, region->regiondata); struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - bmain, CTX_data_scene(C), 0, region, CTX_wm_view3d(C)); + CTX_data_scene(C), 0, region, CTX_wm_view3d(C)); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 74fba4d0cf9..8289f52b0c8 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -303,10 +303,15 @@ void ED_object_add_unit_props_size(wmOperatorType *ot) ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00); } -void ED_object_add_unit_props_radius(wmOperatorType *ot) +void ED_object_add_unit_props_radius_ex(wmOperatorType *ot, float default_value) { RNA_def_float_distance( - ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00); + ot->srna, "radius", default_value, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00); +} + +void ED_object_add_unit_props_radius(wmOperatorType *ot) +{ + ED_object_add_unit_props_radius_ex(ot, 1.0f); } void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) @@ -345,6 +350,18 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) DEG2RADF(-360.0f), DEG2RADF(360.0f)); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_float_vector_xyz(ot->srna, + "scale", + 3, + NULL, + -OBJECT_ADD_SIZE_MAXF, + OBJECT_ADD_SIZE_MAXF, + "Scale", + "Scale for the newly added object", + -1000.0f, + 1000.0f); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } void ED_object_add_mesh_props(wmOperatorType *ot) @@ -357,6 +374,7 @@ bool ED_object_add_generic_get_opts(bContext *C, const char view_align_axis, float loc[3], float rot[3], + float scale[3], bool *enter_editmode, ushort *local_view_bits, bool *is_view_aligned) @@ -465,6 +483,26 @@ bool ED_object_add_generic_get_opts(bContext *C, } } + /* Scale! */ + { + float _scale[3]; + if (!scale) { + scale = _scale; + } + + /* For now this is optional, we can make it always use. */ + copy_v3_fl(scale, 1.0f); + if ((prop = RNA_struct_find_property(op->ptr, "scale"))) { + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_get_array(op->ptr, prop, scale); + } + else { + copy_v3_fl(scale, 1.0f); + RNA_property_float_set_array(op->ptr, prop, scale); + } + } + } + return true; } @@ -530,7 +568,7 @@ static int object_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } radius = RNA_float_get(op->ptr, "radius"); @@ -604,7 +642,7 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } type = RNA_enum_get(op->ptr, "type"); @@ -663,7 +701,7 @@ static int effector_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } type = RNA_enum_get(op->ptr, "type"); @@ -741,7 +779,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) RNA_enum_set(op->ptr, "align", ALIGN_VIEW); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, local_view_bits); @@ -802,7 +840,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if (obedit == NULL || obedit->type != OB_MBALL) { @@ -814,7 +852,10 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) } ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); - dia = RNA_float_get(op->ptr, "radius"); + /* Halving here is done to account for constant values from #BKE_mball_element_add. + * While the default radius of the resulting meta element is 2, + * we want to pass in 1 so other values such as resolution are scaled by 1.0. */ + dia = RNA_float_get(op->ptr, "radius") / 2; ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type")); @@ -845,7 +886,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", ""); - ED_object_add_unit_props_radius(ot); + ED_object_add_unit_props_radius_ex(ot, 2.0f); ED_object_add_generic_props(ot, true); } @@ -864,7 +905,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if (obedit && obedit->type == OB_FONT) { @@ -916,7 +957,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts( - C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { + C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) { @@ -979,7 +1020,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, local_view_bits); @@ -1039,7 +1080,8 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv ushort local_view_bits; float rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts( + C, op, 'Z', NULL, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, local_view_bits); @@ -1126,7 +1168,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) /* Note: We use 'Y' here (not 'Z'), as */ WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } /* add new object if not currently editing a GP object, @@ -1256,7 +1298,7 @@ static int object_light_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; WM_operator_view3d_unit_defaults(C, op); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits); @@ -1341,7 +1383,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op) collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")); } - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } if (collection) { @@ -1414,7 +1456,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; Scene *scene = CTX_data_scene(C); - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits); @@ -1471,7 +1513,7 @@ static int object_hair_add_exec(bContext *C, wmOperator *op) ushort local_view_bits; float loc[3], rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } Object *object = ED_object_add_type(C, OB_HAIR, NULL, loc, rot, false, local_view_bits); @@ -1508,7 +1550,7 @@ static int object_pointcloud_add_exec(bContext *C, wmOperator *op) ushort local_view_bits; float loc[3], rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return OPERATOR_CANCELLED; } Object *object = ED_object_add_type(C, OB_POINTCLOUD, NULL, loc, rot, false, local_view_bits); @@ -2857,6 +2899,7 @@ static int add_named_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index c31de7f371c..e84dbca2469 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -96,6 +96,7 @@ typedef struct BakeAPIRender { bool is_cage; float cage_extrusion; + float max_ray_distance; int normal_space; eBakeNormalSwizzle normal_swizzle[3]; @@ -737,6 +738,7 @@ static int bake(Render *re, const bool is_selected_to_active, const bool is_cage, const float cage_extrusion, + const float max_ray_distance, const int normal_space, const eBakeNormalSwizzle normal_swizzle[], const char *custom_cage, @@ -1010,6 +1012,7 @@ static int bake(Render *re, num_pixels, ob_cage != NULL, cage_extrusion, + max_ray_distance, ob_low_eval->obmat, (ob_cage ? ob_cage->obmat : ob_low_eval->obmat), me_cage)) { @@ -1305,6 +1308,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active"); bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage"); bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion"); + bkr->max_ray_distance = RNA_float_get(op->ptr, "max_ray_distance"); bkr->normal_space = RNA_enum_get(op->ptr, "normal_space"); bkr->normal_swizzle[0] = RNA_enum_get(op->ptr, "normal_r"); @@ -1394,6 +1398,7 @@ static int bake_exec(bContext *C, wmOperator *op) true, bkr.is_cage, bkr.cage_extrusion, + bkr.max_ray_distance, bkr.normal_space, bkr.normal_swizzle, bkr.custom_cage, @@ -1426,6 +1431,7 @@ static int bake_exec(bContext *C, wmOperator *op) false, bkr.is_cage, bkr.cage_extrusion, + bkr.max_ray_distance, bkr.normal_space, bkr.normal_swizzle, bkr.custom_cage, @@ -1495,6 +1501,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa true, bkr->is_cage, bkr->cage_extrusion, + bkr->max_ray_distance, bkr->normal_space, bkr->normal_swizzle, bkr->custom_cage, @@ -1527,6 +1534,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa false, bkr->is_cage, bkr->cage_extrusion, + bkr->max_ray_distance, bkr->normal_space, bkr->normal_swizzle, bkr->custom_cage, @@ -1586,6 +1594,11 @@ static void bake_set_props(wmOperator *op, Scene *scene) RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0); } + prop = RNA_struct_find_property(op->ptr, "max_ray_distance"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set(op->ptr, prop, bake->max_ray_distance); + } + prop = RNA_struct_find_property(op->ptr, "cage_extrusion"); if (!RNA_property_is_set(op->ptr, prop)) { RNA_property_float_set(op->ptr, prop, bake->cage_extrusion); @@ -1766,12 +1779,23 @@ void OBJECT_OT_bake(wmOperatorType *ot) "Selected to Active", "Bake shading on the surface of selected objects to the active object"); RNA_def_float(ot->srna, + "max_ray_distance", + 0.0f, + 0.0f, + FLT_MAX, + "Max Ray Distance", + "The maximum ray distance for matching points between the active and selected " + "objects. If zero, there is no limit", + 0.0f, + 1.0f); + RNA_def_float(ot->srna, "cage_extrusion", 0.0f, 0.0f, FLT_MAX, "Cage Extrusion", - "Distance to use for the inward ray cast when using selected to active", + "Inflate the active object by the specified distance for baking. This helps " + "matching to points nearer to the outside of the selected object meshes", 0.0f, 1.0f); RNA_def_string(ot->srna, diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 690c63a2cbf..53a557c5871 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1466,6 +1466,13 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C, return item; } +static bool object_mode_set_poll(bContext *C) +{ + /* Needed as #ED_operator_object_active_editable doesn't call use 'active_object'. */ + Object *ob = CTX_data_active_object(C); + return ED_operator_object_active_editable_ex(C, ob); +} + static int object_mode_set_exec(bContext *C, wmOperator *op) { bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode"); @@ -1551,7 +1558,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) /* api callbacks */ ot->exec = object_mode_set_exec; - ot->poll = ED_operator_object_active_editable; + ot->poll = object_mode_set_poll; /* flags */ ot->flag = 0; /* no register/undo here, leave it to operators being called */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 5cb4714dabf..9398a5f2ce7 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -805,7 +805,7 @@ bool ED_object_modifier_apply(Main *bmain, /* Get evaluated modifier, so object links pointer to evaluated data, * but still use original object it is applied to the original mesh. */ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findny_name(ob_eval, md->name) : md; + ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md; /* allow apply of a not-realtime modifier, by first re-enabling realtime. */ prev_mode = md_eval->mode; @@ -1020,7 +1020,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) ModifierData *md; RNA_string_get(op->ptr, "modifier", modifier_name); - md = BKE_modifiers_findny_name(ob, modifier_name); + md = BKE_modifiers_findby_name(ob, modifier_name); if (md && type != 0 && md->type != type) { md = NULL; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index bfceaef4644..11e9c396552 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2072,7 +2072,7 @@ void ED_object_single_users(Main *bmain, /* Duplicating obdata and other IDs may require another update of the collections and objects * pointers, especially regarding drivers and custom props, see T66641. - * Note that this whole scene duplication code and 'make single user' functions have te be + * Note that this whole scene duplication code and 'make single user' functions have to be * rewritten at some point to make use of proper modern ID management code, * but that is no small task. * For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */ diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c index 3c1f7da2bd6..4cdbbea492b 100644 --- a/source/blender/editors/object/object_volume.c +++ b/source/blender/editors/object/object_volume.c @@ -59,7 +59,7 @@ static Object *object_volume_add(bContext *C, wmOperator *op, const char *name) ushort local_view_bits; float loc[3], rot[3]; - if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) { + if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) { return false; } return ED_object_add_type(C, OB_VOLUME, name, loc, rot, false, local_view_bits); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 6cafc51231c..306adb36c52 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -5127,7 +5127,7 @@ void PE_create_particle_edit( int totpoint; if (psmd != NULL) { - psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findny_name(ob_eval, + psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(ob_eval, psmd->modifier.name); } @@ -5251,9 +5251,6 @@ static bool particle_edit_toggle_poll(bContext *C) if (!ob->data || ID_IS_LINKED(ob->data)) { return 0; } - if (CTX_data_edit_object(C)) { - return 0; - } return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) || BKE_modifiers_findby_type(ob, eModifierType_Softbody)); @@ -5301,7 +5298,7 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) * with possible changes applied when object was outside of the * edit mode. */ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findny_name( + edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name( object_eval, edit->psmd->modifier.name); recalc_emitter_field(depsgraph, ob, edit->psys); } diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index ceaac201da3..8524870c15e 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -52,6 +52,7 @@ #include "DEG_depsgraph.h" +#include "ED_object.h" #include "ED_screen.h" #include "PIL_time.h" @@ -154,7 +155,7 @@ static bool fluid_initjob( { FluidModifierData *mmd = NULL; FluidDomainSettings *mds; - Object *ob = CTX_data_active_object(C); + Object *ob = ED_object_active_context(C); mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); if (!mmd) { @@ -170,7 +171,7 @@ static bool fluid_initjob( job->bmain = CTX_data_main(C); job->scene = CTX_data_scene(C); job->depsgraph = CTX_data_depsgraph_pointer(C); - job->ob = CTX_data_active_object(C); + job->ob = ob; job->mmd = mmd; job->type = op->type->idname; job->name = op->type->name; @@ -616,7 +617,7 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op) { FluidModifierData *mmd = NULL; FluidDomainSettings *mds; - Object *ob = CTX_data_active_object(C); + Object *ob = ED_object_active_context(C); Scene *scene = CTX_data_scene(C); /* @@ -679,7 +680,7 @@ static int fluid_pause_exec(struct bContext *C, struct wmOperator *op) { FluidModifierData *mmd = NULL; FluidDomainSettings *mds; - Object *ob = CTX_data_active_object(C); + Object *ob = ED_object_active_context(C); /* * Get modifier data diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 17049fdb28b..1db7bf5a766 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -349,7 +349,6 @@ static int screen_render_exec(bContext *C, wmOperator *op) RE_SetReports(re, op->reports); - BLI_threaded_malloc_begin(); if (is_animation) { RE_RenderAnim(re, mainp, @@ -363,7 +362,6 @@ static int screen_render_exec(bContext *C, wmOperator *op) else { RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); } - BLI_threaded_malloc_end(); RE_SetReports(re, NULL); @@ -391,16 +389,14 @@ static void make_renderinfo_string(const RenderStats *rs, char *str) { char info_time_str[32]; // used to be extern to header_info.c - uintptr_t mem_in_use, mmap_in_use, peak_memory; - float megs_used_memory, mmap_used_memory, megs_peak_memory; + uintptr_t mem_in_use, peak_memory; + float megs_used_memory, megs_peak_memory; char *spos = str; mem_in_use = MEM_get_memory_in_use(); - mmap_in_use = MEM_get_mapped_memory_in_use(); peak_memory = MEM_get_peak_memory(); - megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0); - mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0); + megs_used_memory = (mem_in_use) / (1024.0 * 1024.0); megs_peak_memory = (peak_memory) / (1024.0 * 1024.0); /* local view */ @@ -441,7 +437,7 @@ static void make_renderinfo_string(const RenderStats *rs, } } else { - if (rs->totvert || rs->totface || rs->tothalo || rs->totstrand || rs->totlamp) { + if (rs->totvert || rs->totface || rs->totlamp) { spos += sprintf(spos, "| "); } @@ -451,38 +447,16 @@ static void make_renderinfo_string(const RenderStats *rs, if (rs->totface) { spos += sprintf(spos, TIP_("Fa:%d "), rs->totface); } - if (rs->tothalo) { - spos += sprintf(spos, TIP_("Ha:%d "), rs->tothalo); - } - if (rs->totstrand) { - spos += sprintf(spos, TIP_("St:%d "), rs->totstrand); - } if (rs->totlamp) { spos += sprintf(spos, TIP_("Li:%d "), rs->totlamp); } if (rs->mem_peak == 0.0f) { - spos += sprintf(spos, - TIP_("| Mem:%.2fM (%.2fM, Peak %.2fM) "), - megs_used_memory, - mmap_used_memory, - megs_peak_memory); + spos += sprintf(spos, TIP_("| Mem:%.2fM (Peak %.2fM) "), megs_used_memory, megs_peak_memory); } else { spos += sprintf(spos, TIP_("| Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak); } - - if (rs->curfield) { - spos += sprintf(spos, TIP_("Field %d "), rs->curfield); - } - if (rs->curblur) { - spos += sprintf(spos, TIP_("Blur %d "), rs->curblur); - } - } - - /* full sample */ - if (rs->curfsa) { - spos += sprintf(spos, TIP_("| Full Sample %d "), rs->curfsa); } /* extra info */ diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index f2e8209b099..2861e851282 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -494,7 +494,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) scene, oglrender->sizex, oglrender->sizey, - 100.0f, + 100, false, &context); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 48b54ddcea3..c04122edd36 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2345,6 +2345,15 @@ BLI_INLINE bool streq_array_any(const char *s, const char *arr[]) return false; } +/** + * Builds the panel layout for the input \a panel or type \a pt. + * + * \param panel The panel to draw. Can be null, in which case a panel with the type of \a pt will + * be created. + * \param unique_panel_str A unique identifier for the name of the \a uiBlock associated with the + * panel. Used when the panel is an instanced panel so a unique identifier is needed to find the + * correct old \a uiBlock, and NULL otherwise. + */ static void ed_panel_draw(const bContext *C, ScrArea *area, ARegion *region, @@ -2353,18 +2362,27 @@ static void ed_panel_draw(const bContext *C, Panel *panel, int w, int em, - bool vertical) + bool vertical, + char *unique_panel_str) { const uiStyle *style = UI_style_get_dpi(); - /* draw panel */ - uiBlock *block = UI_block_begin(C, region, pt->idname, UI_EMBOSS); + /* Draw panel. */ + + char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN]; + strncpy(block_name, pt->idname, BKE_ST_MAXNAME); + if (unique_panel_str != NULL) { + /* Instanced panels should have already been added at this point. */ + strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN); + } + uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS); bool open; panel = UI_panel_begin(area, region, lb, block, pt, panel, &open); /* bad fixed values */ int xco, yco, h = 0; + int headerend = w - UI_UNIT_X; if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { /* for preset menu */ @@ -2380,8 +2398,6 @@ static void ed_panel_draw(const bContext *C, pt->draw_header_preset(C, panel); - int headerend = w - UI_UNIT_X; - UI_block_layout_resolve(block, &xco, &yco); UI_block_translate(block, headerend - xco, 0); panel->layout = NULL; @@ -2391,9 +2407,24 @@ static void ed_panel_draw(const bContext *C, int labelx, labely; UI_panel_label_offset(block, &labelx, &labely); - /* for enabled buttons */ - panel->layout = UI_block_layout( - block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style); + /* Unusual case: Use expanding layout (buttons stretch to available width). */ + if (pt->flag & PNL_LAYOUT_HEADER_EXPAND) { + uiLayout *layout = UI_block_layout(block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + labelx, + labely, + headerend - 2 * style->panelspace, + 1, + 0, + style); + panel->layout = uiLayoutRow(layout, false); + } + /* Regular case: Normal panel with fixed size buttons. */ + else { + panel->layout = UI_block_layout( + block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style); + } pt->draw_header(C, panel); @@ -2449,7 +2480,16 @@ static void ed_panel_draw(const bContext *C, Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt); if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) { - ed_panel_draw(C, area, region, &panel->children, child_pt, child_panel, w, em, vertical); + ed_panel_draw(C, + area, + region, + &panel->children, + child_pt, + child_panel, + w, + em, + vertical, + unique_panel_str); } } } @@ -2571,6 +2611,7 @@ void ED_region_panels_layout_ex(const bContext *C, } w -= margin_x; + int w_box_panel = w - UI_PANEL_BOX_STYLE_MARGIN * 2.0f; /* create panels */ UI_panels_begin(C, region); @@ -2578,8 +2619,14 @@ void ED_region_panels_layout_ex(const bContext *C, /* set view2d view matrix - UI_block_begin() stores it */ UI_view2d_view_ortho(v2d); + bool has_instanced_panel = false; for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) { PanelType *pt = pt_link->link; + + if (pt->flag & PNL_INSTANCED) { + has_instanced_panel = true; + continue; + } Panel *panel = UI_panel_find_by_type(®ion->panels, pt); if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) { @@ -2593,7 +2640,46 @@ void ED_region_panels_layout_ex(const bContext *C, update_tot_size = false; } - ed_panel_draw(C, area, region, ®ion->panels, pt, panel, w, em, vertical); + ed_panel_draw(C, + area, + region, + ®ion->panels, + pt, + panel, + (pt->flag & PNL_DRAW_BOX) ? w_box_panel : w, + em, + vertical, + NULL); + } + + /* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */ + if (has_instanced_panel) { + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + if (panel->type == NULL) { + continue; /* Some panels don't have a type.. */ + } + if (panel->type->flag & PNL_INSTANCED) { + if (panel && UI_panel_is_dragging(panel)) { + /* Prevent View2d.tot rectangle size changes while dragging panels. */ + update_tot_size = false; + } + + /* Use a unique identifier for instanced panels, otherwise an old block for a different + * panel of the same type might be found. */ + char unique_panel_str[8]; + UI_list_panel_unique_str(panel, unique_panel_str); + ed_panel_draw(C, + area, + region, + ®ion->panels, + panel->type, + panel, + (panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w, + em, + vertical, + unique_panel_str); + } + } } /* align panels and return size */ diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index b383930ddda..3202dc68f37 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -118,8 +118,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult ScrArea *area = CTX_wm_area(C); Scene *scene = WM_window_get_active_scene(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); - Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL; - Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL; + Object *obact = view_layer->basact ? view_layer->basact->object : NULL; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); if (CTX_data_dir(member)) { CTX_data_dir_set(result, screen_context_dir); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 00afbf452dd..6f004238522 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -305,30 +305,28 @@ int area_getorientation(ScrArea *area, ScrArea *sb) ScrVert *sbTR = sb->v3; ScrVert *sbBR = sb->v4; - int tolerance = U.pixelsize * 4; - if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* area to right of sb = W */ - if ((abs(saBL->vec.y - sbBR->vec.y) <= tolerance) && - (abs(saTL->vec.y - sbTR->vec.y) <= tolerance)) { + if ((abs(saBL->vec.y - sbBR->vec.y) <= AREAJOINTOLERANCE) && + (abs(saTL->vec.y - sbTR->vec.y) <= AREAJOINTOLERANCE)) { return 0; } } else if (saTL->vec.y == sbBL->vec.y && saTR->vec.y == sbBR->vec.y) { /* area to bottom of sb = N */ - if ((abs(saTL->vec.x - sbBL->vec.x) <= tolerance) && - (abs(saTR->vec.x - sbBR->vec.x) <= tolerance)) { + if ((abs(saTL->vec.x - sbBL->vec.x) <= AREAJOINTOLERANCE) && + (abs(saTR->vec.x - sbBR->vec.x) <= AREAJOINTOLERANCE)) { return 1; } } else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* area to left of sb = E */ - if ((abs(saTR->vec.y - sbTL->vec.y) <= tolerance) && - (abs(saBR->vec.y - sbBL->vec.y) <= tolerance)) { + if ((abs(saTR->vec.y - sbTL->vec.y) <= AREAJOINTOLERANCE) && + (abs(saBR->vec.y - sbBL->vec.y) <= AREAJOINTOLERANCE)) { return 2; } } else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* area on top of sb = S*/ - if ((abs(saBL->vec.x - sbTL->vec.x) <= tolerance) && - (abs(saBR->vec.x - sbTR->vec.x) <= tolerance)) { + if ((abs(saBL->vec.x - sbTL->vec.x) <= AREAJOINTOLERANCE) && + (abs(saBR->vec.x - sbTR->vec.x) <= AREAJOINTOLERANCE)) { return 3; } } @@ -336,6 +334,69 @@ int area_getorientation(ScrArea *area, ScrArea *sb) return -1; } +/* Screen verts with horizontal position equal to from_x are moved to to_x. */ +static void screen_verts_halign(const wmWindow *win, + const bScreen *screen, + const short from_x, + const short to_x) +{ + ED_screen_verts_iter(win, screen, v1) + { + if (v1->vec.x == from_x) { + v1->vec.x = to_x; + } + } +} + +/* Screen verts with vertical position equal to from_y are moved to to_y. */ +static void screen_verts_valign(const wmWindow *win, + const bScreen *screen, + const short from_y, + const short to_y) +{ + ED_screen_verts_iter(win, screen, v1) + { + if (v1->vec.y == from_y) { + v1->vec.y = to_y; + } + } +} + +/* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation(). + */ +static void screen_areas_align( + bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir) +{ + wmWindow *win = CTX_wm_window(C); + + if (dir == 0 || dir == 2) { + /* horizontal join, use average for new top and bottom. */ + int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2; + int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2; + + /* Move edges exactly matching source top and bottom. */ + screen_verts_valign(win, screen, sa1->v2->vec.y, top); + screen_verts_valign(win, screen, sa1->v4->vec.y, bottom); + + /* Move edges exactly matching target top and bottom. */ + screen_verts_valign(win, screen, sa2->v2->vec.y, top); + screen_verts_valign(win, screen, sa2->v4->vec.y, bottom); + } + else { + /* Vertical join, use averages for new left and right. */ + int left = (sa1->v1->vec.x + sa2->v1->vec.x) / 2; + int right = (sa1->v3->vec.x + sa2->v3->vec.x) / 2; + + /* Move edges exactly matching source left and right. */ + screen_verts_halign(win, screen, sa1->v1->vec.x, left); + screen_verts_halign(win, screen, sa1->v3->vec.x, right); + + /* Move edges exactly matching target left and right */ + screen_verts_halign(win, screen, sa2->v1->vec.x, left); + screen_verts_halign(win, screen, sa2->v3->vec.x, right); + } +} + /* Helper function to join 2 areas, it has a return value, 0=failed 1=success * used by the split, join operators */ @@ -348,21 +409,7 @@ int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2) } /* Align areas if they are not. Do sanity checking before getting here. */ - - if (dir == 0 || dir == 2) { - /* horizontal join, so vertically align source vert to target */ - sa2->v1->vec.y = sa1->v1->vec.y; /* vertical align sa1 BL */ - sa2->v2->vec.y = sa1->v2->vec.y; /* vertical align sa1 TL */ - sa2->v3->vec.y = sa1->v3->vec.y; /* vertical align sa1 TR */ - sa2->v4->vec.y = sa1->v4->vec.y; /* vertical align sa1 BR */ - } - else { - /* vertical join, so horizontally align source verts to target */ - sa2->v1->vec.x = sa1->v1->vec.x; /* vertical align sa1 BL */ - sa2->v2->vec.x = sa1->v2->vec.x; /* vertical align sa1 TL */ - sa2->v3->vec.x = sa1->v3->vec.x; /* vertical align sa1 TR */ - sa2->v4->vec.x = sa1->v4->vec.x; /* vertical align sa1 BR */ - } + screen_areas_align(C, screen, sa1, sa2, dir); if (dir == 0) { /* sa1 to right of sa2 = W */ sa1->v1 = sa2->v1; /* BL */ @@ -690,8 +737,10 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2]) ARegion *region_prev = screen->active_region; ED_screen_areas_iter (win, screen, area_iter) { - if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) { - if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) { + if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) && + xy[0] < (area_iter->totrct.xmax - BORDERPADDING)) { + if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) && + xy[1] < (area_iter->totrct.ymax - BORDERPADDING)) { if (ED_area_azones_update(area_iter, xy) == NULL) { area = area_iter; break; diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c index 4069795657e..47580c2f4b3 100644 --- a/source/blender/editors/screen/screen_geometry.c +++ b/source/blender/editors/screen/screen_geometry.c @@ -92,7 +92,7 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map, const int mx, const int my) { - int safety = U.widget_unit / 10; + int safety = BORDERPADDING; CLAMP_MIN(safety, 2); diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index 3dfc147bc73..2d42313d528 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -35,6 +35,11 @@ struct bContextDataResult; #define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */ #define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */ +#define AREAJOINTOLERANCE (1.0f * U.widget_unit) /* Edges must be close to allow joining. */ + +/* Expanded interaction influence of area borders. */ +#define BORDERPADDING (U.dpi_fac + U.pixelsize) + /* area.c */ void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free); void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 5b808206935..f2bfcb7a395 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -339,7 +339,7 @@ bool ED_operator_console_active(bContext *C) return ed_spacetype_test(C, SPACE_CONSOLE); } -static bool ed_object_hidden(Object *ob) +static bool ed_object_hidden(const Object *ob) { /* if hidden but in edit mode, we still display, can happen with animation */ return ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT)); @@ -351,10 +351,15 @@ bool ED_operator_object_active(bContext *C) return ((ob != NULL) && !ed_object_hidden(ob)); } +bool ED_operator_object_active_editable_ex(bContext *UNUSED(C), const Object *ob) +{ + return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob)); +} + bool ED_operator_object_active_editable(bContext *C) { Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob)); + return ED_operator_object_active_editable_ex(C, ob); } bool ED_operator_object_active_editable_mesh(bContext *C) @@ -4861,8 +4866,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot) /** \name Show User Preferences Operator * \{ */ -static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int userpref_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC; int sizey = 520 * UI_DPI_FAC; @@ -4899,7 +4907,7 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_userpref_show"; /* api callbacks */ - ot->invoke = userpref_show_invoke; + ot->exec = userpref_show_exec; ot->poll = ED_operator_screenactive; } @@ -4909,8 +4917,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) /** \name Show Drivers Editor Operator * \{ */ -static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int drivers_editor_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; PointerRNA ptr = {NULL}; PropertyRNA *prop = NULL; int index = -1; @@ -4974,7 +4985,7 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_drivers_editor_show"; /* api callbacks */ - ot->invoke = drivers_editor_show_invoke; + ot->exec = drivers_editor_show_exec; ot->poll = ED_operator_screenactive; } @@ -4984,8 +4995,11 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot) /** \name Show Info Log Operator * \{ */ -static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int info_log_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; int sizex = 900 * UI_DPI_FAC; int sizey = 580 * UI_DPI_FAC; int shift_y = 480; @@ -5015,7 +5029,7 @@ static void SCREEN_OT_info_log_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_info_log_show"; /* api callbacks */ - ot->invoke = info_log_show_invoke; + ot->exec = info_log_show_exec; ot->poll = ED_operator_screenactive; } diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 8feef0c675a..3edc51b038b 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -109,9 +109,9 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain, layout_new = win->workspace_hook->temp_layout_store; } else { - layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new); + layout_new = BKE_workspace_active_layout_for_workspace_get(win->workspace_hook, workspace_new); if (!layout_new) { - layout_new = BKE_workspace_layouts_get(workspace_new)->first; + layout_new = workspace_new->layouts.first; } } screen_new = BKE_workspace_layout_screen_get(layout_new); @@ -163,7 +163,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager return false; } - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace_new, layout_new); + BKE_workspace_active_layout_set(win->workspace_hook, workspace_new, layout_new); BKE_workspace_active_set(win->workspace_hook, workspace_new); /* update screen *after* changing workspace - which also causes the @@ -188,7 +188,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win) { WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook); - ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old); WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2); workspace_new->flags = workspace_old->flags; @@ -198,7 +197,7 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo /* TODO(campbell): tools */ - LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, layouts_old) { + LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, &workspace_old->layouts) { WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate( bmain, workspace_new, layout_old, win); diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c index cf9637788a9..7ce92bc3e4d 100644 --- a/source/blender/editors/screen/workspace_layout_edit.c +++ b/source/blender/editors/screen/workspace_layout_edit.c @@ -140,7 +140,7 @@ bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_ol const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old); WorkSpaceLayout *layout_new; - BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1); + BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1); /* don't allow deleting temp fullscreens for now */ if (BKE_screen_is_fullscreen_area(screen_old)) { diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index e227db1c644..fd5018f76ff 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -1130,9 +1130,6 @@ static bool texture_paint_toggle_poll(bContext *C) if (!ob->data || ID_IS_LINKED(ob->data)) { return 0; } - if (CTX_data_edit_object(C)) { - return 0; - } return 1; } diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index d607b6a9d6f..0f54d5e0821 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -731,7 +731,14 @@ static bool brush_generic_tool_set(bContext *C, WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); /* Tool System - * This is needed for when there is a non-sculpt tool active (transform for e.g.) */ + * This is needed for when there is a non-sculpt tool active (transform for e.g.). + * In case we are toggling (and the brush changed to the toggle_brush), we need to get the + * tool_name again. */ + int tool_result = brush_tool(brush, paint->runtime.tool_offset); + ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); + const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); + RNA_enum_name_from_value(items, tool_result, &tool_name); + char tool_id[MAX_NAME]; SNPRINTF(tool_id, "builtin_brush.%s", tool_name); WM_toolsystem_ref_set_by_id(C, tool_id); @@ -1140,24 +1147,24 @@ static int stencil_fit_image_aspect_exec(bContext *C, wmOperator *op) aspy *= tex->yrepeat; } - orig_area = aspx * aspy; + orig_area = fabsf(aspx * aspy); if (do_mask) { - stencil_area = br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1]; + stencil_area = fabsf(br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1]); } else { - stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1]; + stencil_area = fabsf(br->stencil_dimension[0] * br->stencil_dimension[1]); } factor = sqrtf(stencil_area / orig_area); if (do_mask) { - br->mask_stencil_dimension[0] = factor * aspx; - br->mask_stencil_dimension[1] = factor * aspy; + br->mask_stencil_dimension[0] = fabsf(factor * aspx); + br->mask_stencil_dimension[1] = fabsf(factor * aspy); } else { - br->stencil_dimension[0] = factor * aspx; - br->stencil_dimension[1] = factor * aspy; + br->stencil_dimension[0] = fabsf(factor * aspx); + br->stencil_dimension[1] = fabsf(factor * aspy); } } diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 458c24e5194..723ac58bc6e 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -230,8 +230,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode) SCULPT_TOOL_THUMB)) { return false; } - else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH && - brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { + else if (SCULPT_is_cloth_deform_brush(brush)) { return false; } else { diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index a18a0145faa..6172b77de07 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2694,19 +2694,19 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) /* Implementation notes: * * Operator->invoke() - * - validate context (add mcol) - * - create customdata storage - * - call paint once (mouse click) - * - add modal handler + * - Validate context (add #Mesh.mloopcol). + * - Create custom-data storage. + * - Call paint once (mouse click). + * - Add modal handler. * * Operator->modal() - * - for every mousemove, apply vertex paint - * - exit on mouse release, free customdata + * - For every mouse-move, apply vertex paint. + * - Exit on mouse release, free custom-data. * (return OPERATOR_FINISHED also removes handler and operator) * * For future: - * - implement a stroke event (or mousemove with past positions) - * - revise whether op->customdata should be added in object, in set_vpaint + * - implement a stroke event (or mouse-move with past positions). + * - revise whether op->customdata should be added in object, in set_vpaint. */ struct VPaintData { @@ -2718,8 +2718,10 @@ struct VPaintData { struct VertProjHandle *vp_handle; struct CoNo *vertexcosnos; - /* modify 'me->mcol' directly, since the derived mesh is drawing from this - * array, otherwise we need to refresh the modifier stack */ + /** + * Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this + * array, otherwise we need to refresh the modifier stack. + */ bool use_fast_update; /* loops tagged as having been painted, to apply shared vertex color diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 045fd54b46a..4ad6bcc5d0f 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -156,9 +156,16 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index) void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) { switch (BKE_pbvh_type(ss->pbvh)) { - case PBVH_FACES: - normal_short_to_float_v3(no, ss->mvert[index].no); - return; + case PBVH_FACES: { + if (ss->shapekey_active || ss->deform_modifiers_active) { + const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); + normal_short_to_float_v3(no, mverts[index].no); + } + else { + normal_short_to_float_v3(no, ss->mvert[index].no); + } + break; + } case PBVH_BMESH: copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no); break; @@ -851,7 +858,7 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood) SCULPT_vertex_random_access_init(ss); flood->queue = BLI_gsqueue_new(sizeof(int)); - flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices"); + flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices"); } void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index) @@ -919,8 +926,8 @@ void SCULPT_floodfill_execute( SculptVertexNeighborIter ni; SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { const int to_v = ni.index; - if (flood->visited_vertices[to_v] == 0 && SCULPT_vertex_visible_get(ss, to_v)) { - flood->visited_vertices[to_v] = 1; + if (!BLI_BITMAP_TEST(flood->visited_vertices, to_v) && SCULPT_vertex_visible_get(ss, to_v)) { + BLI_BITMAP_ENABLE(flood->visited_vertices, to_v); if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { BLI_gsqueue_push(flood->queue, &to_v); @@ -2084,9 +2091,13 @@ static float brush_strength(const Sculpt *sd, case SCULPT_TOOL_LAYER: return alpha * flip * pressure * overlap * feather; case SCULPT_TOOL_CLOTH: - /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over - * the same vertices. */ - if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) { + if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { + /* Grab deform uses the same falloff as a regular grab brush. */ + return root_alpha * feather; + } + else if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) { + /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over + * the same vertices. */ return 0.1f * alpha * flip * pressure * overlap * feather; } else { @@ -6208,6 +6219,34 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo } } +/* In these brushes the grab delta is calculated always from the initial stroke location, which is + * generally used to create grab deformations. */ +static bool sculpt_needs_delta_from_anchored_origin(Brush *brush) +{ + return ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_POSE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_ELASTIC_DEFORM) || + SCULPT_is_cloth_deform_brush(brush); +} + +/* In these brushes the grab delta is calculated from the previous stroke location, which is used + * to calculate to orientate the brush tip and deformation towards the stroke direction. */ +static bool sculpt_needs_delta_for_tip_orientation(Brush *brush) +{ + if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { + return !SCULPT_is_cloth_deform_brush(brush); + } + return ELEM(brush->sculpt_tool, + SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_PINCH, + SCULPT_TOOL_MULTIPLANE_SCRAPE, + SCULPT_TOOL_CLAY_THUMB, + SCULPT_TOOL_NUDGE, + SCULPT_TOOL_SNAKE_HOOK); +} + static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush) { SculptSession *ss = ob->sculpt; @@ -6251,38 +6290,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru /* Compute delta to move verts by. */ if (!cache->first_time) { - switch (tool) { - case SCULPT_TOOL_GRAB: - case SCULPT_TOOL_POSE: - case SCULPT_TOOL_THUMB: - case SCULPT_TOOL_ELASTIC_DEFORM: - sub_v3_v3v3(delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ob->obmat); - mul_mat3_m4_v3(imat, delta); - add_v3_v3(cache->grab_delta, delta); - break; - case SCULPT_TOOL_CLAY_STRIPS: - case SCULPT_TOOL_PINCH: - case SCULPT_TOOL_CLOTH: - case SCULPT_TOOL_MULTIPLANE_SCRAPE: - case SCULPT_TOOL_CLAY_THUMB: - case SCULPT_TOOL_NUDGE: - case SCULPT_TOOL_SNAKE_HOOK: - if (brush->flag & BRUSH_ANCHORED) { - float orig[3]; - mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); - sub_v3_v3v3(cache->grab_delta, grab_location, orig); - } - else { - sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - } - invert_m4_m4(imat, ob->obmat); - mul_mat3_m4_v3(imat, cache->grab_delta); - break; - default: - /* Use for 'Brush.topology_rake_factor'. */ + if (sculpt_needs_delta_from_anchored_origin(brush)) { + sub_v3_v3v3(delta, grab_location, cache->old_grab_location); + invert_m4_m4(imat, ob->obmat); + mul_mat3_m4_v3(imat, delta); + add_v3_v3(cache->grab_delta, delta); + } + else if (sculpt_needs_delta_for_tip_orientation(brush)) { + if (brush->flag & BRUSH_ANCHORED) { + float orig[3]; + mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); + sub_v3_v3v3(cache->grab_delta, grab_location, orig); + } + else { sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - break; + } + invert_m4_m4(imat, ob->obmat); + mul_mat3_m4_v3(imat, cache->grab_delta); + } + else { + /* Use for 'Brush.topology_rake_factor'. */ + sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); } } else { @@ -6303,18 +6331,14 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru copy_v3_v3(cache->anchored_location, cache->true_location); } } - else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) { + else if (tool == SCULPT_TOOL_ELASTIC_DEFORM || SCULPT_is_cloth_deform_brush(brush)) { copy_v3_v3(cache->anchored_location, cache->true_location); } else if (tool == SCULPT_TOOL_THUMB) { copy_v3_v3(cache->anchored_location, cache->orig_grab_location); } - if (ELEM(tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_ELASTIC_DEFORM, - SCULPT_TOOL_POSE)) { + if (sculpt_needs_delta_from_anchored_origin(brush)) { /* Location stays the same for finding vertices in brush radius. */ copy_v3_v3(cache->true_location, cache->orig_grab_location); @@ -6385,9 +6409,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po if (cache->first_time || !((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) || - (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || - (brush->sculpt_tool == SCULPT_TOOL_CLOTH && - brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) { + (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || SCULPT_is_cloth_deform_brush(brush))) { RNA_float_get_array(ptr, "location", cache->true_location); } @@ -7389,7 +7411,7 @@ static bool sculpt_no_multires_poll(bContext *C) return false; } -static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) +static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -7440,7 +7462,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) MirrorModifierData mmd = {{0}}; int axis = 0; mmd.flag = 0; - mmd.tolerance = 0.005f; + mmd.tolerance = RNA_float_get(op->ptr, "merge_tolerance"); switch (sd->symmetrize_direction) { case BMO_SYMMETRIZE_NEGATIVE_X: axis = 0; @@ -7497,6 +7519,16 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot) /* API callbacks. */ ot->exec = sculpt_symmetrize_exec; ot->poll = sculpt_no_multires_poll; + + RNA_def_float(ot->srna, + "merge_tolerance", + 0.001f, + 0.0f, + FLT_MAX, + "Merge Limit", + "Distance within which symmetrical vertices are merged", + 0.0f, + 1.0f); } /**** Toggle operator for turning sculpt mode on or off ****/ @@ -7803,8 +7835,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float float brush_co[3]; copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss)); - char *visited_vertices = MEM_callocN(SCULPT_vertex_count_get(ss) * sizeof(char), - "visited vertices"); + BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; @@ -7828,8 +7859,8 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float totpoints++; ss->preview_vert_index_list[totpoints] = to_v; totpoints++; - if (visited_vertices[to_v] == 0) { - visited_vertices[to_v] = 1; + if (!BLI_BITMAP_TEST(visited_vertices, to_v)) { + BLI_BITMAP_ENABLE(visited_vertices, to_v); const float *co = SCULPT_vertex_co_get(ss, to_v); if (len_squared_v3v3(brush_co, co) < radius * radius) { BLI_gsqueue_push(not_visited_vertices, &to_v); diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 62a7f1925ab..6dac2b51645 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -212,8 +212,9 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, const float *grab_delta = data->grab_delta; float(*imat)[4] = data->mat; - const bool use_falloff_plane = brush->cloth_force_falloff_type == - BRUSH_CLOTH_FORCE_FALLOFF_PLANE; + const bool use_falloff_plane = !SCULPT_is_cloth_deform_brush(brush) && + brush->cloth_force_falloff_type == + BRUSH_CLOTH_FORCE_FALLOFF_PLANE; PBVHVertexIter vd; const float bstrength = ss->cache->bstrength; @@ -246,14 +247,29 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, gravity, ss->cache->gravity_direction, -ss->cache->radius * data->sd->gravity_factor); } + /* Original data for deform brushes. */ + SculptOrigVertData orig_data; + if (SCULPT_is_cloth_deform_brush(brush)) { + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + } + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float force[3]; const float sim_factor = cloth_brush_simulation_falloff_get( brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]); + float current_vertex_location[3]; + if (SCULPT_is_cloth_deform_brush(brush)) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + copy_v3_v3(current_vertex_location, orig_data.co); + } + else { + copy_v3_v3(current_vertex_location, vd.co); + } + /* When using the plane falloff mode the falloff is not constrained by the brush radius. */ - if (sculpt_brush_test_sq_fn(&test, vd.co) || use_falloff_plane) { + if (sculpt_brush_test_sq_fn(&test, current_vertex_location) || use_falloff_plane) { float dist = sqrtf(test.dist); @@ -264,7 +280,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, const float fade = sim_factor * bstrength * SCULPT_brush_strength_factor(ss, brush, - vd.co, + current_vertex_location, dist, vd.no, vd.fno, @@ -293,7 +309,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(force, offset, -fade); break; case BRUSH_CLOTH_DEFORM_GRAB: - mul_v3_v3fl(force, grab_delta, fade); + /* Grab writes the positions in the simulation directly without applying forces. */ + madd_v3_v3v3fl( + cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade); + zero_v3(force); break; case BRUSH_CLOTH_DEFORM_PINCH_POINT: if (use_falloff_plane) { diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index f96f08e3244..cbdbab14690 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -297,6 +297,25 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (mode == SCULPT_FACE_SET_VISIBLE) { + + /* If all vertices in the sculpt are visible, create the new face set and update the default + * color. This way the new face set will be white, which is a quick way of disabling all face + * sets and the performance hit of rendering the overlay. */ + bool all_visible = true; + for (int i = 0; i < tot_vert; i++) { + if (!SCULPT_vertex_visible_get(ss, i)) { + all_visible = false; + break; + } + } + + if (all_visible) { + Mesh *mesh = ob->data; + mesh->face_sets_color_default = next_face_set; + BKE_pbvh_face_sets_color_set( + ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); + } + for (int i = 0; i < tot_vert; i++) { if (SCULPT_vertex_visible_get(ss, i)) { SCULPT_vertex_face_set_set(ss, i, next_face_set); @@ -504,7 +523,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, .calc_face_normal = true, })); - bool *visited_faces = MEM_callocN(sizeof(bool) * mesh->totpoly, "visited faces"); + BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces"); const int totfaces = mesh->totpoly; int *face_sets = ss->face_sets; @@ -515,12 +534,12 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, int next_face_set = 1; for (int i = 0; i < totfaces; i++) { - if (!visited_faces[i]) { + if (!BLI_BITMAP_TEST(visited_faces, i)) { GSQueue *queue; queue = BLI_gsqueue_new(sizeof(int)); face_sets[i] = next_face_set; - visited_faces[i] = true; + BLI_BITMAP_ENABLE(visited_faces, i); BLI_gsqueue_push(queue, &i); while (!BLI_gsqueue_is_empty(queue)) { @@ -537,10 +556,10 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) { if (f_neighbor != f) { int neighbor_face_index = BM_elem_index_get(f_neighbor); - if (!visited_faces[neighbor_face_index]) { + if (!BLI_BITMAP_TEST(visited_faces, neighbor_face_index)) { if (test(bm, f, ed, f_neighbor, threshold)) { face_sets[neighbor_face_index] = next_face_set; - visited_faces[neighbor_face_index] = true; + BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index); BLI_gsqueue_push(queue, &neighbor_face_index); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 9b13f6e6c24..6c217f66940 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -120,7 +120,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ neighbor_iterator.i++) { \ - neighbor_iterator.index = ni.neighbors[ni.i]; + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; /* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come * first since they are nearest for floodfill. */ @@ -128,8 +128,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss, SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ neighbor_iterator.i--) { \ - neighbor_iterator.index = ni.neighbors[ni.i]; \ - neighbor_iterator.is_duplicate = (ni.i >= \ + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \ neighbor_iterator.size - neighbor_iterator.num_duplicates); #define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \ @@ -233,7 +233,7 @@ void SCULPT_flip_quat_by_symm_area(float quat[3], /* Flood Fill. */ typedef struct { GSQueue *queue; - char *visited_vertices; + BLI_bitmap *visited_vertices; } SculptFloodFill; void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood); @@ -333,6 +333,13 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, struct SculptSession *ss, const float outline_col[3], float outline_alpha); + +BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) +{ + return brush->sculpt_tool == SCULPT_TOOL_CLOTH && + brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB; +} + /* Pose Brush. */ void SCULPT_do_pose_brush(struct Sculpt *sd, struct Object *ob, diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index c7511dfc80f..35f4870fa12 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -131,6 +131,32 @@ static void pose_solve_roll_chain(SculptPoseIKChain *ik_chain, } } +static void pose_solve_translate_chain(SculptPoseIKChain *ik_chain, const float delta[3]) +{ + SculptPoseIKChainSegment *segments = ik_chain->segments; + const int tot_segments = ik_chain->tot_segments; + + for (int i = 0; i < tot_segments; i++) { + /* Move the origin and head of each segment by delta. */ + add_v3_v3v3(segments[i].head, segments[i].initial_head, delta); + add_v3_v3v3(segments[i].orig, segments[i].initial_orig, delta); + + /* Reset the segment rotation. */ + unit_qt(segments[i].rot); + } +} + +static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale) +{ + SculptPoseIKChainSegment *segments = ik_chain->segments; + const int tot_segments = ik_chain->tot_segments; + + for (int i = 0; i < tot_segments; i++) { + /* Assign the scale to each segment. */ + segments[i].scale = scale; + } +} + static void do_pose_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) @@ -363,10 +389,14 @@ typedef struct PoseFloodFillData { GSet *visited_face_sets; /* In face sets origin mode, each vertex can only be assigned to one face set. */ - bool *is_weighted; + BLI_bitmap *is_weighted; bool is_first_iteration; + /* In topology mode this stores the furthest point from the stroke origin for cases when a pose + * origin based on the brush radius can't be set. */ + float fallback_floodfill_origin[3]; + /* Fallback origin. If we can't find any face set to continue, use the position of all vertices * that have the current face set. */ float fallback_origin[3]; @@ -377,12 +407,17 @@ static bool pose_topology_floodfill_cb( SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; + const float *co = SCULPT_vertex_co_get(ss, to_v); if (data->pose_factor) { data->pose_factor[to_v] = 1.0f; } - const float *co = SCULPT_vertex_co_get(ss, to_v); + if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) < + len_squared_v3v3(data->pose_initial_co, co)) { + copy_v3_v3(data->fallback_floodfill_origin, co); + } + if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { return true; @@ -415,7 +450,7 @@ static bool pose_face_sets_floodfill_cb( if (data->current_face_set == SCULPT_FACE_SET_NONE) { data->pose_factor[index] = 1.0f; - data->is_weighted[index] = true; + BLI_BITMAP_ENABLE(data->is_weighted, index); if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { @@ -446,9 +481,9 @@ static bool pose_face_sets_floodfill_cb( if (is_vertex_valid) { - if (!data->is_weighted[index]) { + if (!BLI_BITMAP_TEST(data->is_weighted, index)) { data->pose_factor[index] = 1.0f; - data->is_weighted[index] = true; + BLI_BITMAP_ENABLE(data->is_weighted, index); visit_next = true; } @@ -521,12 +556,16 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd, }; zero_v3(fdata.pose_origin); copy_v3_v3(fdata.pose_initial_co, initial_location); + copy_v3_v3(fdata.fallback_floodfill_origin, initial_location); SCULPT_floodfill_execute(ss, &flood, pose_topology_floodfill_cb, &fdata); SCULPT_floodfill_free(&flood); if (fdata.tot_co > 0) { mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co); } + else { + copy_v3_v3(fdata.pose_origin, fdata.fallback_floodfill_origin); + } /* Offset the pose origin. */ float pose_d[3]; @@ -600,9 +639,21 @@ static void pose_ik_chain_origin_heads_init(SculptPoseIKChain *ik_chain, copy_v3_v3(ik_chain->segments[i].initial_orig, origin); copy_v3_v3(ik_chain->segments[i].initial_head, head); ik_chain->segments[i].len = len_v3v3(head, origin); + ik_chain->segments[i].scale = 1.0f; } } +static int pose_brush_num_effective_segments(const Brush *brush) +{ + /* Scaling multiple segments at the same time is not supported as the IK solver can't handle + * changes in the segment's length. It will also required a better weight distribution to avoid + * artifacts in the areas affected by multiple segments. */ + if (brush->pose_deform_type == BRUSH_POSE_DEFORM_SCALE_TRASLATE) { + return 1; + } + return brush->pose_ik_segments; +} + static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, Object *ob, SculptSession *ss, @@ -629,7 +680,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd, pose_factor_grow[nearest_vertex_index] = 1.0f; - SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert); + const int tot_segments = pose_brush_num_effective_segments(br); + SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert); /* Calculate the first segment in the chain using the brush radius and the pose origin offset. */ copy_v3_v3(next_chain_segment_target, initial_location); @@ -688,11 +740,13 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets( int totvert = SCULPT_vertex_count_get(ss); - SculptPoseIKChain *ik_chain = pose_ik_chain_new(br->pose_ik_segments, totvert); + const int tot_segments = pose_brush_num_effective_segments(br); + + SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert); GSet *visited_face_sets = BLI_gset_int_new_ex("visited_face_sets", ik_chain->tot_segments); - bool *is_weighted = MEM_callocN(sizeof(bool) * totvert, "weighted"); + BLI_bitmap *is_weighted = BLI_BITMAP_NEW(totvert, "weighted"); int current_face_set = SCULPT_FACE_SET_NONE; int prev_face_set = SCULPT_FACE_SET_NONE; @@ -802,13 +856,86 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br MEM_SAFE_FREE(nodes); } +static void sculpt_pose_do_translate_deform(SculptSession *ss, Brush *brush) +{ + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + BKE_curvemapping_initialize(brush->curve); + pose_solve_translate_chain(ik_chain, ss->cache->grab_delta); +} + +static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush) +{ + float ik_target[3]; + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + copy_v3_v3(ik_target, ss->cache->true_location); + add_v3_v3(ik_target, ss->cache->grab_delta); + + /* Solve the IK for the first segment to include rotation as part of scale. */ + pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); + + /* Calculate a scale factor based on the grab delta. */ + float plane[4]; + float segment_dir[3]; + sub_v3_v3v3(segment_dir, ik_chain->segments[0].initial_head, ik_chain->segments[0].initial_orig); + normalize_v3(segment_dir); + plane_from_point_normal_v3(plane, ik_chain->segments[0].initial_head, segment_dir); + const float segment_len = ik_chain->segments[0].len; + const float scale = segment_len / (segment_len - dist_signed_to_plane_v3(ik_target, plane)); + + /* Write the scale into the segments. */ + pose_solve_scale_chain(ik_chain, scale); +} + +static void sculpt_pose_do_twist_deform(SculptSession *ss, Brush *brush) +{ + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + /* Calculate the maximum roll. 0.02 radians per pixel works fine. */ + float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * 0.02f; + BKE_curvemapping_initialize(brush->curve); + pose_solve_roll_chain(ik_chain, brush, roll); +} + +static void sculpt_pose_do_rotate_deform(SculptSession *ss, Brush *brush) +{ + float ik_target[3]; + SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + + /* Calculate the IK target. */ + copy_v3_v3(ik_target, ss->cache->true_location); + add_v3_v3(ik_target, ss->cache->grab_delta); + + /* Solve the IK positions. */ + pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); +} + +static void sculpt_pose_do_rotate_twist_deform(SculptSession *ss, Brush *brush) +{ + if (ss->cache->invert) { + sculpt_pose_do_twist_deform(ss, brush); + } + else { + sculpt_pose_do_rotate_deform(ss, brush); + } +} + +static void sculpt_pose_do_scale_translate_deform(SculptSession *ss, Brush *brush) +{ + if (ss->cache->invert) { + sculpt_pose_do_translate_deform(ss, brush); + } + else { + sculpt_pose_do_scale_deform(ss, brush); + } +} + /* Main Brush Function. */ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); float grab_delta[3]; - float ik_target[3]; const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; /* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be @@ -818,26 +945,15 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain; + copy_v3_v3(grab_delta, ss->cache->grab_delta); - /* Solve the positions and rotations of the IK chain. */ - if (ss->cache->invert) { - /* Roll Mode. */ - /* Calculate the maximum roll. 0.02 radians per pixel works fine. */ - float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * - 0.02f; - BKE_curvemapping_initialize(brush->curve); - pose_solve_roll_chain(ik_chain, brush, roll); - } - else { - /* IK follow target mode. */ - /* Calculate the IK target. */ - - copy_v3_v3(grab_delta, ss->cache->grab_delta); - copy_v3_v3(ik_target, ss->cache->true_location); - add_v3_v3(ik_target, ss->cache->grab_delta); - - /* Solve the IK positions. */ - pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED); + switch (brush->pose_deform_type) { + case BRUSH_POSE_DEFORM_ROTATE_TWIST: + sculpt_pose_do_rotate_twist_deform(ss, brush); + break; + case BRUSH_POSE_DEFORM_SCALE_TRASLATE: + sculpt_pose_do_scale_translate_deform(ss, brush); + break; } /* Flip the segment chain in all symmetry axis and calculate the transform matrices for each @@ -845,7 +961,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* This can be optimized by skipping the calculation of matrices where the symmetry is not * enabled. */ for (int symm_it = 0; symm_it < PAINT_SYMM_AREAS; symm_it++) { - for (int i = 0; i < brush->pose_ik_segments; i++) { + for (int i = 0; i < ik_chain->tot_segments; i++) { float symm_rot[4]; float symm_orig[3]; float symm_initial_orig[3]; @@ -865,6 +981,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* Create the transform matrix and store it in the segment. */ unit_m4(ik_chain->segments[i].pivot_mat[symm_it]); quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot); + mul_m4_fl(ik_chain->segments[i].trans_mat[symm_it], ik_chain->segments[i].scale); translate_m4(ik_chain->segments[i].trans_mat[symm_it], symm_orig[0] - symm_initial_orig[0], diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 912a6e1aaf6..d21552efafe 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -847,6 +847,7 @@ static void sculpt_undo_free_list(ListBase *lb) sculpt_undo_geometry_free_data(&unode->geometry_original); sculpt_undo_geometry_free_data(&unode->geometry_modified); + sculpt_undo_geometry_free_data(&unode->geometry_bmesh_enter); if (unode->face_sets) { MEM_freeN(unode->face_sets); @@ -913,7 +914,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL); - unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden"); + unode->grid_hidden = MEM_callocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden"); for (i = 0; i < totgrid; i++) { if (grid_hidden[grid_indices[i]]) { @@ -974,13 +975,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt maxgrid = 0; } - /* We will use this while sculpting, is mapalloc slow to access then? */ - /* General TODO, fix count_alloc. */ switch (type) { case SCULPT_UNDO_COORDS: - unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co"); - unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no"); + unode->co = MEM_callocN(sizeof(float[3]) * allvert, "SculptUndoNode.co"); + unode->no = MEM_callocN(sizeof(short[3]) * allvert, "SculptUndoNode.no"); usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert; break; @@ -994,7 +993,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt break; case SCULPT_UNDO_MASK: - unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask"); + unode->mask = MEM_callocN(sizeof(float) * allvert, "SculptUndoNode.mask"); usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert; @@ -1013,12 +1012,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt unode->maxgrid = maxgrid; unode->totgrid = totgrid; unode->gridsize = gridsize; - unode->grids = MEM_mapallocN(sizeof(int) * totgrid, "SculptUndoNode.grids"); + unode->grids = MEM_callocN(sizeof(int) * totgrid, "SculptUndoNode.grids"); } else { /* Regular mesh. */ unode->maxvert = ss->totvert; - unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index"); + unode->index = MEM_callocN(sizeof(int) * allvert, "SculptUndoNode.index"); } if (ss->deform_modifiers_active) { @@ -1571,7 +1570,7 @@ static void sculpt_undo_push_all_grids(Object *object) /* It is possible that undo push is done from an object state where there is no PBVH. This * happens, for example, when an operation which tagged for geometry update was performed prior - * to the current operation without making any stroke inbetween. + * to the current operation without making any stroke in between. * * Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure * PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index a1094dde749..d6b259c9ac0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -548,8 +548,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm if (do_island_optimization) { UvElement *element; UvNearestHit hit = UV_NEAREST_HIT_INIT; - Image *ima = CTX_data_edit_image(C); - uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit); + uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit); element = BM_uv_element_get(data->elementMap, hit.efa, hit.l); island_index = element->island; diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 7c2e055b1fb..9b752fbebe9 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -143,6 +143,7 @@ void ED_spacetypes_init(void) ED_gizmotypes_blank_3d(); ED_gizmotypes_cage_2d(); ED_gizmotypes_cage_3d(); + ED_gizmotypes_snap_3d(); /* register types for operators and gizmos */ spacetypes = BKE_spacetypes_list(); diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 6b7f86a9143..5bf431be9f8 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -373,7 +373,7 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg) /* set user as active */ if (user->node) { - ED_node_set_active(CTX_data_main(C), user->ntree, user->node); + ED_node_set_active(CTX_data_main(C), user->ntree, user->node, NULL); ct->texture = NULL; } else { diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 6c56e8dfb79..805e9608fec 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -91,7 +91,6 @@ void console_scrollback_prompt_end(SpaceConsole *sc, ConsoleLine *cl_dummy) static int console_textview_begin(TextViewContext *tvc) { SpaceConsole *sc = (SpaceConsole *)tvc->arg1; - tvc->lheight = sc->lheight * UI_DPI_FAC; tvc->sel_start = sc->sel_start; tvc->sel_end = sc->sel_end; @@ -143,10 +142,7 @@ static void console_cursor_wrap_offset( return; } -static void console_textview_draw_cursor(TextViewContext *tvc, - int cwidth, - int columns, - int descender) +static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int columns) { int pen[2]; { @@ -157,10 +153,10 @@ static void console_textview_draw_cursor(TextViewContext *tvc, console_cursor_wrap_offset(sc->prompt, columns, &offl, &offc, NULL); console_cursor_wrap_offset(cl->line, columns, &offl, &offc, cl->line + cl->cursor); pen[0] = cwidth * offc; - pen[1] = -2 - (tvc->lheight + descender) * offl; + pen[1] = -tvc->lheight * offl; console_cursor_wrap_offset(cl->line + cl->cursor, columns, &offl, &offc, NULL); - pen[1] += (tvc->lheight + descender) * offl; + pen[1] += tvc->lheight * offl; pen[0] += tvc->draw_rect.xmin; pen[1] += tvc->draw_rect.ymin; @@ -172,8 +168,7 @@ static void console_textview_draw_cursor(TextViewContext *tvc, immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColor(TH_CONSOLE_CURSOR); - immRectf( - pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight + descender); + immRectf(pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight); immUnbindProgram(); } @@ -229,7 +224,7 @@ static int console_textview_main__internal(SpaceConsole *sc, /* view */ tvc.sel_start = sc->sel_start; tvc.sel_end = sc->sel_end; - tvc.lheight = sc->lheight * 1.2f * UI_DPI_FAC; + tvc.lheight = sc->lheight * UI_DPI_FAC; tvc.scroll_ymin = v2d->cur.ymin; tvc.scroll_ymax = v2d->cur.ymax; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 226e7ae6b22..8d14664c0fa 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -220,7 +220,8 @@ static void file_draw_preview(uiBlock *block, const bool is_icon, const int typeflags, const bool drag, - const bool dimmed) + const bool dimmed, + const bool is_link) { uiBut *but; float fx, fy; @@ -312,37 +313,57 @@ static void file_draw_preview(uiBlock *block, GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - if (icon && !(typeflags & FILE_TYPE_FTFONT)) { - /* size of center icon is scaled to fit container and UI scale */ + if (icon && is_icon) { + /* Small icon in the middle of large image, scaled to fit container and UI scale */ float icon_x, icon_y; - - if (is_icon) { - const float icon_size = 16.0f / icon_aspect * U.dpi_fac; - float icon_opacity = 0.3f; - uchar icon_color[4] = {0, 0, 0, 255}; - float bgcolor[4]; - UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor); - if (rgb_to_grayscale(bgcolor) < 0.5f) { - icon_color[0] = 255; - icon_color[1] = 255; - icon_color[2] = 255; - } - icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); - icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); - UI_icon_draw_ex( - icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + const float icon_size = 16.0f / icon_aspect * U.dpi_fac; + float icon_opacity = 0.3f; + uchar icon_color[4] = {0, 0, 0, 255}; + float bgcolor[4]; + UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor); + if (rgb_to_grayscale(bgcolor) < 0.5f) { + icon_color[0] = 255; + icon_color[1] = 255; + icon_color[2] = 255; } - else { + icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); + icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); + UI_icon_draw_ex( + icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + } + + if (is_link) { + /* Arrow icon to indicate it is a shortcut, link, or alias. */ + float icon_x, icon_y; + icon_x = xco + (2.0f * UI_DPI_FAC); + icon_y = yco + (2.0f * UI_DPI_FAC); + const int arrow = ICON_LOOP_FORWARDS; + if (!is_icon) { + /* Arrow at very bottom-left if preview style. */ const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; - - /* Smaller, fainter icon for preview image thumbnail. */ - icon_x = xco + (2.0f * UI_DPI_FAC); - icon_y = yco + (2.0f * UI_DPI_FAC); - - UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); + UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); } + else { + /* Link to folder or non-previewed file. */ + uchar icon_color[4]; + UI_GetThemeColor4ubv(TH_BACK, icon_color); + icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; + icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; + UI_icon_draw_ex( + icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); + } + } + else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) { + /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */ + float icon_x, icon_y; + const uchar dark[4] = {0, 0, 0, 255}; + const uchar light[4] = {255, 255, 255, 255}; + icon_x = xco + (2.0f * UI_DPI_FAC); + icon_y = yco + (2.0f * UI_DPI_FAC); + UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); + UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); } /* Contrasting outline around some preview types. */ @@ -788,6 +809,7 @@ void file_draw_list(const bContext *C, ARegion *region) /* don't drag parent or refresh items */ do_drag = !(FILENAME_IS_CURRPAR(file->relpath)); const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN); + const bool is_link = (file->attributes & FILE_ATTR_ANY_LINK); if (FILE_IMGDISPLAY == params->display) { const int icon = filelist_geticon(files, i, false); @@ -809,7 +831,8 @@ void file_draw_list(const bContext *C, ARegion *region) is_icon, file->typeflag, do_drag, - is_hidden); + is_hidden, + is_link); } else { file_draw_icon(block, diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index a5263378850..41d32fda088 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1469,9 +1469,12 @@ void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, ch for (i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { FileDirEntry *file = filelist_file(sfile->files, i); - RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", file->relpath); - num_files++; + /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */ + if (!file->redirection_path) { + RNA_property_collection_add(op->ptr, prop, &itemptr); + RNA_string_set(&itemptr, "name", file->relpath); + num_files++; + } } } /* make sure the file specified in the filename button is added even if no @@ -1617,9 +1620,23 @@ static int file_exec(bContext *C, wmOperator *exec_op) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); + struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); char filepath[FILE_MAX]; + if (file && file->redirection_path) { + /* redirection_path is an absolute path that takes precedence + * over using sfile->params->dir + sfile->params->file. */ + BLI_split_dirfile(file->redirection_path, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + /* Update relpath with redirected filename as well so that the alternative + * combination of sfile->params->dir + relpath remains valid as well. */ + MEM_freeN(file->relpath); + file->relpath = BLI_strdup(sfile->params->file); + } + /* directory change */ if (file && (file->typeflag & FILE_TYPE_DIR)) { if (!file->relpath) { @@ -1634,9 +1651,6 @@ static int file_exec(bContext *C, wmOperator *exec_op) BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); BLI_path_slash_ensure(sfile->params->dir); } - if (file->redirection_path) { - STRNCPY(sfile->params->dir, file->redirection_path); - } ED_file_change_dir(C); } /* opening file - sends events now, so things get handled on windowqueue level */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 7f6d0658ec8..d8d7ef01a2e 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1015,6 +1015,7 @@ static int filelist_geticon_ex(FileDirEntry *file, /* If this path is in System list or path cache then use that icon. */ struct FSMenu *fsmenu = ED_fsmenu_get(); FSMenuCategory categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_OTHER, }; @@ -1022,10 +1023,16 @@ static int filelist_geticon_ex(FileDirEntry *file, for (int i = 0; i < ARRAY_SIZE(categories); i++) { FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]); char fullpath[FILE_MAX_LIBEXTRA]; - BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); - BLI_path_slash_ensure(fullpath); + char *target = fullpath; + if (file->redirection_path) { + target = file->redirection_path; + } + else { + BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); + BLI_path_slash_ensure(fullpath); + } for (; tfsm; tfsm = tfsm->next) { - if (STREQ(tfsm->path, fullpath)) { + if (STREQ(tfsm->path, target)) { /* Never want a little folder inside a large one. */ return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon; } @@ -1033,10 +1040,7 @@ static int filelist_geticon_ex(FileDirEntry *file, } } - if (file->attributes & FILE_ATTR_ANY_LINK) { - return ICON_LOOP_FORWARDS; - } - else if (file->attributes & FILE_ATTR_OFFLINE) { + if (file->attributes & FILE_ATTR_OFFLINE) { return ICON_ERROR; } else if (file->attributes & FILE_ATTR_TEMPORARY) { @@ -1375,8 +1379,15 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); - BLI_join_dirfile( - preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + + if (entry->redirection_path) { + BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); + } + else { + BLI_join_dirfile( + preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + } + preview->index = index; preview->flags = entry->typeflag; preview->img = NULL; @@ -2270,13 +2281,6 @@ int ED_path_extension_type(const char *path) return 0; } -static int file_extension_type(const char *dir, const char *relpath) -{ - char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), dir, relpath); - return ED_path_extension_type(path); -} - int ED_file_extension_icon(const char *path) { const int type = ED_path_extension_type(path); @@ -2475,7 +2479,8 @@ static int filelist_readjob_list_dir(const char *root, { struct direntry *files; int nbr_files, nbr_entries = 0; - char path[FILE_MAX]; + /* Full path of the item. */ + char full_path[FILE_MAX]; nbr_files = BLI_filelist_dir_contents(root, &files); if (files) { @@ -2491,38 +2496,53 @@ static int filelist_readjob_list_dir(const char *root, entry->relpath = MEM_dupallocN(files[i].relname); entry->st = files[i].s; - BLI_join_dirfile(path, sizeof(path), root, entry->relpath); + BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath); + char *target = full_path; - /* Set file type. */ + /* Set initial file type and attributes. */ + entry->attributes = BLI_file_attributes(full_path); if (S_ISDIR(files[i].s.st_mode)) { entry->typeflag = FILE_TYPE_DIR; } - else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { - /* If we are considering .blend files as libs, promote them to directory status. */ - entry->typeflag = FILE_TYPE_BLENDER; - /* prevent current file being used as acceptable dir */ - if (BLI_path_cmp(main_name, path) != 0) { - entry->typeflag |= FILE_TYPE_DIR; - } - } - /* Otherwise, do not check extensions for directories! */ - else if (!(entry->typeflag & FILE_TYPE_DIR)) { - entry->typeflag = file_extension_type(root, entry->relpath); - if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) { - entry->typeflag |= FILE_TYPE_OPERATOR; - } - } - /* Set file attributes. */ - entry->attributes = BLI_file_attributes(path); + /* Is this a file that points to another file? */ if (entry->attributes & FILE_ATTR_ALIAS) { entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__); - if (BLI_file_alias_target(entry->redirection_path, path)) { + if (BLI_file_alias_target(entry->redirection_path, full_path)) { if (BLI_is_dir(entry->redirection_path)) { entry->typeflag = FILE_TYPE_DIR; + BLI_path_slash_ensure(entry->redirection_path); } - else + else { entry->typeflag = ED_path_extension_type(entry->redirection_path); + } + target = entry->redirection_path; +#ifdef WIN32 + /* On Windows don't show ".lnk" extension for valid shortcuts. */ + BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, ""); +#endif + } + else { + MEM_freeN(entry->redirection_path); + entry->redirection_path = NULL; + entry->attributes |= FILE_ATTR_HIDDEN; + } + } + + if (!(entry->typeflag & FILE_TYPE_DIR)) { + if (do_lib && BLO_has_bfile_extension(target)) { + /* If we are considering .blend files as libs, promote them to directory status. */ + entry->typeflag = FILE_TYPE_BLENDER; + /* prevent current file being used as acceptable dir */ + if (BLI_path_cmp(main_name, target) != 0) { + entry->typeflag |= FILE_TYPE_DIR; + } + } + else { + entry->typeflag = ED_path_extension_type(target); + if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) { + entry->typeflag |= FILE_TYPE_OPERATOR; + } } } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 66157296064..b03df01a02b 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -418,7 +418,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, else { /* if we're bookmarking this, file should come * before the last separator, only automatically added - * current dir go after the last sep. */ + * current dir go after the last separator. */ if (flag & FS_INSERT_SAVE) { break; } @@ -848,6 +848,10 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) CFRelease(volEnum); + /* kLSSharedFileListFavoriteItems is deprecated, but available till macOS 10.15. + * Will have to find a new method to sync the Finder Favorites with File Browser. */ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" /* Finally get user favorite places */ if (read_bookmarks) { UInt32 seed; @@ -891,6 +895,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) CFRelease(pathesArray); CFRelease(list); } +# pragma GCC diagnostic pop } # else /* unix */ diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index ca8919f51a6..185bf029f1a 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -423,8 +423,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) col = uiLayoutColumn(layout, true); /* keyframe itself */ { - - uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -435,16 +434,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) UI_UNIT_Y, &bezt_ptr, "co", - 1, + 0, 0, 0, -1, -1, NULL); - UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); - UI_but_unit_type_set(but, unit); - uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -455,21 +452,42 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) UI_UNIT_Y, &bezt_ptr, "co", - 0, + 1, 0, 0, -1, -1, NULL); UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); + UI_but_unit_type_set(but, unit); + + UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); } /* previous handle - only if previous was Bezier interpolation */ if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) { col = uiLayoutColumn(layout, true); + uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE); + but = uiDefButR(block, + UI_BTYPE_MENU, + B_REDR, + NULL, + 0, + 0, + but_max_width, + UI_UNIT_Y, + &bezt_ptr, + "handle_left_type", + 0, + 0, + 0, + -1, + -1, + "Type of left handle"); + UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt); - uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -488,7 +506,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt); - uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -507,8 +525,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt); UI_but_unit_type_set(but, unit); + } + + /* next handle - only if current is Bezier interpolation */ + if (bezt->ipo == BEZT_IPO_BEZ) { + /* NOTE: special update callbacks are needed on the coords here due to T39911 */ - uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE); + col = uiLayoutColumn(layout, true); + uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, @@ -518,22 +542,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) but_max_width, UI_UNIT_Y, &bezt_ptr, - "handle_left_type", + "handle_right_type", 0, 0, 0, -1, -1, - "Type of left handle"); + "Type of right handle"); UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt); - } - /* next handle - only if current is Bezier interpolation */ - if (bezt->ipo == BEZT_IPO_BEZ) { - /* NOTE: special update callbacks are needed on the coords here due to T39911 */ - - col = uiLayoutColumn(layout, true); - uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -552,7 +570,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt); - uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -571,25 +589,6 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt); UI_but_unit_type_set(but, unit); - - uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE); - but = uiDefButR(block, - UI_BTYPE_MENU, - B_REDR, - NULL, - 0, - 0, - but_max_width, - UI_UNIT_Y, - &bezt_ptr, - "handle_right_type", - 0, - 0, - 0, - -1, - -1, - "Type of right handle"); - UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt); } } else { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index eb97077f77a..8cb85ce9800 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -885,7 +885,6 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene; ViewLayer *view_layer; Object *obedit; - Image *ima; /* retrieve state */ sima = CTX_wm_space_image(C); @@ -894,15 +893,13 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) view_layer = CTX_data_view_layer(C); obedit = CTX_data_edit_object(C); - ima = ED_space_image(sima); - /* get bounds */ float min[2], max[2]; if (ED_space_image_show_uvedit(sima, obedit)) { uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - bool success = ED_uvedit_minmax_multi(scene, ima, objects, objects_len, min, max); + bool success = ED_uvedit_minmax_multi(scene, objects, objects_len, min, max); MEM_freeN(objects); if (!success) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index eb1c46240cb..5668b88826e 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -225,9 +225,9 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles, "PaintTile.mask"); } - ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) * - square_i(ED_IMAGE_UNDO_TILE_SIZE), - "PaintTile.rect"); + ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) * + square_i(ED_IMAGE_UNDO_TILE_SIZE), + "PaintTile.rect"); ptile->use_float = has_float; ptile->valid = true; diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c index 2a3f6d6e365..3685e5de852 100644 --- a/source/blender/editors/space_info/info_draw.c +++ b/source/blender/editors/space_info/info_draw.c @@ -141,7 +141,6 @@ static int report_textview_begin(TextViewContext *tvc) { const ReportList *reports = tvc->arg2; - tvc->lheight = 14 * UI_DPI_FAC; tvc->sel_start = 0; tvc->sel_end = 0; diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index f8c0e66873f..e1937dffb37 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -414,17 +414,11 @@ static const char *footer_string(ViewLayer *view_layer) size_t ofs = 0; uintptr_t mem_in_use = MEM_get_memory_in_use(); - uintptr_t mmap_in_use = MEM_get_mapped_memory_in_use(); /* get memory statistics */ - BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false); + BLI_str_format_byte_unit(formatted_mem, mem_in_use, false); ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem); - if (mmap_in_use) { - BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false); - BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem); - } - if (GPU_mem_stats_supported()) { int gpu_free_mem, gpu_tot_memory; @@ -444,7 +438,7 @@ static const char *footer_string(ViewLayer *view_layer) "%s%s | %s", memstr, gpumemstr, - versionstr); + BKE_blender_version_string()); return view_layer->footer_str; diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index c842fa8b4ac..8076d3d7eaf 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -394,25 +394,26 @@ int textview_draw(TextViewContext *tvc, tvc->line_get(tvc, &ext_line, &ext_len); - if (!textview_draw_string(&tds, - ext_line, - ext_len, - (data_flag & TVC_LINE_FG) ? fg : NULL, - (data_flag & TVC_LINE_BG) ? bg : NULL, - (data_flag & TVC_LINE_ICON) ? icon : 0, - (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL, - (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL, - bg_sel)) { - /* When drawing, if we pass v2d->cur.ymax, then quit. */ - if (do_draw) { - /* Past the y limits. */ - break; - } - } + const bool is_out_of_view_y = !textview_draw_string( + &tds, + ext_line, + ext_len, + (data_flag & TVC_LINE_FG) ? fg : NULL, + (data_flag & TVC_LINE_BG) ? bg : NULL, + (data_flag & TVC_LINE_ICON) ? icon : 0, + (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL, + (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL, + bg_sel); if (do_draw) { + /* We always want the cursor to draw. */ if (tvc->draw_cursor && iter_index == 0) { - tvc->draw_cursor(tvc, tds.cwidth, tds.columns, tds.lofs); + tvc->draw_cursor(tvc, tds.cwidth, tds.columns); + } + + /* When drawing, if we pass v2d->cur.ymax, then quit. */ + if (is_out_of_view_y) { + break; } } @@ -428,6 +429,11 @@ int textview_draw(TextViewContext *tvc, tvc->end(tvc); + /* Sanity checks (bugs here can be tricky to track down). */ + BLI_assert(tds.lheight == tvc->lheight); + BLI_assert(tds.row_vpadding == tvc->row_vpadding); + BLI_assert(tds.do_draw == do_draw); + xy[1] += tvc->lheight * 2; return xy[1] - y_orig; diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index 8eef4ef5d56..41f8baf634e 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -60,7 +60,7 @@ typedef struct TextViewContext { int *r_icon, uchar r_icon_fg[4], uchar r_icon_bg[4]); - void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender); + void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns); /* constant theme colors */ void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]); const void *iter; diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 1d73937d762..95a37f85828 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -82,7 +82,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx nodeSetSelected(node, true); ntreeUpdateTree(bmain, snode->edittree); - ED_node_set_active(bmain, snode->edittree, node); + ED_node_set_active(bmain, snode->edittree, node, NULL); snode_update(snode, node); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index bd5ce135f82..ac58ec1e636 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -648,9 +648,12 @@ void snode_update(SpaceNode *snode, bNode *node) } } -void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) +void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) { const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0; + if (r_active_texture_changed) { + *r_active_texture_changed = false; + } nodeSetActive(ntree, node); @@ -719,6 +722,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) } } + if (r_active_texture_changed) { + *r_active_texture_changed = true; + } ED_node_tag_update_nodetree(bmain, ntree, node); WM_main_add_notifier(NC_IMAGE, NULL); } @@ -1290,7 +1296,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) newnode = node->new_node; nodeSetSelected(node, false); - node->flag &= ~NODE_ACTIVE; + node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); nodeSetSelected(newnode, true); do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode)); diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 9eabcc44d80..06f568c80f3 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include "DNA_node_types.h" +#include "DNA_windowmanager_types.h" #include "BLI_lasso_2d.h" #include "BLI_listbase.h" @@ -36,10 +37,12 @@ #include "BKE_context.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_workspace.h" #include "ED_node.h" /* own include */ #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_view3d.h" #include "RNA_access.h" #include "RNA_define.h" @@ -57,6 +60,36 @@ #include "node_intern.h" /* own include */ +/* Function to detect if there is a visible view3d that uses workbench in texture mode. + * This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in + * the depsgraph that can be used by the draw engines to check if they need to be redrawn. + * + * We don't want to add these risky changes this close before releasing 2.83 without good testing + * hence this workaround. There are still cases were too many updates happen. For example when you + * have both a Cycles and workbench with textures viewport. + * */ +static bool has_workbench_in_texture_color(const wmWindowManager *wm, + const Scene *scene, + const Object *ob) +{ + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + if (win->scene != scene) { + continue; + } + const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype == SPACE_VIEW3D) { + const View3D *v3d = area->spacedata.first; + + if (ED_view3d_has_workbench_in_texture_color(scene, ob, v3d)) { + return true; + } + } + } + } + return false; +} + /* -------------------------------------------------------------------- */ /** \name Public Node Selection API * \{ */ @@ -415,6 +448,10 @@ void node_select_single(bContext *C, bNode *node) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); + const Object *ob = CTX_data_active_object(C); + const Scene *scene = CTX_data_scene(C); + const wmWindowManager *wm = CTX_wm_manager(C); + bool active_texture_changed = false; bNode *tnode; for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { @@ -424,10 +461,13 @@ void node_select_single(bContext *C, bNode *node) } nodeSetSelected(node, true); - ED_node_set_active(bmain, snode->edittree, node); + ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); + if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { + DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + } WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } @@ -440,6 +480,9 @@ static int node_mouse_select(bContext *C, Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); ARegion *region = CTX_wm_region(C); + const Object *ob = CTX_data_active_object(C); + const Scene *scene = CTX_data_scene(C); + const wmWindowManager *wm = CTX_wm_manager(C); bNode *node, *tnode; bNodeSocket *sock = NULL; bNodeSocket *tsock; @@ -546,12 +589,15 @@ static int node_mouse_select(bContext *C, /* update node order */ if (ret_value != OPERATOR_CANCELLED) { + bool active_texture_changed = false; if (node != NULL && ret_value != OPERATOR_RUNNING_MODAL) { - ED_node_set_active(bmain, snode->edittree, node); + ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed); } ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); - DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { + DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + } WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 740d090e641..e879e01ecc4 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -209,6 +209,7 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e ED_region_tag_redraw(region); WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL); + WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL); break; @@ -354,6 +355,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op)) ED_region_tag_redraw(region); WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL); + WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 13cbda5aad7..7d3b95721c6 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -178,20 +178,13 @@ static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2) WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin); } -static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2) +static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *UNUSED(poin2)) { - bArmature *arm = (bArmature *)poin; - Bone *bone = (Bone *)poin2; - if (bone->flag & BONE_HIDDEN_P) { - bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } + Bone *bone = (Bone *)poin; if (CTX_wm_window(C)->eventstate->ctrl) { restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0); } - - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); } static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2) @@ -859,6 +852,7 @@ typedef struct RestrictProperties { *layer_collection_hide_viewport; PropertyRNA *modifier_show_viewport, *modifier_show_render; PropertyRNA *constraint_enable; + PropertyRNA *bone_hide_viewport; } RestrictProperties; /* We don't care about the value of the property @@ -877,6 +871,7 @@ typedef struct RestrictPropertiesActive { bool modifier_show_viewport; bool modifier_show_render; bool constraint_enable; + bool bone_hide_viewport; } RestrictPropertiesActive; static void outliner_restrict_properties_enable_collection_set( @@ -1011,6 +1006,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute"); + props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide"); + props.initialized = true; } @@ -1279,27 +1276,32 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } else if (tselem->type == TSE_POSE_CHANNEL) { + PointerRNA ptr; bPoseChannel *pchan = (bPoseChannel *)te->directdata; Bone *bone = pchan->bone; Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + + RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_HIDDEN_P, - 0, - ICON_RESTRICT_VIEW_OFF, - (int)(region->v2d.cur.xmax - restrict_offsets.viewport), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(bone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(region->v2d.cur.xmax - restrict_offsets.viewport), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.bone_hide_viewport, + -1, + 0, + 0, + -1, + -1, + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_visibility_cb, bone, NULL); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 97ce9ad549f..3db75d9288b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -460,6 +460,9 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot) ot->invoke = outliner_item_rename; ot->poll = ED_operator_outliner_active; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -578,6 +581,9 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot) ot->invoke = outliner_id_delete_invoke; ot->poll = ED_operator_outliner_active; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -715,7 +721,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot) ot->exec = outliner_id_remap_exec; ot->poll = ED_operator_outliner_active; - ot->flag = 0; + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); @@ -823,6 +830,7 @@ void OUTLINER_OT_id_copy(wmOperatorType *ot) ot->exec = outliner_id_copy_exec; ot->poll = ED_operator_outliner_active; + /* Flags, don't need any undo here (this operator does not change anything in Blender data). */ ot->flag = 0; } @@ -863,7 +871,8 @@ void OUTLINER_OT_id_paste(wmOperatorType *ot) ot->exec = outliner_id_paste_exec; ot->poll = ED_operator_outliner_active; - ot->flag = 0; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -974,6 +983,9 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot) ot->invoke = outliner_lib_relocate_invoke; ot->poll = ED_operator_outliner_active; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* XXX This does not work with several items @@ -1028,6 +1040,9 @@ void OUTLINER_OT_lib_reload(wmOperatorType *ot) ot->invoke = outliner_lib_reload_invoke; ot->poll = ED_operator_outliner_active; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void lib_reload_cb(bContext *C, diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 0ccf982fd29..6b65167a921 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -1450,7 +1450,8 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) } else if (event == OL_OP_REMAP) { outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); - str = "Remap ID"; + /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth trick + * does not work here). */ } else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb); @@ -1481,7 +1482,9 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) ED_outliner_select_sync_from_object_tag(C); } - ED_undo_push(C, str); + if (str != NULL) { + ED_undo_push(C, str); + } return OPERATOR_FINISHED; } @@ -1681,6 +1684,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C, static int outliner_id_operation_exec(bContext *C, wmOperator *op) { + wmWindowManager *wm = CTX_wm_manager(C); Scene *scene = CTX_data_scene(C); SpaceOutliner *soops = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; @@ -1801,16 +1805,22 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) if (idlevel > 0) { outliner_do_libdata_operation( C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); - ED_undo_push(C, "Remap"); + /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth + * trick does not work here). */ } break; } case OUTLINER_IDOP_COPY: { + wm->op_undo_depth++; WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL); + wm->op_undo_depth--; + /* No need for undo, this operation does not change anything... */ break; } case OUTLINER_IDOP_PASTE: { + wm->op_undo_depth++; WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL); + wm->op_undo_depth--; ED_outliner_select_sync_from_all_tag(C); ED_undo_push(C, "Paste"); break; @@ -1929,7 +1939,6 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) switch (event) { case OL_LIB_RENAME: { - /* rename */ outliner_do_libdata_operation( C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); @@ -1944,16 +1953,17 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) break; } case OL_LIB_RELOCATE: { - /* rename */ outliner_do_libdata_operation( C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL); - ED_undo_push(C, "Relocate Library"); + /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth + * trick does not work here). */ break; } case OL_LIB_RELOAD: { - /* rename */ outliner_do_libdata_operation( C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL); + /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth + * trick does not work here). */ break; } default: @@ -2102,7 +2112,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; /* flags */ - ot->flag = 0; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* props */ // TODO: this would be nicer as an ID-pointer... @@ -2150,6 +2160,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = { static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceOutliner *soops = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; eOutliner_AnimDataOps event; @@ -2178,7 +2189,10 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) case OUTLINER_ANIMOP_SET_ACT: /* delegate once again... */ + wm->op_undo_depth++; WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL); + wm->op_undo_depth--; + ED_undo_push(C, "Set active action"); break; case OUTLINER_ANIMOP_CLEAR_ACT: @@ -2474,6 +2488,7 @@ static int do_outliner_operation_event( /* Only redraw, don't rebuild here because TreeElement pointers will * become invalid and operations will crash. */ ED_region_tag_redraw_no_rebuild(region); + ED_outliner_select_sync_from_outliner(C, soops); } set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index c910f1d2382..232bb1d66e8 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1652,10 +1652,10 @@ static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData * if (hasNumInput(&data->num_input)) { char num_str[NUM_STR_REP_LEN]; outputNumInput(&data->num_input, num_str, &scene->unit); - BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %s"), num_str); + BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %s"), num_str); } else { - BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %d"), offset); + BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %d"), offset); } } @@ -2508,7 +2508,7 @@ static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *e } } - return WM_operator_confirm(C, op, event); + return sequencer_delete_exec(C, op); } void SEQUENCER_OT_delete(wmOperatorType *ot) diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 0ab8f285de9..9ae501dc060 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC view3d_header.c view3d_iterators.c view3d_ops.c + view3d_placement.c view3d_project.c view3d_select.c view3d_snap.c diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7fcd881d481..74c6692337e 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -675,6 +675,8 @@ static void view3d_widgets(void) WM_gizmogrouptype_append(VIEW3D_GGT_ruler); WM_gizmotype_append(VIEW3D_GT_ruler_item); + WM_gizmogrouptype_append(VIEW3D_GGT_placement); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate); WM_gizmotype_append(VIEW3D_GT_navigate_rotate); } @@ -1087,9 +1089,19 @@ static void view3d_main_region_message_subscribe(const struct bContext *C, } } +/* concept is to retrieve cursor type context-less */ static void view3d_main_region_cursor(wmWindow *win, ScrArea *area, ARegion *region) { - if (!WM_cursor_set_from_tool(win, area, region)) { + if (WM_cursor_set_from_tool(win, area, region)) { + return; + } + + ViewLayer *view_layer = WM_window_get_active_view_layer(win); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + if (obedit) { + WM_cursor_set(win, WM_CURSOR_EDIT); + } + else { WM_cursor_set(win, WM_CURSOR_DEFAULT); } } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 18425b88047..f81b4bb09e2 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1577,9 +1577,7 @@ static void view3d_panel_transform(const bContext *C, Panel *panel) } else { View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const float lim = 10000.0f * max_ff(1.0f, ED_view3d_grid_scale(scene, v3d, NULL)); - v3d_editvertex_buts(col, v3d, ob, lim); + v3d_editvertex_buts(col, v3d, ob, FLT_MAX); } } else if (ob->mode & OB_MODE_POSE) { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 5cdf6ce28cb..25678820050 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -5018,7 +5018,6 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, float cursor_co[3], float cursor_quat[4]) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ARegion *region = CTX_wm_region(C); @@ -5052,7 +5051,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, float ray_co[3]; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - bmain, scene, 0, region, v3d); + scene, 0, region, v3d); float obmat[4][4]; Object *ob_dummy = NULL; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c index 3301e28c90c..3ce4c8dc9a8 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -536,9 +536,12 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv return -1; } -static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz)) +static int gizmo_axis_cursor_get(wmGizmo *gz) { - return WM_CURSOR_DEFAULT; + if (gz->highlight_part > 0) { + return WM_CURSOR_EDIT; + } + return WM_CURSOR_NSEW_SCROLL; } void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt) diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index e4863c0cdeb..f3bc0a8a15b 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -40,6 +40,7 @@ #include "DNA_object_types.h" #include "DNA_view3d_types.h" +#include "ED_gizmo_library.h" #include "ED_gizmo_utils.h" #include "ED_gpencil.h" #include "ED_screen.h" @@ -57,10 +58,13 @@ #include "WM_toolsystem.h" #include "WM_types.h" +#include "DEG_depsgraph_query.h" + #include "view3d_intern.h" /* own include */ #include "GPU_immediate.h" #include "GPU_immediate_util.h" +#include "GPU_matrix.h" #include "GPU_state.h" #include "BLF_api.h" @@ -94,10 +98,6 @@ enum { RULER_STATE_DRAG, }; -enum { - RULER_SNAP_OK = (1 << 0), -}; - struct RulerItem; typedef struct RulerInfo { @@ -106,19 +106,25 @@ typedef struct RulerInfo { int snap_flag; int state; - struct SnapObjectContext *snap_context; - /* wm state */ + wmWindowManager *wm; wmWindow *win; ScrArea *area; ARegion *region; /* re-assigned every modal update */ /* Track changes in state. */ struct { +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK bool do_snap; +#endif bool do_thickness; } drag_state_prev; + struct { + wmGizmo *gizmo; + PropertyRNA *prop_prevpoint; + } snap_data; + } RulerInfo; /* -------------------------------------------------------------------- */ @@ -269,26 +275,17 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, * Ensure the 'snap_context' is only cached while dragging, * needed since the user may toggle modes between tool use. */ -static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) +static void ruler_state_set(RulerInfo *ruler_info, int state) { - Main *bmain = CTX_data_main(C); if (state == ruler_info->state) { return; } - /* always remove */ - if (ruler_info->snap_context) { - ED_transform_snap_object_context_destroy(ruler_info->snap_context); - ruler_info->snap_context = NULL; - } - if (state == RULER_STATE_NORMAL) { /* pass */ } else if (state == RULER_STATE_DRAG) { memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev)); - ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - bmain, CTX_data_scene(C), 0, ruler_info->region, CTX_wm_view3d(C)); } else { BLI_assert(0); @@ -307,13 +304,18 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2], - const bool do_thickness, - const bool do_snap) + const bool do_thickness +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + const bool do_snap +#endif +) { + wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo; const float eps_bias = 0.0002f; float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ - ruler_info->snap_flag &= ~RULER_SNAP_OK; + WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, true); if (ruler_item) { RulerInteraction *inter = ruler_item->gz.interaction_data; @@ -322,8 +324,10 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, copy_v3_v3(co, inter->drag_start_co); view3d_ruler_item_project(ruler_info, co, mval); if (do_thickness && inter->co_index != 1) { - // Scene *scene = CTX_data_scene(C); - // View3D *v3d = ruler_info->area->spacedata.first; + Scene *scene = DEG_get_input_scene(depsgraph); + View3D *v3d = ruler_info->area->spacedata.first; + SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure( + scene, ruler_info->region, v3d, snap_gizmo); const float mval_fl[2] = {UNPACK2(mval)}; float ray_normal[3]; float ray_start[3]; @@ -331,7 +335,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0]; - if (ED_transform_snap_object_project_view3d(ruler_info->snap_context, + if (ED_transform_snap_object_project_view3d(snap_context, depsgraph, SCE_SNAP_MODE_FACE, &(const struct SnapObjectParams){ @@ -346,7 +350,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, negate_v3(ray_normal); /* add some bias */ madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias); - ED_transform_snap_object_project_ray(ruler_info->snap_context, + ED_transform_snap_object_project_ray(snap_context, depsgraph, &(const struct SnapObjectParams){ .snap_select = SNAP_ALL, @@ -359,7 +363,12 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, NULL); } } - else if (do_snap) { + else +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + if (do_snap) +#endif + { + View3D *v3d = ruler_info->area->spacedata.first; const float mval_fl[2] = {UNPACK2(mval)}; float *prev_point = NULL; @@ -374,23 +383,16 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, prev_point = ruler_item->co[0]; } } + if (prev_point != NULL) { + RNA_property_float_set_array( + snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + } - if (ED_transform_snap_object_project_view3d( - ruler_info->snap_context, - depsgraph, - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR), - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - .use_object_edit_cage = true, - .use_occlusion_test = true, - }, - mval_fl, - prev_point, - &dist_px, - co, - NULL)) { - ruler_info->snap_flag |= RULER_SNAP_OK; + short snap_elem = ED_gizmotypes_snap_3d_update( + snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL); + + if (snap_elem) { + WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, false); } } return true; @@ -417,6 +419,15 @@ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd) return NULL; } +static RulerItem *gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup) +{ +#ifndef NDEBUG + RulerInfo *ruler_info = gzgroup->customdata; + BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo); +#endif + return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next; +} + #define RULER_ID "RulerData3D" static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) { @@ -448,7 +459,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); BKE_gpencil_free_strokes(gpf); - for (ruler_item = gzgroup->gizmos.first; ruler_item; + for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item; ruler_item = (RulerItem *)ruler_item->gz.next) { bGPDspoint *pt; int j; @@ -556,6 +567,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) uchar color_wire[3]; float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f}; + /* Pixel Space. */ + GPU_matrix_push_projection(); + GPU_matrix_push(); + GPU_matrix_identity_set(); + wmOrtho2_region_pixelspace(region); + /* anti-aliased lines for more consistent appearance */ GPU_line_smooth(true); GPU_line_width(1.0f); @@ -575,20 +592,30 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) const bool is_act = (ruler_info->item_active == ruler_item); float dir_ruler[2]; float co_ss[3][2]; + bool proj_ok[3]; int j; - /* should these be checked? - ok for now not to */ + /* Check if each corner is behind the near plane. If it is, we do not draw certain lines. */ for (j = 0; j < 3; j++) { - ED_view3d_project_float_global(region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); + eV3DProjStatus status = ED_view3d_project_float_global( + region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_CLIP_NEAR); + proj_ok[j] = (status == V3D_PROJ_RET_OK); } + /* 3d drawing. */ + + GPU_matrix_push_projection(); + GPU_matrix_push(); + GPU_matrix_projection_set(rv3d->winmat); + GPU_matrix_set(rv3d->viewmat); + GPU_blend(true); - const uint shdr_pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + const uint shdr_pos_3d = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); if (ruler_item->flag & RULERITEM_USE_ANGLE) { - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -605,21 +632,20 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINE_STRIP, 3); - immVertex2fv(shdr_pos, co_ss[0]); - immVertex2fv(shdr_pos, co_ss[1]); - immVertex2fv(shdr_pos, co_ss[2]); + immVertex3fv(shdr_pos_3d, ruler_item->co[0]); + immVertex3fv(shdr_pos_3d, ruler_item->co[1]); + immVertex3fv(shdr_pos_3d, ruler_item->co[2]); immEnd(); immUnbindProgram(); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); /* arc */ { float dir_tmp[3]; - float co_tmp[3]; - float arc_ss_coord[2]; + float ar_coord[3]; float dir_a[3]; float dir_b[3]; @@ -648,16 +674,53 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1); for (j = 0; j <= arc_steps; j++) { - madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); - ED_view3d_project_float_global(region, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP); + madd_v3_v3v3fl(ar_coord, ruler_item->co[1], dir_tmp, px_scale); mul_qt_v3(quat, dir_tmp); - immVertex2fv(shdr_pos, arc_ss_coord); + immVertex3fv(shdr_pos_3d, ar_coord); } immEnd(); } + immUnbindProgram(); + } + else { + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("colors_len", 2); /* "advanced" mode */ + const float *col = is_act ? color_act : color_base; + immUniformArray4fv( + "colors", + (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, + 2); + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); + + immBegin(GPU_PRIM_LINES, 2); + + immVertex3fv(shdr_pos_3d, ruler_item->co[0]); + immVertex3fv(shdr_pos_3d, ruler_item->co[2]); + + immEnd(); + + immUnbindProgram(); + } + + /* 2d drawing. */ + + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + + const uint shdr_pos_2d = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* capping */ { float rot_90_vec_a[2]; @@ -676,15 +739,15 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_blend(true); - if (is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) { + if (proj_ok[1] && is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) { GPU_line_width(3.0f); immUniformColor3fv(color_act); immBegin(GPU_PRIM_LINES, 4); /* angle vertex */ - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); immEnd(); GPU_line_width(1.0f); @@ -692,25 +755,33 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUniformColor3ubv(color_wire); - immBegin(GPU_PRIM_LINES, 8); + if (proj_ok[0] || proj_ok[2] || proj_ok[1]) { + immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[0]) { + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[2]) { + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - /* angle vertex */ - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); - immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + /* angle vertex */ + if (proj_ok[1]) { + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + } - immEnd(); + immEnd(); + } GPU_blend(false); } @@ -729,10 +800,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); /* draw text (bg) */ - { + if (proj_ok[1]) { immUniformColor4fv(color_back); GPU_blend(true); - immRectf(shdr_pos, + immRectf(shdr_pos_2d, posit[0] - bg_margin, posit[1] - bg_margin, posit[0] + bg_margin + numstr_size[0], @@ -743,7 +814,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUnbindProgram(); /* draw text */ - { + if (proj_ok[1]) { BLF_color3ubv(blf_mono_font, color_text); BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); BLF_rotation(blf_mono_font, 0.0f); @@ -751,30 +822,6 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) } } else { - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - - immUniform1i("colors_len", 2); /* "advanced" mode */ - const float *col = is_act ? color_act : color_base; - immUniformArray4fv( - "colors", - (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, - 2); - immUniform1f("dash_width", 6.0f); - immUniform1f("dash_factor", 0.5f); - - immBegin(GPU_PRIM_LINES, 2); - - immVertex2fv(shdr_pos, co_ss[0]); - immVertex2fv(shdr_pos, co_ss[2]); - - immEnd(); - - immUnbindProgram(); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); @@ -790,19 +837,25 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUniformColor3ubv(color_wire); - immBegin(GPU_PRIM_LINES, 4); + if (proj_ok[0] || proj_ok[2]) { + immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[0]) { + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); - immVertex2fv(shdr_pos, cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); - immVertex2fv(shdr_pos, cap); + if (proj_ok[2]) { + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); + immVertex2fv(shdr_pos_2d, cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); + immVertex2fv(shdr_pos_2d, cap); + } - immEnd(); + immEnd(); + } GPU_blend(false); } @@ -824,10 +877,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) posit[1] -= numstr_size[1] / 2.0f; /* draw text (bg) */ - { + if (proj_ok[0] && proj_ok[2]) { immUniformColor4fv(color_back); GPU_blend(true); - immRectf(shdr_pos, + immRectf(shdr_pos_2d, posit[0] - bg_margin, posit[1] - bg_margin, posit[0] + bg_margin + numstr_size[0], @@ -838,7 +891,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) immUnbindProgram(); /* draw text */ - { + if (proj_ok[0] && proj_ok[2]) { BLF_color3ubv(blf_mono_font, color_text); BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); BLF_draw(blf_mono_font, numstr, sizeof(numstr)); @@ -849,27 +902,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) BLF_disable(blf_mono_font, BLF_ROTATION); -#undef ARC_STEPS - - /* draw snap */ - if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG) && - (ruler_item->gz.interaction_data != NULL)) { - RulerInteraction *inter = ruler_item->gz.interaction_data; - /* size from drawSnapping */ - const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); - float co_ss_snap[3]; - ED_view3d_project_float_global( - region, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP); - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_matrix_pop(); + GPU_matrix_pop_projection(); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColor3(TH_GIZMO_VIEW_ALIGN); - - imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32); - - immUnbindProgram(); - } +#undef ARC_STEPS } static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) @@ -902,35 +938,36 @@ static int gizmo_ruler_modal(bContext *C, RulerInfo *ruler_info = gz->parent_gzgroup->customdata; RulerItem *ruler_item = (RulerItem *)gz; ARegion *region = CTX_wm_region(C); - bool do_cursor_update = false; + bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE); ruler_info->region = region; - switch (event->type) { - case MOUSEMOVE: { - do_cursor_update = true; - break; - } - } - - const bool do_snap = tweak_flag & WM_GIZMO_TWEAK_SNAP; +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP); +#endif const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE; - if ((ruler_info->drag_state_prev.do_snap != do_snap) || - (ruler_info->drag_state_prev.do_thickness != do_thickness)) { + if ((ruler_info->drag_state_prev.do_thickness != do_thickness)) { do_cursor_update = true; } if (do_cursor_update) { if (ruler_info->state == RULER_STATE_DRAG) { struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - if (view3d_ruler_item_mousemove( - depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap)) { + if (view3d_ruler_item_mousemove(depsgraph, + ruler_info, + ruler_item, + event->mval, + do_thickness +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + do_snap +#endif + )) { do_draw = true; } } } - ruler_info->drag_state_prev.do_snap = do_snap; ruler_info->drag_state_prev.do_thickness = do_thickness; if (do_draw) { @@ -957,7 +994,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) /* Add Center Point */ ruler_item_pick->flag |= RULERITEM_USE_ANGLE; inter->co_index = 1; - ruler_state_set(C, ruler_info, RULER_STATE_DRAG); + ruler_state_set(ruler_info, RULER_STATE_DRAG); /* find the factor */ { @@ -978,13 +1015,21 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) /* update the new location */ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - view3d_ruler_item_mousemove( - depsgraph, ruler_info, ruler_item_pick, event->mval, false, false); + view3d_ruler_item_mousemove(depsgraph, + ruler_info, + ruler_item_pick, + event->mval, + false +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + false +#endif + ); } } else { inter->co_index = gz->highlight_part; - ruler_state_set(C, ruler_info, RULER_STATE_DRAG); + ruler_state_set(ruler_info, RULER_STATE_DRAG); /* store the initial depth */ copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]); @@ -997,6 +1042,28 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) ruler_item_pick->flag &= ~RULERITEM_USE_ANGLE_ACTIVE; } + { + /* Set Snap prev point. */ + float *prev_point; + if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) { + prev_point = (inter->co_index != 1) ? ruler_item_pick->co[1] : NULL; + } + else if (inter->co_index == 0) { + prev_point = ruler_item_pick->co[2]; + } + else { + prev_point = ruler_item_pick->co[0]; + } + + if (prev_point) { + RNA_property_float_set_array( + ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); + } + else { + RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); + } + } + ruler_info->item_active = ruler_item_pick; return OPERATOR_RUNNING_MODAL; @@ -1009,10 +1076,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { - if (ruler_info->snap_flag & RULER_SNAP_OK) { - ruler_info->snap_flag &= ~RULER_SNAP_OK; - } - ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); + WM_gizmo_set_flag(ruler_info->snap_data.gizmo, WM_GIZMO_HIDDEN, false); + RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); + ruler_state_set(ruler_info, RULER_STATE_NORMAL); } /* We could convert only the current gizmo, for now just re-generate. */ view3d_ruler_to_gpencil(C, gzgroup); @@ -1022,7 +1088,7 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) MEM_SAFE_FREE(gz->interaction_data); } - ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); + ruler_state_set(ruler_info, RULER_STATE_NORMAL); } static int gizmo_ruler_cursor_get(wmGizmo *gz) @@ -1059,16 +1125,39 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup) { RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__); + wmGizmo *gizmo; + { + /* The gizmo snap has to be the first gizmo. */ + const wmGizmoType *gzt_snap; + gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); + gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); + RNA_enum_set(gizmo->ptr, + "snap_elements_force", + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)); + + WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + + wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true); + WM_gizmo_operator_set(gizmo, 0, ot, NULL); + } + if (view3d_ruler_from_gpencil(C, gzgroup)) { /* nop */ } + wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); + + ruler_info->wm = wm; ruler_info->win = win; ruler_info->area = area; ruler_info->region = region; + ruler_info->snap_data.gizmo = gizmo; + ruler_info->snap_data.prop_prevpoint = RNA_struct_find_property(gizmo->ptr, "prev_point"); gzgroup->customdata = ruler_info; } @@ -1078,7 +1167,7 @@ void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt) gzgt->name = "Ruler Widgets"; gzgt->idname = view3d_gzgt_ruler_id; - gzgt->flag |= WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; + gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; gzgt->gzmap_params.spaceid = SPACE_VIEW3D; gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; @@ -1132,8 +1221,20 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); /* snap the first point added, not essential but handy */ inter->co_index = 0; - view3d_ruler_item_mousemove(depsgraph, ruler_info, ruler_item, event->mval, false, true); + view3d_ruler_item_mousemove(depsgraph, + ruler_info, + ruler_item, + event->mval, + false +#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK + , + true +#endif + ); copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]); + RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr, + ruler_info->snap_data.prop_prevpoint, + inter->drag_start_co); } else { negate_v3_v3(inter->drag_start_co, rv3d->ofs); @@ -1152,6 +1253,7 @@ void VIEW3D_OT_ruler_add(wmOperatorType *ot) /* identifiers */ ot->name = "Ruler Add"; ot->idname = "VIEW3D_OT_ruler_add"; + ot->description = "Add ruler"; ot->invoke = view3d_ruler_add_invoke; ot->poll = view3d_ruler_poll; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index c16131c8317..50cd71d7edc 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -213,6 +213,7 @@ void viewrotate_modal_keymap(struct wmKeyConfig *keyconf); void viewmove_modal_keymap(struct wmKeyConfig *keyconf); void viewzoom_modal_keymap(struct wmKeyConfig *keyconf); void viewdolly_modal_keymap(struct wmKeyConfig *keyconf); +void viewplace_modal_keymap(struct wmKeyConfig *keyconf); /* view3d_buttons.c */ void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot); @@ -243,6 +244,9 @@ void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot); +/* view3d_placement.c */ +void VIEW3D_OT_interactive_add(struct wmOperatorType *ot); + /* space_view3d.c */ extern const char *view3d_context_dir[]; /* doc access */ @@ -268,6 +272,8 @@ void VIEW3D_OT_ruler_remove(struct wmOperatorType *ot); void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt); +void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt); + /* workaround for trivial but noticeable camera bug caused by imprecision * between view border calculation in 2D/3D space, workaround for bug [#28037]. * without this define we get the old behavior which is to try and align them diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index 08e68c9174e..91e629147f4 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -126,7 +126,7 @@ void meshobject_foreachScreenVert( Scene *scene_eval = DEG_get_evaluated_scene(vc->depsgraph); Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact); - me = mesh_get_eval_deform(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + me = mesh_get_eval_final(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); ED_view3d_check_mats_rv3d(vc->rv3d); @@ -406,6 +406,7 @@ void nurbs_foreachScreenVert(ViewContext *vc, BPoint *bp, BezTriple *bezt, int beztindex, + bool handles_visible, const float screen_co_b[2]), void *userData, const eV3DProjTest clip_flag) @@ -414,6 +415,8 @@ void nurbs_foreachScreenVert(ViewContext *vc, Nurb *nu; int i; ListBase *nurbs = BKE_curve_editNurbs_get(cu); + /* If no point in the triple is selected, the handles are invisible. */ + const bool only_selected = (vc->v3d->overlay.handle_display == CURVE_HANDLE_SELECTED); ED_view3d_check_mats_rv3d(vc->rv3d); @@ -427,15 +430,17 @@ void nurbs_foreachScreenVert(ViewContext *vc, BezTriple *bezt = &nu->bezt[i]; if (bezt->hide == 0) { + const bool handles_visible = (vc->v3d->overlay.handle_display != CURVE_HANDLE_NONE) && + (!only_selected || BEZT_ISSEL_ANY(bezt)); float screen_co[2]; - if ((vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { + if (!handles_visible) { if (ED_view3d_project_float_object(vc->region, bezt->vec[1], screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 1, screen_co); + func(userData, nu, NULL, bezt, 1, false, screen_co); } } else { @@ -444,21 +449,21 @@ void nurbs_foreachScreenVert(ViewContext *vc, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 0, screen_co); + func(userData, nu, NULL, bezt, 0, true, screen_co); } if (ED_view3d_project_float_object(vc->region, bezt->vec[1], screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 1, screen_co); + func(userData, nu, NULL, bezt, 1, true, screen_co); } if (ED_view3d_project_float_object(vc->region, bezt->vec[2], screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 2, screen_co); + func(userData, nu, NULL, bezt, 2, true, screen_co); } } } @@ -473,7 +478,7 @@ void nurbs_foreachScreenVert(ViewContext *vc, if (ED_view3d_project_float_object( vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { - func(userData, nu, bp, NULL, -1, screen_co); + func(userData, nu, bp, NULL, -1, false, screen_co); } } } diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 1ad3f8bb1f5..0770bac1313 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -211,6 +211,8 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active); + WM_operatortype_append(VIEW3D_OT_interactive_add); + WM_operatortype_append(VIEW3D_OT_toggle_shading); WM_operatortype_append(VIEW3D_OT_toggle_xray); WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip); @@ -234,4 +236,5 @@ void view3d_keymap(wmKeyConfig *keyconf) viewmove_modal_keymap(keyconf); viewzoom_modal_keymap(keyconf); viewdolly_modal_keymap(keyconf); + viewplace_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c new file mode 100644 index 00000000000..f2b78bc2aaf --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -0,0 +1,1153 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + * + * Operator to interactively place data. + * + * Currently only adds meshes, but could add other kinds of data + * including library assets & non-mesh types. + */ + +#include "BLI_math_vector.h" +#include "MEM_guardedalloc.h" + +#include "DNA_collection_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_vfont_types.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_main.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "ED_gizmo_library.h" +#include "ED_gizmo_utils.h" +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_transform.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "UI_resources.h" + +#include "GPU_batch.h" +#include "GPU_immediate.h" +#include "GPU_state.h" + +#include "view3d_intern.h" + +static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; + +/* -------------------------------------------------------------------- */ +/** \name Local Types + * \{ */ + +enum ePlace_PrimType { + PLACE_PRIMITIVE_TYPE_CUBE = 1, + PLACE_PRIMITIVE_TYPE_CYLINDER = 2, + PLACE_PRIMITIVE_TYPE_CONE = 3, + PLACE_PRIMITIVE_TYPE_SPHERE_UV = 4, + PLACE_PRIMITIVE_TYPE_SPHERE_ICO = 5, +}; + +enum ePlace_Origin { + PLACE_ORIGIN_BASE = 1, + PLACE_ORIGIN_CENTER = 2, +}; + +enum ePlace_Depth { + PLACE_DEPTH_SURFACE = 1, + PLACE_DEPTH_CURSOR_PLANE = 2, + PLACE_DEPTH_CURSOR_VIEW = 3, +}; + +struct InteractivePlaceData { + /* Window manager variables (set these even when waiting for input). */ + Scene *scene; + ScrArea *area; + View3D *v3d; + ARegion *region; + + /** Draw object preview region draw callback. */ + void *draw_handle_view; + + float co_src[3]; + + /** Primary & secondary steps. */ + struct { + bool is_centered; + bool is_fixed_aspect; + float plane[4]; + float co_dst[3]; + } step[2]; + + float matrix_orient[3][3]; + int orient_axis; + + /** The tool option, if we start centered, invert toggling behavior. */ + bool is_centered_init; + + bool use_snap, is_snap_found, is_snap_invert; + float snap_co[3]; + + /** Can index into #InteractivePlaceData.step. */ + enum { + STEP_BASE = 0, + STEP_DEPTH = 1, + } step_index; + + enum ePlace_PrimType primitive_type; + + /** Activated from the tool-system. */ + bool use_tool; + + /** Event used to start the operator. */ + short launch_event; + + /** When activated without a tool. */ + bool wait_for_input; + + /** Optional snap gizmo, needed for snapping. */ + wmGizmo *snap_gizmo; +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ + +/* On-screen snap distance. */ +#define MVAL_MAX_PX_DIST 12.0f + +static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3]) +{ + if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) { + PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, "location"); + RNA_property_float_get_array(gz->ptr, prop_location, r_location); + return true; + } + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Primitive Drawing (Cube, Cone, Cylinder...) + * \{ */ + +static void draw_line_loop(float coords[][3], int coords_len, const float color[4]) +{ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, coords_len); + + for (int i = 0; i < coords_len; i++) { + GPU_vertbuf_attr_set(vert, pos, i, coords[i]); + } + + GPU_blend(true); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + GPU_batch_bind(batch); + + GPU_batch_uniform_4fv(batch, "color", color); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); + GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); + + GPU_batch_draw(batch); + + GPU_batch_program_use_end(batch); + + GPU_batch_discard(batch); + GPU_blend(false); +} + +static void draw_line_pairs(float coords_a[][3], + float coords_b[][3], + int coords_len, + const float color[4]) +{ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, coords_len * 2); + + for (int i = 0; i < coords_len; i++) { + GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]); + GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]); + } + + GPU_blend(true); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + GPU_batch_bind(batch); + + GPU_batch_uniform_4fv(batch, "color", color); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); + GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); + + GPU_batch_draw(batch); + + GPU_batch_program_use_end(batch); + + GPU_batch_discard(batch); + GPU_blend(false); +} + +static void draw_line_bounds(const BoundBox *bounds, const float color[4]) +{ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + int edges[12][2] = { + /* First side. */ + {0, 1}, + {1, 2}, + {2, 3}, + {3, 0}, + /* Second side. */ + {4, 5}, + {5, 6}, + {6, 7}, + {7, 4}, + /* Edges between. */ + {0, 4}, + {1, 5}, + {2, 6}, + {3, 7}, + }; + + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, ARRAY_SIZE(edges) * 2); + + for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) { + GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]); + GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]); + } + + GPU_blend(true); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR); + + GPU_batch_bind(batch); + + GPU_batch_uniform_4fv(batch, "color", color); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]); + GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize); + + GPU_batch_draw(batch); + + GPU_batch_program_use_end(batch); + + GPU_batch_discard(batch); + GPU_blend(false); +} + +static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds) +{ + memset(bounds, 0x0, sizeof(*bounds)); + + if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) { + return false; + } + + float matrix_orient_inv[3][3]; + invert_m3_m3(matrix_orient_inv, ipd->matrix_orient); + + const int x_axis = (ipd->orient_axis + 1) % 3; + const int y_axis = (ipd->orient_axis + 2) % 3; + + float quad_base[4][3]; + float quad_secondary[4][3]; + + copy_v3_v3(quad_base[0], ipd->co_src); + copy_v3_v3(quad_base[2], ipd->step[0].co_dst); + + /* Only set when we have a fixed aspect. */ + float fixed_aspect_dimension; + + /* *** Primary *** */ + + { + float delta_local[3]; + float delta_a[3]; + float delta_b[3]; + + sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src); + mul_m3_v3(matrix_orient_inv, delta_local); + + copy_v3_v3(delta_a, delta_local); + copy_v3_v3(delta_b, delta_local); + delta_a[ipd->orient_axis] = 0.0f; + delta_b[ipd->orient_axis] = 0.0f; + + delta_a[x_axis] = 0.0f; + delta_b[y_axis] = 0.0f; + + /* Assign here in case secondary */ + fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis])); + + if (ipd->step[0].is_fixed_aspect) { + delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]); + delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]); + } + + mul_m3_v3(ipd->matrix_orient, delta_a); + mul_m3_v3(ipd->matrix_orient, delta_b); + + if (ipd->step[0].is_fixed_aspect) { + /* Recalculate the destination point. */ + copy_v3_v3(quad_base[2], ipd->co_src); + add_v3_v3(quad_base[2], delta_a); + add_v3_v3(quad_base[2], delta_b); + } + + add_v3_v3v3(quad_base[1], ipd->co_src, delta_a); + add_v3_v3v3(quad_base[3], ipd->co_src, delta_b); + } + + if (ipd->step[0].is_centered) { + /* Use a copy in case aspect was applied to the quad. */ + float base_co_dst[3]; + copy_v3_v3(base_co_dst, quad_base[2]); + for (int i = 0; i < 4; i++) { + sub_v3_v3(quad_base[i], base_co_dst); + mul_v3_fl(quad_base[i], 2.0f); + add_v3_v3(quad_base[i], base_co_dst); + } + } + + /* *** Secondary *** */ + + float delta_local[3]; + if (ipd->step_index == STEP_DEPTH) { + sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst); + } + else { + zero_v3(delta_local); + } + + if (ipd->step[1].is_fixed_aspect) { + if (!is_zero_v3(delta_local)) { + normalize_v3_length(delta_local, fixed_aspect_dimension); + } + } + + if (ipd->step[1].is_centered) { + for (int i = 0; i < ARRAY_SIZE(quad_base); i++) { + sub_v3_v3(quad_base[i], delta_local); + } + mul_v3_fl(delta_local, 2.0f); + } + + if ((ipd->step_index == STEP_DEPTH) && + (compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false)) { + + for (int i = 0; i < ARRAY_SIZE(quad_base); i++) { + add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local); + } + } + else { + copy_v3_v3(quad_secondary[0], quad_base[0]); + copy_v3_v3(quad_secondary[1], quad_base[1]); + copy_v3_v3(quad_secondary[2], quad_base[2]); + copy_v3_v3(quad_secondary[3], quad_base[3]); + } + + for (int i = 0; i < 4; i++) { + copy_v3_v3(bounds->vec[i], quad_base[i]); + copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]); + } + + return true; +} + +static void draw_circle_in_quad(const float v1[2], + const float v2[2], + const float v3[2], + const float v4[2], + const int resolution, + const float color[4]) +{ + /* This isn't so efficient. */ + const float quad[4][2] = { + {-1, -1}, + {+1, -1}, + {+1, +1}, + {-1, +1}, + }; + + float(*coords)[3] = MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__); + for (int i = 0; i <= resolution; i++) { + float theta = ((2.0f * M_PI) * ((float)i / (float)resolution)) + 0.01f; + float x = cosf(theta); + float y = sinf(theta); + float pt[2] = {x, y}; + float w[4]; + barycentric_weights_v2_quad(UNPACK4(quad), pt, w); + + float *co = coords[i]; + zero_v3(co); + madd_v3_v3fl(co, v1, w[0]); + madd_v3_v3fl(co, v2, w[1]); + madd_v3_v3fl(co, v3, w[2]); + madd_v3_v3fl(co, v4, w[3]); + } + draw_line_loop(coords, resolution + 1, color); + MEM_freeN(coords); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Drawing Callbacks + * \{ */ + +static void draw_primitive_view_impl(const struct bContext *C, + struct InteractivePlaceData *ipd, + const float color[4]) +{ + UNUSED_VARS(C); + + BoundBox bounds; + calc_bbox(ipd, &bounds); + draw_line_bounds(&bounds, color); + + if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) { + /* pass */ + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) { + draw_circle_in_quad(UNPACK4(bounds.vec), 32, color); + draw_circle_in_quad(UNPACK4((&bounds.vec[4])), 32, color); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) { + draw_circle_in_quad(UNPACK4(bounds.vec), 32, color); + + float center[3]; + mid_v3_v3v3v3v3(center, UNPACK4((&bounds.vec[4]))); + + float coords_a[4][3]; + float coords_b[4][3]; + + for (int i = 0; i < 4; i++) { + copy_v3_v3(coords_a[i], center); + mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]); + } + + draw_line_pairs(coords_a, coords_b, 4, color); + } + else if (ELEM(ipd->primitive_type, + PLACE_PRIMITIVE_TYPE_SPHERE_UV, + PLACE_PRIMITIVE_TYPE_SPHERE_ICO)) { + /* See bound-box diagram for reference. */ + + /* Primary Side. */ + float v01[3], v12[3], v23[3], v30[3]; + mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]); + mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]); + mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]); + mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]); + /* Secondary Side. */ + float v45[3], v56[3], v67[3], v74[3]; + mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]); + mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]); + mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]); + mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]); + /* Edges between. */ + float v04[3], v15[3], v26[3], v37[3]; + mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]); + mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]); + mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]); + mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]); + + draw_circle_in_quad(v01, v45, v67, v23, 32, color); + draw_circle_in_quad(v30, v12, v56, v74, 32, color); + draw_circle_in_quad(v04, v15, v26, v37, 32, color); + } +} + +static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region), void *arg) +{ + struct InteractivePlaceData *ipd = arg; + float color[4]; + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, color); + + const bool use_depth = !XRAY_ENABLED(ipd->v3d); + const bool depth_test_enabled = GPU_depth_test_enabled(); + + if (use_depth) { + GPU_depth_test(false); + color[3] = 0.15f; + draw_primitive_view_impl(C, ipd, color); + } + + if (use_depth) { + GPU_depth_test(true); + } + color[3] = 1.0f; + draw_primitive_view_impl(C, ipd, color); + + if (use_depth) { + if (depth_test_enabled == false) { + GPU_depth_test(false); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Object Modal Operator + * \{ */ + +/** + * + * */ +static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event) +{ + + const int plane_axis = RNA_enum_get(op->ptr, "plane_axis"); + const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth"); + const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin"); + + struct InteractivePlaceData *ipd = op->customdata; + + RegionView3D *rv3d = ipd->region->regiondata; + + ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type); + + ED_transform_calc_orientation_from_type(C, ipd->matrix_orient); + + ipd->orient_axis = plane_axis; + ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER); + ipd->step[0].is_centered = ipd->is_centered_init; + ipd->step[1].is_centered = ipd->is_centered_init; + ipd->step_index = STEP_BASE; + + /* Assign snap gizmo which is may be used as part of the tool. */ + { + wmGizmoMap *gzmap = ipd->region->gizmo_map; + wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL; + if ((gzgroup != NULL) && gzgroup->gizmos.first) { + ipd->snap_gizmo = gzgroup->gizmos.first; + } + } + + { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type"); + if (RNA_property_is_set(op->ptr, prop)) { + ipd->primitive_type = RNA_property_enum_get(op->ptr, prop); + ipd->use_tool = false; + } + else { + ipd->use_tool = true; + + /* Get from the tool, a bit of a non-standard way of operating. */ + const bToolRef *tref = ipd->area->runtime.tool; + if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CYLINDER; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CONE; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_UV; + } + else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) { + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_ICO; + } + else { + /* If the user runs this as an operator they should set the 'primitive_type', + * however running from operator search will end up at this point. */ + ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE; + ipd->use_tool = false; + } + } + } + + UNUSED_VARS(C, event); + + ipd->draw_handle_view = ED_region_draw_cb_activate( + ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW); + + ED_region_tag_redraw(ipd->region); + + plane_from_point_normal_v3( + ipd->step[0].plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]); + + const float mval_fl[2] = {UNPACK2(event->mval)}; + + const bool is_snap_found = ipd->snap_gizmo ? + idp_snap_point_from_gizmo(ipd->snap_gizmo, ipd->co_src) : + false; + ipd->is_snap_invert = ipd->snap_gizmo ? ED_gizmotypes_snap_3d_invert_snap_get(ipd->snap_gizmo) : + false; + { + const ToolSettings *ts = ipd->scene->toolsettings; + ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP)); + } + + if (is_snap_found) { + /* pass */ + } + else { + bool use_depth_fallback = true; + if (plane_depth == PLACE_DEPTH_CURSOR_VIEW) { + /* View plane. */ + ED_view3d_win_to_3d( + ipd->v3d, ipd->region, ipd->scene->cursor.location, mval_fl, ipd->co_src); + use_depth_fallback = false; + } + else if (plane_depth == PLACE_DEPTH_SURFACE) { + SnapObjectContext *snap_context = + (ipd->snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure( + ipd->scene, ipd->region, ipd->v3d, ipd->snap_gizmo) : + NULL); + if ((snap_context != NULL) && + ED_transform_snap_object_project_view3d(snap_context, + CTX_data_ensure_evaluated_depsgraph(C), + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = true, + }, + mval_fl, + NULL, + NULL, + ipd->co_src, + NULL)) { + use_depth_fallback = false; + } + } + + /* Use as fallback to surface. */ + if (use_depth_fallback || (plane_depth == PLACE_DEPTH_CURSOR_PLANE)) { + /* Cursor plane. */ + float plane[4]; + plane_from_point_normal_v3( + plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]); + if (ED_view3d_win_to_3d_on_plane(ipd->region, plane, mval_fl, false, ipd->co_src)) { + use_depth_fallback = false; + } + /* Even if the calculation works, it's possible the point found is behind the view. */ + if (rv3d->is_persp) { + float dir[3]; + sub_v3_v3v3(dir, rv3d->viewinv[3], ipd->co_src); + if (dot_v3v3(dir, rv3d->viewinv[2]) < ipd->v3d->clip_start) { + use_depth_fallback = true; + } + } + } + + if (use_depth_fallback) { + float co_depth[3]; + /* Fallback to view center. */ + negate_v3_v3(co_depth, rv3d->ofs); + ED_view3d_win_to_3d(ipd->v3d, ipd->region, co_depth, mval_fl, ipd->co_src); + } + } + + plane_from_point_normal_v3( + ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[ipd->orient_axis]); + + copy_v3_v3(ipd->step[0].co_dst, ipd->co_src); +} + +static int view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input"); + + struct InteractivePlaceData *ipd = MEM_callocN(sizeof(*ipd), __func__); + op->customdata = ipd; + + ipd->scene = CTX_data_scene(C); + ipd->area = CTX_wm_area(C); + ipd->region = CTX_wm_region(C); + ipd->v3d = CTX_wm_view3d(C); + + if (wait_for_input) { + ipd->wait_for_input = true; + /* TODO: support snapping when not using with tool. */ +#if 0 + WM_gizmo_group_type_ensure(view3d_gzgt_placement_id); +#endif + } + else { + view3d_interactive_add_begin(C, op, event); + } + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static void view3d_interactive_add_exit(bContext *C, wmOperator *op) +{ + UNUSED_VARS(C); + + struct InteractivePlaceData *ipd = op->customdata; + + ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view); + + ED_region_tag_redraw(ipd->region); + + MEM_freeN(ipd); +} + +static void view3d_interactive_add_cancel(bContext *C, wmOperator *op) +{ + view3d_interactive_add_exit(C, op); +} + +enum { + PLACE_MODAL_SNAP_ON, + PLACE_MODAL_SNAP_OFF, + PLACE_MODAL_FIXED_ASPECT_ON, + PLACE_MODAL_FIXED_ASPECT_OFF, + PLACE_MODAL_PIVOT_CENTER_ON, + PLACE_MODAL_PIVOT_CENTER_OFF, +}; + +void viewplace_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""}, + {PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""}, + {PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""}, + {PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""}, + {PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""}, + {PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + const char *keymap_name = "View3D Placement Modal Map"; + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name); + + /* This function is called for each space-type, only needs to add map once. */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items); + + WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add"); +} + +static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + UNUSED_VARS(C, op); + + struct InteractivePlaceData *ipd = op->customdata; + + ARegion *region = ipd->region; + bool do_redraw = false; + bool do_cursor_update = false; + + /* Handle modal key-map. */ + if (event->type == EVT_MODAL_MAP) { + bool is_fallthrough = false; + switch (event->val) { + case PLACE_MODAL_FIXED_ASPECT_ON: { + is_fallthrough = true; + ATTR_FALLTHROUGH; + } + case PLACE_MODAL_FIXED_ASPECT_OFF: { + ipd->step[ipd->step_index].is_fixed_aspect = is_fallthrough; + do_redraw = true; + break; + } + case PLACE_MODAL_PIVOT_CENTER_ON: { + is_fallthrough = true; + ATTR_FALLTHROUGH; + } + case PLACE_MODAL_PIVOT_CENTER_OFF: { + ipd->step[ipd->step_index].is_centered = is_fallthrough; + do_redraw = true; + break; + } + case PLACE_MODAL_SNAP_ON: { + is_fallthrough = true; + ATTR_FALLTHROUGH; + } + case PLACE_MODAL_SNAP_OFF: { + const ToolSettings *ts = ipd->scene->toolsettings; + ipd->is_snap_invert = is_fallthrough; + ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP)); + do_cursor_update = true; + break; + } + } + } + + if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) { + view3d_interactive_add_exit(C, op); + return OPERATOR_CANCELLED; + } + else if (event->type == MOUSEMOVE) { + do_cursor_update = true; + } + + if (ipd->wait_for_input) { + if (ELEM(event->type, LEFTMOUSE)) { + if (event->val == KM_PRESS) { + view3d_interactive_add_begin(C, op, event); + ipd->wait_for_input = false; + return OPERATOR_RUNNING_MODAL; + } + } + return OPERATOR_RUNNING_MODAL; + } + + if (ipd->step_index == STEP_BASE) { + if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) { + if (event->val == KM_RELEASE) { + /* Set secondary plane. */ + + /* Create normal. */ + { + RegionView3D *rv3d = region->regiondata; + float no_temp[3]; + float no[3]; + cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]); + cross_v3_v3v3(no, no_temp, ipd->step[0].plane); + normalize_v3(no); + + plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no); + } + + copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst); + ipd->step_index = STEP_DEPTH; + + /* Keep these values from the previous step. */ + ipd->step[1].is_centered = ipd->step[0].is_centered; + ipd->step[1].is_fixed_aspect = ipd->step[0].is_fixed_aspect; + } + } + } + else if (ipd->step_index == STEP_DEPTH) { + if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) { + if (event->val == KM_PRESS) { + + BoundBox bounds; + calc_bbox(ipd, &bounds); + + float location[3]; + float rotation[3]; + float scale[3]; + + float matrix_orient_axis[3][3]; + copy_m3_m3(matrix_orient_axis, ipd->matrix_orient); + if (ipd->orient_axis != 2) { + swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]); + swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]); + } + /* Needed for shapes where the sign matters (cone for eg). */ + { + float delta[3]; + sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]); + if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) { + negate_v3(matrix_orient_axis[2]); + + /* Only flip Y so we don't flip a single axis which causes problems. */ + negate_v3(matrix_orient_axis[1]); + } + } + + mat3_to_eul(rotation, matrix_orient_axis); + + mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]); + const int cube_verts[3] = {3, 1, 4}; + for (int i = 0; i < 3; i++) { + scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]); + } + + wmOperatorType *ot = NULL; + PointerRNA op_props; + if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) { + ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) { + ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) { + ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_UV) { + ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false); + } + else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_ICO) { + ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false); + } + + if (ot != NULL) { + WM_operator_properties_create_ptr(&op_props, ot); + + if (ipd->use_tool) { + bToolRef *tref = ipd->area->runtime.tool; + PointerRNA temp_props; + WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot); + SWAP(PointerRNA, temp_props, op_props); + WM_operator_properties_free(&temp_props); + } + + RNA_float_set_array(&op_props, "rotation", rotation); + RNA_float_set_array(&op_props, "location", location); + RNA_float_set_array(&op_props, "scale", scale); + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); + WM_operator_properties_free(&op_props); + } + else { + BLI_assert(0); + } + + view3d_interactive_add_exit(C, op); + return OPERATOR_FINISHED; + } + } + } + else { + BLI_assert(0); + } + + if (do_cursor_update) { + const float mval_fl[2] = {UNPACK2(event->mval)}; + + /* Calculate the snap location on mouse-move or when toggling snap. */ + bool is_snap_found_prev = ipd->is_snap_found; + ipd->is_snap_found = false; + if (ipd->use_snap) { + if (ipd->snap_gizmo != NULL) { + ED_gizmotypes_snap_3d_toggle_set(ipd->snap_gizmo, ipd->use_snap); + if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo, + CTX_data_ensure_evaluated_depsgraph(C), + ipd->region, + ipd->v3d, + NULL, + mval_fl, + ipd->snap_co, + NULL)) { + ipd->is_snap_found = true; + } + ED_gizmotypes_snap_3d_toggle_clear(ipd->snap_gizmo); + } + } + + /* Workaround because test_select doesn't run at the same time as the modal operator. */ + if (is_snap_found_prev != ipd->is_snap_found) { + wmGizmoMap *gzmap = ipd->region->gizmo_map; + WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL); + } + + if (ipd->step_index == STEP_BASE) { + if (ipd->is_snap_found) { + closest_to_plane_normalized_v3(ipd->step[0].co_dst, ipd->step[0].plane, ipd->snap_co); + } + else { + if (ED_view3d_win_to_3d_on_plane( + region, ipd->step[0].plane, mval_fl, false, ipd->step[0].co_dst)) { + /* pass */ + } + } + } + else if (ipd->step_index == STEP_DEPTH) { + if (ipd->is_snap_found) { + closest_to_plane_normalized_v3(ipd->step[1].co_dst, ipd->step[1].plane, ipd->snap_co); + } + else { + if (ED_view3d_win_to_3d_on_plane( + region, ipd->step[1].plane, mval_fl, false, ipd->step[1].co_dst)) { + /* pass */ + } + } + + /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */ + float close[3], delta[3]; + closest_to_plane_normalized_v3(close, ipd->step[0].plane, ipd->step[1].co_dst); + sub_v3_v3v3(delta, close, ipd->step[0].co_dst); + sub_v3_v3(ipd->step[1].co_dst, delta); + } + do_redraw = true; + } + + if (do_redraw) { + ED_region_tag_redraw(region); + } + + return OPERATOR_RUNNING_MODAL; +} + +static bool view3d_interactive_add_poll(bContext *C) +{ + const enum eContextObjectMode mode = CTX_data_mode_enum(C); + return ELEM(mode, CTX_MODE_OBJECT, CTX_MODE_EDIT_MESH); +} + +void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Primitive Object"; + ot->description = "Interactively add an object"; + ot->idname = "VIEW3D_OT_interactive_add"; + + /* api callbacks */ + ot->invoke = view3d_interactive_add_invoke; + ot->modal = view3d_interactive_add_modal; + ot->cancel = view3d_interactive_add_cancel; + ot->poll = view3d_interactive_add_poll; + + /* Note, let the operator we call handle undo and registering it's self. */ + /* flags */ + ot->flag = 0; + + /* properties */ + PropertyRNA *prop; + + /* Normally not accessed directly, leave unset and check the active tool. */ + static const EnumPropertyItem primitive_type[] = { + {PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""}, + {PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""}, + {PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""}, + {PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""}, + {PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Primitive", ""); + RNA_def_property_enum_items(prop, primitive_type); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_property(ot->srna, "plane_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Plane Axis", "The axis used for placing the base region"); + RNA_def_property_enum_default(prop, 2); + RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + static const EnumPropertyItem plane_depth_items[] = { + {PLACE_DEPTH_SURFACE, + "SURFACE", + 0, + "Surface", + "Start placing on the surface, using the 3D cursor position as a fallback"}, + {PLACE_DEPTH_CURSOR_PLANE, + "CURSOR_PLANE", + 0, + "3D Cursor Plane", + "Start placement using a point projected onto the selected axis at the 3D cursor position"}, + {PLACE_DEPTH_CURSOR_VIEW, + "CURSOR_VIEW", + 0, + "3D Cursor View", + "Start placement using the mouse cursor projected onto the view plane"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_property(ot->srna, "plane_depth", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Position", "The initial depth used when placing the cursor"); + RNA_def_property_enum_default(prop, PLACE_DEPTH_SURFACE); + RNA_def_property_enum_items(prop, plane_depth_items); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + static const EnumPropertyItem origin_items[] = { + {PLACE_ORIGIN_BASE, "BASE", 0, "Base", "Start placing the corner position"}, + {PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_property(ot->srna, "plane_origin", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Origin", "The initial position for placement"); + RNA_def_property_enum_default(prop, PLACE_ORIGIN_BASE); + RNA_def_property_enum_items(prop, origin_items); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + /* When not accessed via a tool. */ + prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Placement Gizmo Group + * + * This is currently only used for snapping before the tool is initialized, + * we could show a placement plane here. + * \{ */ + +static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + wmGizmo *gizmo; + + { + /* The gizmo snap has to be the first gizmo. */ + const wmGizmoType *gzt_snap; + gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); + gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); + RNA_enum_set(gizmo->ptr, + "snap_elements_force", + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)); + + WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); + + /* Don't handle any events, this is for display only. */ + gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP; + } +} + +void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Placement Widget"; + gzgt->idname = view3d_gzgt_placement_id; + + gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; + + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + + gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; + gzgt->setup = WIDGETGROUP_placement_setup; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 2ce2edb98fe..8c60e36a141 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -411,6 +411,7 @@ typedef struct LassoSelectUserData { const int (*mcoords)[2]; int mcoords_len; eSelectOp sel_op; + eBezTriple_Flag select_flag; /* runtime */ int pass; @@ -434,6 +435,8 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->mcoords = mcoords; r_data->mcoords_len = mcoords_len; r_data->sel_op = sel_op; + /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ + r_data->select_flag = SELECT; /* runtime */ r_data->pass = 0; @@ -903,6 +906,7 @@ static void do_lasso_select_curve__doSelect(void *userData, BPoint *bp, BezTriple *bezt, int beztindex, + bool handles_visible, const float screen_co[2]) { LassoSelectUserData *data = userData; @@ -913,17 +917,17 @@ static void do_lasso_select_curve__doSelect(void *userData, const bool is_select = bp->f1 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag); data->is_changed = true; } } else { - if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { - /* can only be (beztindex == 0) here since handles are hidden */ + if (!handles_visible) { + /* can only be (beztindex == 1) here since handles are hidden */ const bool is_select = bezt->f2 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag); } bezt->f1 = bezt->f3 = bezt->f2; data->is_changed = true; @@ -933,7 +937,7 @@ static void do_lasso_select_curve__doSelect(void *userData, const bool is_select = *flag_p & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag); data->is_changed = true; } } @@ -945,6 +949,7 @@ static bool do_lasso_select_curve(ViewContext *vc, const int mcoords_len, const eSelectOp sel_op) { + const bool deselect_all = (sel_op == SEL_OP_SET); LassoSelectUserData data; rcti rect; @@ -952,13 +957,23 @@ static bool do_lasso_select_curve(ViewContext *vc, view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - Curve *curve = (Curve *)vc->obedit->data; - data.is_changed |= ED_curve_deselect_all(curve->editnurb); + Curve *curve = (Curve *)vc->obedit->data; + ListBase *nurbs = BKE_curve_editNurbs_get(curve); + + /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */ + if (deselect_all) { + BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false); + data.select_flag = BEZT_FLAG_TEMP_TAG; } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + /* Deselect items that were not added to selection (indicated by temp flag). */ + if (deselect_all) { + BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); + } + if (data.is_changed) { BKE_curve_nurb_vert_active_validate(vc->obedit->data); } @@ -2559,6 +2574,7 @@ typedef struct BoxSelectUserData { const rctf *rect_fl; rctf _rect_fl; eSelectOp sel_op; + eBezTriple_Flag select_flag; /* runtime */ bool is_done; @@ -2577,6 +2593,8 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); r_data->sel_op = sel_op; + /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ + r_data->select_flag = SELECT; /* runtime */ r_data->is_done = false; @@ -2707,6 +2725,7 @@ static void do_nurbs_box_select__doSelect(void *userData, BPoint *bp, BezTriple *bezt, int beztindex, + bool handles_visible, const float screen_co[2]) { BoxSelectUserData *data = userData; @@ -2716,17 +2735,17 @@ static void do_nurbs_box_select__doSelect(void *userData, const bool is_select = bp->f1 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag); data->is_changed = true; } } else { - if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { - /* can only be (beztindex == 0) here since handles are hidden */ + if (!handles_visible) { + /* can only be (beztindex == 1) here since handles are hidden */ const bool is_select = bezt->f2 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag); data->is_changed = true; } bezt->f1 = bezt->f3 = bezt->f2; @@ -2736,7 +2755,7 @@ static void do_nurbs_box_select__doSelect(void *userData, const bool is_select = *flag_p & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag); data->is_changed = true; } } @@ -2744,17 +2763,28 @@ static void do_nurbs_box_select__doSelect(void *userData, } static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) { + const bool deselect_all = (sel_op == SEL_OP_SET); BoxSelectUserData data; view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - Curve *curve = (Curve *)vc->obedit->data; - data.is_changed |= ED_curve_deselect_all(curve->editnurb); + Curve *curve = (Curve *)vc->obedit->data; + ListBase *nurbs = BKE_curve_editNurbs_get(curve); + + /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */ + if (deselect_all) { + BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false); + data.select_flag = BEZT_FLAG_TEMP_TAG; } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + /* Deselect items that were not added to selection (indicated by temp flag). */ + if (deselect_all) { + BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); + } + BKE_curve_nurb_vert_active_validate(vc->obedit->data); return data.is_changed; @@ -3393,6 +3423,7 @@ typedef struct CircleSelectUserData { float mval_fl[2]; float radius; float radius_squared; + eBezTriple_Flag select_flag; /* runtime */ bool is_changed; @@ -3413,6 +3444,9 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, r_data->radius = rad; r_data->radius_squared = rad * rad; + /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ + r_data->select_flag = SELECT; + /* runtime */ r_data->is_changed = false; } @@ -3650,29 +3684,24 @@ static void nurbscurve_circle_doSelect(void *userData, BPoint *bp, BezTriple *bezt, int beztindex, + bool UNUSED(handles_visible), const float screen_co[2]) { CircleSelectUserData *data = userData; if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { if (bp) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + SET_FLAG_FROM_TEST(bp->f1, data->select, data->select_flag); } else { - if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { - /* can only be (beztindex == 0) here since handles are hidden */ - bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); + if (beztindex == 0) { + SET_FLAG_FROM_TEST(bezt->f1, data->select, data->select_flag); + } + else if (beztindex == 1) { + SET_FLAG_FROM_TEST(bezt->f2, data->select, data->select_flag); } else { - if (beztindex == 0) { - bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT); - } - else if (beztindex == 1) { - bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); - } - else { - bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT); - } + SET_FLAG_FROM_TEST(bezt->f3, data->select, data->select_flag); } } data->is_changed = true; @@ -3683,18 +3712,30 @@ static bool nurbscurve_circle_select(ViewContext *vc, const int mval[2], float rad) { + const bool select = (sel_op != SEL_OP_SUB); + const bool deselect_all = (sel_op == SEL_OP_SET); CircleSelectUserData data; bool changed = false; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - Curve *curve = vc->obedit->data; - changed |= ED_curve_deselect_all(curve->editnurb); - } - const bool select = (sel_op != SEL_OP_SUB); view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + Curve *curve = (Curve *)vc->obedit->data; + ListBase *nurbs = BKE_curve_editNurbs_get(curve); + + /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */ + if (deselect_all) { + BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false); + data.select_flag = BEZT_FLAG_TEMP_TAG; + } + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + /* Deselect items that were not added to selection (indicated by temp flag). */ + if (deselect_all) { + BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT); + } + BKE_curve_nurb_vert_active_validate(vc->obedit->data); return changed || data.is_changed; diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 09e1dca3152..377e8c58ba3 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -86,6 +86,26 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float UI_GetThemeColor3fv(TH_BACK, r_color); } +bool ED_view3d_has_workbench_in_texture_color(const Scene *scene, + const Object *ob, + const View3D *v3d) +{ + if (v3d->shading.type == OB_SOLID) { + if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) { + return true; + } + if (ob->mode == OB_MODE_TEXTURE_PAINT) { + return true; + } + } + else if (v3d->shading.type == OB_RENDER) { + if (STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH)) { + return scene->display.shading.color_type == V3D_SHADING_TEXTURE_COLOR; + } + } + return false; +} + Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) { /* establish the camera object, diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 8ee52756f27..7aefd173953 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -374,16 +374,19 @@ static bool walk_floor_distance_get(RegionView3D *rv3d, mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(ray_start, dvec_tmp); - ret = ED_transform_snap_object_project_ray(walk->snap_context, - walk->depsgraph, - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - }, - ray_start, - ray_normal, - r_distance, - r_location, - r_normal_dummy); + ret = ED_transform_snap_object_project_ray( + walk->snap_context, + walk->depsgraph, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + /* Avoid having to convert the edit-mesh to a regular mesh. */ + .use_object_edit_cage = true, + }, + ray_start, + ray_normal, + r_distance, + r_location, + r_normal_dummy); /* artificially scale the distance to the scene size */ *r_distance /= walk->grid; @@ -449,7 +452,6 @@ static float userdef_speed = -1.f; static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); - Main *bmain = CTX_data_main(C); wmWindow *win = CTX_wm_window(C); walk->rv3d = CTX_wm_region_view3d(C); @@ -553,7 +555,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; walk->snap_context = ED_transform_snap_object_context_create_view3d( - bmain, walk->scene, 0, walk->region, walk->v3d); + walk->scene, 0, walk->region, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( walk->depsgraph, diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 8e3ad55bae1..5fc65522fe6 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -825,17 +825,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is } } else if (!edit_2d) { - if (t->orientation.index == 0 || ELEM(cmode, '\0', axis)) { + if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) { /* Successive presses on existing axis, cycle orientation modes. */ - t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); - initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); + transform_orientations_current_set(t, t->orient_curr); } - if (t->orientation.index == 0) { + if (t->orient_curr == 0) { stopConstraint(t); } else { - const short orientation = t->orientation.types[t->orientation.index]; + const short orientation = t->orient[t->orient_curr].type; if (is_plane == false) { setUserConstraint(t, orientation, constraint_axis, msg2); } @@ -896,74 +896,59 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_TRANSLATE: /* only switch when... */ - if (ELEM(t->mode, - TFM_ROTATION, - TFM_RESIZE, - TFM_TRACKBALL, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { - restoreTransObjects(t); - resetTransModal(t); - resetTransRestrictions(t); - transform_mode_init(t, NULL, TFM_TRANSLATION); - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - handled = true; - } - else if (t->mode == TFM_SEQ_SLIDE) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - else { - if (t->obedit_type == OB_MESH) { - if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) { - restoreTransObjects(t); + if (t->mode == TFM_TRANSLATION) { + if ((t->obedit_type == OB_MESH) && (t->spacetype == SPACE_VIEW3D)) { + restoreTransObjects(t); + resetTransModal(t); + resetTransRestrictions(t); + + /* first try edge slide */ + transform_mode_init(t, NULL, TFM_EDGE_SLIDE); + /* if that fails, do vertex slide */ + if (t->state == TRANS_CANCEL) { resetTransModal(t); + t->state = TRANS_STARTING; + transform_mode_init(t, NULL, TFM_VERT_SLIDE); + } + /* vert slide can fail on unconnected vertices (rare but possible) */ + if (t->state == TRANS_CANCEL) { + resetTransModal(t); + t->state = TRANS_STARTING; + restoreTransObjects(t); resetTransRestrictions(t); - - /* first try edge slide */ - transform_mode_init(t, NULL, TFM_EDGE_SLIDE); - /* if that fails, do vertex slide */ - if (t->state == TRANS_CANCEL) { - resetTransModal(t); - t->state = TRANS_STARTING; - transform_mode_init(t, NULL, TFM_VERT_SLIDE); - } - /* vert slide can fail on unconnected vertices (rare but possible) */ - if (t->state == TRANS_CANCEL) { - resetTransModal(t); - t->state = TRANS_STARTING; - restoreTransObjects(t); - resetTransRestrictions(t); - transform_mode_init(t, NULL, TFM_TRANSLATION); - } - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - handled = true; + transform_mode_init(t, NULL, TFM_TRANSLATION); } + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + handled = true; } else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) { - if (t->mode == TFM_TRANSLATION) { - restoreTransObjects(t); + restoreTransObjects(t); - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; } } + else if (t->mode == TFM_SEQ_SLIDE) { + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + else if (transform_mode_is_changeable(t->mode)) { + restoreTransObjects(t); + resetTransModal(t); + resetTransRestrictions(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + handled = true; + } break; case TFM_MODAL_ROTATE: /* only switch when... */ if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) { - if (ELEM(t->mode, - TFM_ROTATION, - TFM_RESIZE, - TFM_TRACKBALL, - TFM_TRANSLATION, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { + if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -982,15 +967,23 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_RESIZE: /* only switch when... */ - if (ELEM(t->mode, - TFM_ROTATION, - TFM_TRANSLATION, - TFM_TRACKBALL, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { + if (t->mode == TFM_RESIZE) { + if (t->options & CTX_MOVIECLIP) { + restoreTransObjects(t); + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + } + else if (t->mode == TFM_SHRINKFATTEN) { + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + else if (transform_mode_is_changeable(t->mode)) { /* Scale isn't normally very useful after extrude along normals, see T39756 */ - if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) { + if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) { stopConstraint(t); } @@ -1002,20 +995,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw |= TREDRAW_HARD; handled = true; } - else if (t->mode == TFM_SHRINKFATTEN) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - else if (t->mode == TFM_RESIZE) { - if (t->options & CTX_MOVIECLIP) { - restoreTransObjects(t); - - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - } break; case TFM_MODAL_SNAP_INV_ON: @@ -1229,7 +1208,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; } /* only switch when... */ - if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { + if (t->mode != TFM_TRANSLATION && transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1244,7 +1223,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; } /* only switch when... */ - if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) { + if (t->mode != TFM_RESIZE && transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1260,7 +1239,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) } /* only switch when... */ if (!(t->options & CTX_TEXTURE)) { - if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) { + if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1615,6 +1594,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) int proportional = 0; PropertyRNA *prop; + if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) && + ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) { + /* When redoing these modes the first time, it's more convenient to save + * the Global orientation. */ + mul_m3_v3(t->spacemtx, t->values_final); + unit_m3(t->spacemtx); + + BLI_assert(t->orient_curr == 0); + t->orient[0].type = V3D_ORIENT_GLOBAL; + } + // Save back mode in case we're in the generic operator if ((prop = RNA_struct_find_property(op->ptr, "mode"))) { RNA_property_enum_set(op->ptr, prop, t->mode); @@ -1723,19 +1713,20 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) { - short orient_set, orient_cur; - orient_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : -1; - orient_cur = t->orientation.types[t->orientation.index]; + short orient_type_set, orient_type_curr; + orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : + -1; + orient_type_curr = t->orient[t->orient_curr].type; - if (!ELEM(orient_cur, orient_set, V3D_ORIENT_CUSTOM_MATRIX)) { - RNA_property_enum_set(op->ptr, prop, orient_cur); - orient_set = orient_cur; + if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) { + RNA_property_enum_set(op->ptr, prop, orient_type_curr); + orient_type_set = orient_type_curr; } if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && !RNA_property_is_set(op->ptr, prop))) { /* Set the first time to register on redo. */ - RNA_property_enum_set(op->ptr, prop, orient_set); + RNA_property_enum_set(op->ptr, prop, orient_type_set); RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); } } @@ -1883,11 +1874,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initTransInfo(C, t, op, event); /* Use the custom orientation when it is set. */ - short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ? - V3D_ORIENT_CUSTOM_MATRIX : - t->orientation.types[t->orientation.index]; - - initTransformOrientation(C, t, orientation); + short orient_index = t->orient[0].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr; + transform_orientations_current_set(t, orient_index); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( @@ -2043,7 +2031,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* Constraint init from operator */ if (t->con.mode & CON_APPLY) { - setUserConstraint(t, t->orientation.types[t->orientation.index], t->con.mode, "%s"); + setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s"); } /* Don't write into the values when non-modal because they are already set from operator redo diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 503e7bd4691..7720660e2e8 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -113,13 +113,8 @@ typedef struct TransSnap { } TransSnap; typedef struct TransCon { - short orientation; /** Description of the constraint for header_print. */ char text[50]; - /** Matrix of the constraint space. */ - float mtx[3][3]; - /** Inverse matrix of the constraint space. */ - float imtx[3][3]; /** Projection constraint matrix (same as #imtx with some axis == 0). */ float pmtx[3][3]; /** Initial mouse value for visual calculation @@ -139,8 +134,7 @@ typedef struct TransCon { struct TransDataContainer *tc, struct TransData *td, const float in[3], - float out[3], - float pvec[3]); + float out[3]); /** Apply function pointer for size transformation. */ void (*applySize)(struct TransInfo *t, struct TransDataContainer *tc, @@ -520,6 +514,7 @@ typedef struct TransInfo { /** orientation matrix of the current space. */ float spacemtx[3][3]; + float spacemtx_inv[3][3]; /** name of the current space, MAX_NAME. */ char spacename[64]; @@ -531,13 +526,11 @@ typedef struct TransInfo { bool is_launch_event_tweak; struct { - short index; - short types[3]; - /* this gets used when orientation.type[x] is V3D_ORIENT_CUSTOM */ - struct TransformOrientation *custom; - /* this gets used when orientation.type[0] is V3D_ORIENT_CUSTOM_MATRIX */ - float custom_matrix[3][3]; - } orientation; + short type; + float matrix[3][3]; + } orient[3]; + short orient_curr; + /** backup from view3d, to restore on end. */ short gizmo_flag; @@ -911,8 +904,13 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3]); void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot); /*********************** Transform Orientations ******************************/ - -void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation); +short transform_orientation_matrix_get(struct bContext *C, + TransInfo *t, + const short orientation, + const float custom[3][3], + float r_spacemtx[3][3]); +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type); +void transform_orientations_current_set(struct TransInfo *t, const short orient_index); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat[3][3], const float normal[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index b07eb6edf5a..0a6e0d6b7f5 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -42,6 +42,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_scene.h" #include "ED_view3d.h" @@ -57,6 +58,27 @@ static void drawObjectConstraint(TransInfo *t); +static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3]) +{ + unit_m3(r_pmtx); + + if (!(t->con.mode & CON_AXIS0)) { + zero_v3(r_pmtx[0]); + } + + if (!(t->con.mode & CON_AXIS1)) { + zero_v3(r_pmtx[1]); + } + + if (!(t->con.mode & CON_AXIS2)) { + zero_v3(r_pmtx[2]); + } + + float mat[3][3]; + mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv); + mul_m3_m3m3(r_pmtx, t->spacemtx, mat); +} + /* ************************** CONSTRAINTS ************************* */ static void constraintValuesFinal(TransInfo *t, float vec[3]) { @@ -121,11 +143,9 @@ void constraintNumInput(TransInfo *t, float vec[3]) } } -static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) +static void postConstraintChecks(TransInfo *t, float vec[3]) { - int i = 0; - - mul_m3_v3(t->con.imtx, vec); + mul_m3_v3(t->spacemtx_inv, vec); snapGridIncrement(t, vec); @@ -155,17 +175,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) /* inverse transformation at the end */ } - if (t->con.mode & CON_AXIS0) { - pvec[i++] = vec[0]; - } - if (t->con.mode & CON_AXIS1) { - pvec[i++] = vec[1]; - } - if (t->con.mode & CON_AXIS2) { - pvec[i++] = vec[2]; - } - - mul_m3_v3(t->con.mtx, vec); + mul_m3_v3(t->spacemtx, vec); } static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3]) @@ -298,7 +308,7 @@ static bool isPlaneProjectionViewAligned(const TransInfo *t) int n = 0; for (int i = 0; i < 3; i++) { if (t->con.mode & (CON_AXIS0 << i)) { - constraint_vector[n++] = t->con.mtx[i]; + constraint_vector[n++] = t->spacemtx[i]; if (n == 2) { break; } @@ -346,12 +356,8 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3]) * (in perspective mode, the view vector is relative to the position on screen) */ -static void applyAxisConstraintVec(TransInfo *t, - TransDataContainer *UNUSED(tc), - TransData *td, - const float in[3], - float out[3], - float pvec[3]) +static void applyAxisConstraintVec( + TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3]) { copy_v3_v3(out, in); if (!td && t->con.mode & CON_APPLY) { @@ -371,25 +377,25 @@ static void applyAxisConstraintVec(TransInfo *t, float c[3]; if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); + copy_v3_v3(c, t->spacemtx[0]); } else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); + copy_v3_v3(c, t->spacemtx[1]); } else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); + copy_v3_v3(c, t->spacemtx[2]); } axisProjection(t, c, in, out); } } - postConstraintChecks(t, out, pvec); + postConstraintChecks(t, out); } } /* * Generic callback for object based spatial constraints applied to linear motion * - * At first, the following is applied to the first data in the array + * At first, the following is applied without orientation * The IN vector in projected into the constrained space and then further * projected along the view vector. * (in perspective mode, the view vector is relative to the position on screen) @@ -397,61 +403,19 @@ static void applyAxisConstraintVec(TransInfo *t, * Further down, that vector is mapped to each data's space. */ -static void applyObjectConstraintVec(TransInfo *t, - TransDataContainer *tc, - TransData *td, - const float in[3], - float out[3], - float pvec[3]) +static void applyObjectConstraintVec( + TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3]) { - copy_v3_v3(out, in); - if (t->con.mode & CON_APPLY) { - if (!td) { - mul_m3_v3(t->con.pmtx, out); - - const int dims = getConstraintSpaceDimension(t); - if (dims == 2) { - if (!is_zero_v3(out)) { - if (!isPlaneProjectionViewAligned(t)) { - planeProjection(t, in, out); - } - } - } - else if (dims == 1) { - float c[3]; - - if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); - } - else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); - } - else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); - } - axisProjection(t, c, in, out); - } - postConstraintChecks(t, out, pvec); - copy_v3_v3(out, pvec); - } - else { - int i = 0; - - out[0] = out[1] = out[2] = 0.0f; - if (t->con.mode & CON_AXIS0) { - out[0] = in[i++]; - } - if (t->con.mode & CON_AXIS1) { - out[1] = in[i++]; - } - if (t->con.mode & CON_AXIS2) { - out[2] = in[i++]; - } - - mul_m3_v3(td->axismtx, out); - if (t->flag & T_EDIT) { - mul_m3_v3(tc->mat3_unit, out); - } + if (!td) { + applyAxisConstraintVec(t, tc, td, in, out); + } + else { + /* Specific TransData's space. */ + copy_v3_v3(out, in); + mul_m3_v3(t->spacemtx_inv, out); + mul_m3_v3(td->axismtx, out); + if (t->flag & T_EDIT) { + mul_m3_v3(tc->mat3_unit, out); } } } @@ -478,8 +442,8 @@ static void applyAxisConstraintSize(TransInfo *t, smat[2][2] = 1.0f; } - mul_m3_m3m3(tmat, smat, t->con.imtx); - mul_m3_m3m3(smat, t->con.mtx, tmat); + mul_m3_m3m3(tmat, smat, t->spacemtx_inv); + mul_m3_m3m3(smat, t->spacemtx, tmat); } } @@ -539,15 +503,15 @@ static void applyAxisConstraintRot( switch (mode) { case CON_AXIS0: case (CON_AXIS1 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[0]); + copy_v3_v3(vec, t->spacemtx[0]); break; case CON_AXIS1: case (CON_AXIS0 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[1]); + copy_v3_v3(vec, t->spacemtx[1]); break; case CON_AXIS2: case (CON_AXIS0 | CON_AXIS1): - copy_v3_v3(vec, t->con.mtx[2]); + copy_v3_v3(vec, t->spacemtx[2]); break; } /* don't flip axis if asked to or if num input */ @@ -620,12 +584,11 @@ static void applyObjectConstraintRot( /*--------------------- INTERNAL SETUP CALLS ------------------*/ -void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) +void setConstraint(TransInfo *t, int mode, const char text[]) { BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - copy_m3_m3(t->con.mtx, space); t->con.mode = mode; - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); startConstraint(t); @@ -639,41 +602,25 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) /* applies individual td->axismtx constraints */ void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) { - TransDataContainer *tc = t->data_container; - if (t->data_len_all == 1) { - float axismtx[3][3]; - if (t->flag & T_EDIT) { - mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx); - } - else { - copy_m3_m3(axismtx, tc->data->axismtx); - } - - setConstraint(t, axismtx, mode, text); - } - else { - BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - copy_m3_m3(t->con.mtx, tc->data->axismtx); - t->con.mode = mode; - getConstraintMatrix(t); + BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); + t->con.mode = mode; + projection_matrix_calc(t, t->con.pmtx); - startConstraint(t); + startConstraint(t); - t->con.drawExtra = drawObjectConstraint; - t->con.applyVec = applyObjectConstraintVec; - t->con.applySize = applyObjectConstraintSize; - t->con.applyRot = applyObjectConstraintRot; - t->redraw = TREDRAW_HARD; - } + t->con.drawExtra = drawObjectConstraint; + t->con.applyVec = applyObjectConstraintVec; + t->con.applySize = applyObjectConstraintSize; + t->con.applyRot = applyObjectConstraintRot; + t->redraw = TREDRAW_HARD; } void setLocalConstraint(TransInfo *t, int mode, const char text[]) { - /* edit-mode now allows local transforms too */ if (t->flag & T_EDIT) { - /* Use the active (first) edit object. */ - TransDataContainer *tc = t->data_container; - setConstraint(t, tc->mat3_unit, mode, text); + /* Although in edit-mode each object has its local space, use the + * orientation of the active object. */ + setConstraint(t, mode, text); } else { setAxisMatrixConstraint(t, mode, text); @@ -689,64 +636,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[]) { char text[256]; + const char *spacename = transform_orientations_spacename_get(t, orientation); + BLI_snprintf(text, sizeof(text), ftext, spacename); switch (orientation) { - case V3D_ORIENT_GLOBAL: { - float mtx[3][3]; - BLI_snprintf(text, sizeof(text), ftext, TIP_("global")); - unit_m3(mtx); - setConstraint(t, mtx, mode, text); - break; - } case V3D_ORIENT_LOCAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("local")); setLocalConstraint(t, mode, text); break; case V3D_ORIENT_NORMAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("normal")); if (checkUseAxisMatrix(t)) { setAxisMatrixConstraint(t, mode, text); + break; } - else { - setConstraint(t, t->spacemtx, mode, text); - } - break; + ATTR_FALLTHROUGH; + case V3D_ORIENT_GLOBAL: case V3D_ORIENT_VIEW: - BLI_snprintf(text, sizeof(text), ftext, TIP_("view")); - float mtx[3][3]; - copy_m3_m3(mtx, t->spacemtx); - negate_v3(mtx[2]); - setConstraint(t, mtx, mode, text); - break; case V3D_ORIENT_CURSOR: - BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_GIMBAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CUSTOM_MATRIX: - BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CUSTOM: default: { - BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - char orientation_str[128]; - BLI_snprintf(orientation_str, - sizeof(orientation_str), - "%s \"%s\"", - TIP_("custom orientation"), - t->orientation.custom->name); - BLI_snprintf(text, sizeof(text), ftext, orientation_str); - setConstraint(t, t->spacemtx, mode, text); + setConstraint(t, mode, text); break; } } - - t->con.orientation = orientation; - t->con.mode |= CON_USER; } @@ -777,9 +690,9 @@ void drawConstraint(TransInfo *t) convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); add_v3_v3(vec, t->center_global); - drawLine(t, t->center_global, tc->mtx[0], 'X', 0); - drawLine(t, t->center_global, tc->mtx[1], 'Y', 0); - drawLine(t, t->center_global, tc->mtx[2], 'Z', 0); + drawLine(t, t->center_global, t->spacemtx[0], 'X', 0); + drawLine(t, t->center_global, t->spacemtx[1], 'Y', 0); + drawLine(t, t->center_global, t->spacemtx[2], 'Z', 0); depth_test_enabled = GPU_depth_test_enabled(); if (depth_test_enabled) { @@ -813,13 +726,13 @@ void drawConstraint(TransInfo *t) } if (tc->mode & CON_AXIS0) { - drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[0], 'X', DRAWLIGHT); } if (tc->mode & CON_AXIS1) { - drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[1], 'Y', DRAWLIGHT); } if (tc->mode & CON_AXIS2) { - drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[2], 'Z', DRAWLIGHT); } } } @@ -965,28 +878,6 @@ void stopConstraint(TransInfo *t) t->num.idx_max = t->idx_max; } -void getConstraintMatrix(TransInfo *t) -{ - float mat[3][3]; - invert_m3_m3(t->con.imtx, t->con.mtx); - unit_m3(t->con.pmtx); - - if (!(t->con.mode & CON_AXIS0)) { - zero_v3(t->con.pmtx[0]); - } - - if (!(t->con.mode & CON_AXIS1)) { - zero_v3(t->con.pmtx[1]); - } - - if (!(t->con.mode & CON_AXIS2)) { - zero_v3(t->con.pmtx[2]); - } - - mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); - mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat); -} - /*------------------------- MMB Select -------------------------------*/ void initSelectConstraint(TransInfo *t, bool force_global) @@ -996,11 +887,11 @@ void initSelectConstraint(TransInfo *t, bool force_global) orientation = V3D_ORIENT_GLOBAL; } else { - if (t->orientation.index == 0) { - t->orientation.index = 1; - initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]); + if (t->orient_curr == 0) { + t->orient_curr = 1; + transform_orientations_current_set(t, t->orient_curr); } - orientation = t->orientation.types[t->orientation.index]; + orientation = t->orient[t->orient_curr].type; } setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, ""); @@ -1070,7 +961,7 @@ static void setNearestAxis3d(TransInfo *t) for (i = 0; i < 3; i++) { float axis[3], axis_2d[2]; - copy_v3_v3(axis, t->con.mtx[i]); + copy_v3_v3(axis, t->spacemtx[i]); mul_v3_fl(axis, zfac); /* now we can project to get window coordinate */ @@ -1139,7 +1030,7 @@ void setNearestAxis(TransInfo *t) setNearestAxis2d(t); } - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); } /*-------------- HELPER FUNCTIONS ----------------*/ diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index c98234c83da..b57a7599321 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -27,7 +27,7 @@ struct TransInfo; void constraintNumInput(TransInfo *t, float vec[3]); -void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]); +void setConstraint(TransInfo *t, int mode, const char text[]); void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); void setLocalConstraint(TransInfo *t, int mode, const char text[]); void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]); @@ -35,7 +35,6 @@ void drawConstraint(TransInfo *t); void drawPropCircle(const struct bContext *C, TransInfo *t); void startConstraint(TransInfo *t); void stopConstraint(TransInfo *t); -void getConstraintMatrix(TransInfo *t); void initSelectConstraint(TransInfo *t, bool force_global); void selectConstraint(TransInfo *t); void postSelectConstraint(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index d6875f173e3..b91542a80fc 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1848,7 +1848,10 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t) if (IS_AUTOKEY_ON(t->scene)) { Scene *scene = t->scene; - ED_mask_layer_shape_auto_key_select(mask, CFRA); + if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) { + WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); + DEG_id_tag_update(&mask->id, 0); + } } } @@ -1869,6 +1872,7 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t) nodeRemoveNode(bmain, ntree, node, true); } } + ntreeUpdateTree(bmain, ntree); } } } diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 42ffe675dc5..1f113a36a89 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -93,9 +93,8 @@ void createTransCurveVerts(TransInfo *t) int count = 0, countsel = 0; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; View3D *v3d = t->view; - short hide_handles = (v3d != NULL) ? - ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : - false; + short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) : + false; /* count total of vertices, check identical as in 2nd loop for making transdata! */ ListBase *nurbs = BKE_curve_editNurbs_get(cu); @@ -163,9 +162,8 @@ void createTransCurveVerts(TransInfo *t) int a; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; View3D *v3d = t->view; - short hide_handles = (v3d != NULL) ? - ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : - false; + short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) : + false; bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) && transform_mode_use_local_origins(t)); diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 24dda8c8464..07b2f07bf2c 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1450,7 +1450,6 @@ static void UVsToTransData(const float aspect[2], void createTransUVs(bContext *C, TransInfo *t) { SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); Scene *scene = t->scene; ToolSettings *ts = CTX_data_tool_settings(C); @@ -1500,7 +1499,7 @@ void createTransUVs(bContext *C, TransInfo *t) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BMLoop *l; - if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { BM_elem_flag_disable(efa, BM_ELEM_TAG); continue; } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 4472facf183..b1e69dde0ac 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1626,7 +1626,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) { - /* For operators whose `t->values` is array, set contrain so that the + /* For operators whose `t->values` is array, set constraint so that the * orientation is more intuitive in the Redo Panel. */ for (int i = 3; i--;) { constraint_axis[i] |= t->values[i] != 0.0f; @@ -1650,25 +1650,21 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve { TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - TransformOrientation *custom_orientation = NULL; short orient_type_set = -1; short orient_type_matrix_set = -1; short orient_type_scene = orient_slot->type; if (orient_type_scene == V3D_ORIENT_CUSTOM) { const int index_custom = orient_slot->index_custom; - custom_orientation = BKE_scene_transform_orientation_find(t->scene, index_custom); orient_type_scene += index_custom; } - short orient_type_default = V3D_ORIENT_GLOBAL; - short orient_type_constraint[2]; + short orient_types[3]; + float custom_matrix[3][3]; + bool use_orient_axis = false; if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { t->orient_axis = RNA_property_enum_get(op->ptr, prop); - - /* For transfor modes that require "orient_axis" use - * `V3D_ORIENT_VIEW` as default. */ - orient_type_default = V3D_ORIENT_VIEW; + use_orient_axis = true; } if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); @@ -1681,26 +1677,28 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { orient_type_set = V3D_ORIENT_GLOBAL; } - else { - custom_orientation = BKE_scene_transform_orientation_find( - t->scene, orient_type_default - V3D_ORIENT_CUSTOM); - } } /* Change the default orientation to be used when redoing. */ - orient_type_default = orient_type_set; - orient_type_constraint[0] = orient_type_set; - orient_type_constraint[1] = orient_type_scene; + orient_types[0] = orient_type_set; + orient_types[1] = orient_type_set; + orient_types[2] = orient_type_scene; } else { - orient_type_constraint[0] = orient_type_scene; - orient_type_constraint[1] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : - V3D_ORIENT_LOCAL; + if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) { + orient_types[0] = V3D_ORIENT_VIEW; + } + else { + orient_types[0] = orient_type_scene; + } + orient_types[1] = orient_type_scene; + orient_types[2] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : + V3D_ORIENT_LOCAL; } if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && RNA_property_is_set(op->ptr, prop))) { - RNA_property_float_get_array(op->ptr, prop, &t->orientation.custom_matrix[0][0]); + RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]); if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && RNA_property_is_set(op->ptr, prop)) { @@ -1715,18 +1713,30 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (orient_type_matrix_set == orient_type_set) { /* Constraints are forced to use the custom matrix when redoing. */ - orient_type_default = V3D_ORIENT_CUSTOM_MATRIX; + orient_types[0] = V3D_ORIENT_CUSTOM_MATRIX; } } - t->orientation.types[0] = orient_type_default; - t->orientation.types[1] = orient_type_constraint[0]; - t->orientation.types[2] = orient_type_constraint[1]; - t->orientation.custom = custom_orientation; - if (t->con.mode & CON_APPLY) { - t->orientation.index = 1; + t->orient_curr = 1; } + + /* For efficiency, avoid calculating the same orientation twice. */ + for (int i = 1; i < 3; i++) { + t->orient[i].type = transform_orientation_matrix_get( + C, t, orient_types[i], custom_matrix, t->orient[i].matrix); + } + + if (orient_types[0] != orient_types[1]) { + t->orient[0].type = transform_orientation_matrix_get( + C, t, orient_types[0], custom_matrix, t->orient[0].matrix); + } + else { + memcpy(&t->orient[0], &t->orient[1], sizeof(t->orient[0])); + } + + const char *spacename = transform_orientations_spacename_get(t, orient_types[0]); + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c index 50317d8b395..c63e90ac2b7 100644 --- a/source/blender/editors/transform/transform_gizmo_2d.c +++ b/source/blender/editors/transform/transform_gizmo_2d.c @@ -217,14 +217,12 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min ScrArea *area = CTX_wm_area(C); bool changed = false; if (area->spacetype == SPACE_IMAGE) { - SpaceImage *sima = area->spacedata.first; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = ED_space_image(sima); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, NULL, &objects_len); - if (ED_uvedit_minmax_multi(scene, ima, objects, objects_len, r_min, r_max)) { + if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) { changed = true; } MEM_freeN(objects); diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index b575030778f..04be7048791 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -929,7 +929,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, * if handles are hidden then only check the center points. * If the center knot is selected then only use this as the center point. */ - if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { + if (v3d->overlay.handle_display == CURVE_HANDLE_NONE) { if (bezt->f2 & SELECT) { calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local); totsel++; @@ -1390,21 +1390,21 @@ void drawDial3d(const TransInfo *t) if (tc->mode & CON_APPLY) { if (tc->mode & CON_AXIS0) { axis_idx = MAN_AXIS_ROT_X; - negate_v3_v3(mat_basis[2], tc->mtx[0]); + negate_v3_v3(mat_basis[2], t->spacemtx[0]); } else if (tc->mode & CON_AXIS1) { axis_idx = MAN_AXIS_ROT_Y; - negate_v3_v3(mat_basis[2], tc->mtx[1]); + negate_v3_v3(mat_basis[2], t->spacemtx[1]); } else { BLI_assert((tc->mode & CON_AXIS2) != 0); axis_idx = MAN_AXIS_ROT_Z; - negate_v3_v3(mat_basis[2], tc->mtx[2]); + negate_v3_v3(mat_basis[2], t->spacemtx[2]); } } else { axis_idx = MAN_AXIS_ROT_C; - negate_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]); + copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]); scale *= 1.2f; line_with -= 1.0f; } @@ -2201,6 +2201,15 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); } else { + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + if (ob && ob->mode & OB_MODE_EDIT) { + copy_m4_m4(gz->matrix_space, ob->obmat); + } + else { + unit_m4(gz->matrix_space); + } + gizmo_prepare_mat(C, rv3d, &tbounds); WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); @@ -2258,15 +2267,6 @@ static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C, static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata; - wmGizmo *gz = xgzgroup->gizmo; - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - if (ob && ob->mode & OB_MODE_EDIT) { - copy_m4_m4(gz->matrix_space, ob->obmat); - } - else { - unit_m4(gz->matrix_space); - } RegionView3D *rv3d = CTX_wm_region_view3d(C); { diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 4c14c3aebd7..c2c880b03ff 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -61,6 +61,18 @@ bool transdata_check_local_center(TransInfo *t, short around) (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))); } +/* Informs if the mode can be switched during modal. */ +bool transform_mode_is_changeable(const int mode) +{ + return ELEM(mode, + TFM_ROTATION, + TFM_RESIZE, + TFM_TRACKBALL, + TFM_TRANSLATION, + TFM_EDGE_SLIDE, + TFM_VERT_SLIDE); +} + /* -------------------------------------------------------------------- */ /** \name Transform Locks * \{ */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 6180f6d3477..074e89390c2 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -41,6 +41,7 @@ typedef struct TransDataGenericSlideVert { /* transform_mode.c */ bool transdata_check_local_center(TransInfo *t, short around); +bool transform_mode_is_changeable(const int mode); void protectedTransBits(short protectflag, float vec[3]); void constraintTransLim(TransInfo *t, TransData *td); void postInputRotation(TransInfo *t, float values[3]); diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index ee91459dcdd..8690cd54a3b 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -101,9 +101,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2]) snapSequenceBounds(t, mval); if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; float tvec[3]; - t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec); + t->con.applyVec(t, NULL, NULL, t->values, tvec); copy_v3_v3(t->values_final, tvec); } else { diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index f52bfda0d14..55c97630487 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -146,7 +146,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) snapGridIncrement(t, &final); float axis_final[3]; - copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); + /* Use the negative axis to match the default Z axis of the view matrix. */ + negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, NULL); diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index da34bf50ba3..3eeb8a1e758 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -56,14 +56,14 @@ static void initShear_mouseInputMode(TransInfo *t) copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]); /* Needed for axis aligned view gizmo. */ - if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) { + if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) { if (t->orient_axis_ortho == 0) { - if (t->center2d[1] < t->mouse.imval[1]) { + if (t->center2d[1] > t->mouse.imval[1]) { dir_flip = !dir_flip; } } else if (t->orient_axis_ortho == 1) { - if (t->center2d[0] < t->mouse.imval[0]) { + if (t->center2d[0] > t->mouse.imval[0]) { dir_flip = !dir_flip; } } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 0a7d8bd90d3..69552eda5bf 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -277,8 +277,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) } if (t->con.applyVec) { - float pvec[3]; - t->con.applyVec(t, tc, td, vec, tvec, pvec); + t->con.applyVec(t, tc, td, vec, tvec); } else { copy_v3_v3(tvec, vec); @@ -319,45 +318,39 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; - float values_final[3]; + float global_dir[3]; if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); + mul_v3_m3v3(global_dir, t->spacemtx, t->values); } else { - copy_v3_v3(t->values_final, t->values); + copy_v3_v3(global_dir, t->values); if ((t->con.mode & CON_APPLY) == 0) { - snapGridIncrement(t, t->values_final); + snapGridIncrement(t, global_dir); } - if (applyNumInput(&t->num, t->values_final)) { - removeAspectRatio(t, t->values_final); + if (applyNumInput(&t->num, global_dir)) { + removeAspectRatio(t, global_dir); } - applySnapping(t, t->values_final); + applySnapping(t, global_dir); } - copy_v3_v3(values_final, t->values_final); if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; - t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec); - headerTranslation(t, pvec, str); - - /* only so we have re-usable value with redo, see T46741. */ - mul_v3_m3v3(t->values_final, t->con.imtx, values_final); + float in[3]; + copy_v3_v3(in, global_dir); + t->con.applyVec(t, NULL, NULL, in, global_dir); + headerTranslation(t, global_dir, str); } else { - headerTranslation(t, t->values_final, str); - copy_v3_v3(values_final, t->values_final); + headerTranslation(t, global_dir, str); } - /* don't use 't->values' now on */ - - applyTranslationValue(t, values_final); + applyTranslationValue(t, global_dir); /* evil hack - redo translation if clipping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) { - applyTranslationValue(t, values_final); + if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) { + applyTranslationValue(t, global_dir); /* In proportional edit it can happen that */ /* vertices in the radius of the brush end */ @@ -368,8 +361,10 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) } } - recalcData(t); + /* Set the redo value. */ + mul_v3_m3v3(t->values_final, t->spacemtx_inv, global_dir); + recalcData(t); ED_area_status_text(t->area, str); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 81c63278366..32269e1bacc 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -438,79 +438,148 @@ static int armature_bone_transflags_update_recursive(bArmature *arm, return total; } -void initTransformOrientation(bContext *C, TransInfo *t, short orientation) +/* Sets the matrix of the specified space orientation. + * If the matrix cannot be obtained, an orientation different from the one + * informed is returned */ +short transform_orientation_matrix_get(bContext *C, + TransInfo *t, + const short orientation, + const float custom[3][3], + float r_spacemtx[3][3]) { Object *ob = CTX_data_active_object(C); Object *obedit = CTX_data_active_object(C); switch (orientation) { case V3D_ORIENT_GLOBAL: - unit_m3(t->spacemtx); - BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename)); - break; + unit_m3(r_spacemtx); + return V3D_ORIENT_GLOBAL; case V3D_ORIENT_GIMBAL: - unit_m3(t->spacemtx); - if (ob && gimbal_axis(ob, t->spacemtx)) { - BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename)); - break; + unit_m3(r_spacemtx); + if (ob && gimbal_axis(ob, r_spacemtx)) { + return V3D_ORIENT_GIMBAL; } ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */ + case V3D_ORIENT_NORMAL: if (obedit || (ob && ob->mode & OB_MODE_POSE)) { - BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename)); - ED_getTransformOrientationMatrix(C, t->spacemtx, t->around); - break; + ED_getTransformOrientationMatrix(C, r_spacemtx, t->around); + return V3D_ORIENT_NORMAL; } ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */ - case V3D_ORIENT_LOCAL: - BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename)); + case V3D_ORIENT_LOCAL: if (ob) { - copy_m3_m4(t->spacemtx, ob->obmat); - normalize_m3(t->spacemtx); + copy_m3_m4(r_spacemtx, ob->obmat); + normalize_m3(r_spacemtx); + return V3D_ORIENT_LOCAL; } - else { - unit_m3(t->spacemtx); - } - - break; + unit_m3(r_spacemtx); + return V3D_ORIENT_GLOBAL; case V3D_ORIENT_VIEW: { float mat[3][3]; if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { - BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename)); - copy_m3_m4(mat, t->viewinv); + RegionView3D *rv3d = t->region->regiondata; + copy_m3_m4(mat, rv3d->viewinv); normalize_m3(mat); } else { unit_m3(mat); } - negate_v3(mat[2]); - copy_m3_m3(t->spacemtx, mat); - break; - } - case V3D_ORIENT_CURSOR: { - BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename)); - BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); - break; + copy_m3_m3(r_spacemtx, mat); + return V3D_ORIENT_VIEW; } + case V3D_ORIENT_CURSOR: + BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, r_spacemtx); + return V3D_ORIENT_CURSOR; + case V3D_ORIENT_CUSTOM_MATRIX: - BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename)); - copy_m3_m3(t->spacemtx, t->orientation.custom_matrix); - break; + copy_m3_m3(r_spacemtx, custom); + return V3D_ORIENT_CUSTOM_MATRIX; + case V3D_ORIENT_CUSTOM: default: BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename)); - if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) { + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orientation - V3D_ORIENT_CUSTOM); + if (applyTransformOrientation(ts, r_spacemtx, t->spacename)) { /* pass */ } else { - unit_m3(t->spacemtx); + unit_m3(r_spacemtx); } break; } + + return orientation; +} + +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type) +{ + switch (orient_type) { + case V3D_ORIENT_GLOBAL: + return TIP_("global"); + case V3D_ORIENT_GIMBAL: + return TIP_("gimbal"); + case V3D_ORIENT_NORMAL: + return TIP_("normal"); + case V3D_ORIENT_LOCAL: + return TIP_("local"); + case V3D_ORIENT_VIEW: + return TIP_("view"); + case V3D_ORIENT_CURSOR: + return TIP_("cursor"); + case V3D_ORIENT_CUSTOM_MATRIX: + return TIP_("custom"); + case V3D_ORIENT_CUSTOM: + default: + BLI_assert(orient_type >= V3D_ORIENT_CUSTOM); + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orient_type - V3D_ORIENT_CUSTOM); + return ts->name; + } +} + +void transform_orientations_current_set(TransInfo *t, const short orient_index) +{ + const short orientation = t->orient[orient_index].type; + const char *spacename; + switch (orientation) { + case V3D_ORIENT_GLOBAL: + spacename = TIP_("global"); + break; + case V3D_ORIENT_GIMBAL: + spacename = TIP_("gimbal"); + break; + case V3D_ORIENT_NORMAL: + spacename = TIP_("normal"); + break; + case V3D_ORIENT_LOCAL: + spacename = TIP_("local"); + break; + case V3D_ORIENT_VIEW: + spacename = TIP_("view"); + break; + case V3D_ORIENT_CURSOR: + spacename = TIP_("cursor"); + break; + case V3D_ORIENT_CUSTOM_MATRIX: + spacename = TIP_("custom"); + break; + case V3D_ORIENT_CUSTOM: + default: + BLI_assert(orientation >= V3D_ORIENT_CUSTOM); + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orientation - V3D_ORIENT_CUSTOM); + spacename = ts->name; + break; + } + + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); + copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix); + invert_m3_m3(t->spacemtx_inv, t->spacemtx); } /** @@ -852,7 +921,7 @@ int getTransformOrientation_ex(const bContext *C, } } else { - const bool use_handle = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0; + const bool use_handle = v3d->overlay.handle_display != CURVE_HANDLE_NONE; for (nu = nurbs->first; nu; nu = nu->next) { /* only bezier has a normal */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index cb4446deb99..50f525a324b 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -56,6 +56,7 @@ #include "WM_types.h" +#include "ED_gizmo_library.h" #include "ED_image.h" #include "ED_markers.h" #include "ED_node.h" @@ -178,99 +179,53 @@ void drawSnapping(const struct bContext *C, TransInfo *t) (t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); if (draw_target || validSnap(t)) { - TransSnapPoint *p; - RegionView3D *rv3d = CTX_wm_region_view3d(C); - float imat[4][4]; - float size; + const float *loc_cur = NULL; + const float *loc_prev = NULL; + const float *normal = NULL; GPU_depth_test(false); - size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (!BLI_listbase_is_empty(&t->tsnap.points)) { + /* Draw snap points. */ - invert_m4_m4(imat, rv3d->viewmat); + float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE); + float view_inv[4][4]; + copy_m4_m4(view_inv, rv3d->viewinv); - uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - for (p = t->tsnap.points.first; p; p = p->next) { - if (p == t->tsnap.selectedPoint) { - immUniformColor4ubv(selectedCol); - } - else { - immUniformColor4ubv(col); + LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) { + if (p == t->tsnap.selectedPoint) { + immUniformColor4ubv(selectedCol); + } + else { + immUniformColor4ubv(col); + } + imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos); } - imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos); - } - - if (t->tsnap.status & POINT_INIT) { - immUniformColor4ubv(activeCol); - - imm_drawcircball( - t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos); + immUnbindProgram(); } /* draw normal if needed */ if (usingSnappingNormal(t) && validSnappingNormal(t)) { - immUniformColor4ubv(activeCol); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]); - immVertex3f(pos, - t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0], - t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1], - t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]); - immEnd(); + normal = t->tsnap.snapNormal; } if (draw_target) { - /* Draw snapTarget */ - float targ_co[3], vx[3], vy[3], v1[3], v2[3], v3[3], v4[4]; - copy_v3_v3(targ_co, t->tsnap.snapTarget); - float px_size = 0.75f * size * ED_view3d_pixel_size(rv3d, targ_co); - - mul_v3_v3fl(vx, imat[0], px_size); - mul_v3_v3fl(vy, imat[1], px_size); - - add_v3_v3v3(v1, vx, vy); - sub_v3_v3v3(v2, vx, vy); - negate_v3_v3(v3, v1); - negate_v3_v3(v4, v2); - - add_v3_v3(v1, targ_co); - add_v3_v3(v2, targ_co); - add_v3_v3(v3, targ_co); - add_v3_v3(v4, targ_co); - - immUniformColor4ubv(col); - immBegin(GPU_PRIM_LINES, 4); - immVertex3fv(pos, v3); - immVertex3fv(pos, v1); - immVertex3fv(pos, v4); - immVertex3fv(pos, v2); - immEnd(); - - if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) { - immUnbindProgram(); - - immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - immUniform1f("dash_width", 6.0f * U.pixelsize); - immUniform1f("dash_factor", 1.0f / 4.0f); - immUniformColor4ubv(col); + loc_prev = t->tsnap.snapTarget; + } - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, targ_co); - immVertex3fv(pos, t->tsnap.snapPoint); - immEnd(); - } + if (validSnap(t)) { + loc_cur = t->tsnap.snapPoint; } - immUnbindProgram(); + ED_gizmotypes_snap_3d_draw_util( + rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); GPU_depth_test(true); } @@ -590,7 +545,6 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) static void initSnappingMode(TransInfo *t) { - Main *bmain = CTX_data_main(t->context); ToolSettings *ts = t->settings; /* All obedit types will match. */ const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1; @@ -687,7 +641,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - bmain, t->scene, 0, t->region, t->view); + t->scene, 0, t->region, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( t->tsnap.object_context, @@ -1106,7 +1060,6 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) } else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) { if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) { - Image *ima = ED_space_image(t->area->spacedata.first); float co[2]; UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]); @@ -1117,7 +1070,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) float dist_sq = FLT_MAX; if (ED_uvedit_nearest_uv_multi( - t->scene, ima, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) { + t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) { t->tsnap.snapPoint[0] *= t->aspect[0]; t->tsnap.snapPoint[1] *= t->aspect[1]; @@ -1750,8 +1703,8 @@ static void applyGridIncrement( float local_axis[3]; float pos_on_axis[3]; - copy_v3_v3(local_axis, t->con.mtx[i]); - copy_v3_v3(pos_on_axis, t->con.mtx[i]); + copy_v3_v3(local_axis, t->spacemtx[i]); + copy_v3_v3(pos_on_axis, t->spacemtx[i]); /* amount of movement on axis from initial pos */ mul_v3_fl(pos_on_axis, val[i]); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 2cfeedbb346..77bb0c1c785 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -110,7 +110,6 @@ typedef struct SnapObjectData { } SnapObjectData; struct SnapObjectContext { - Main *bmain; Scene *scene; int flag; @@ -1707,8 +1706,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, &nearest.dist_sq, nearest.co)) { nearest.index = vindex[v_id]; - nearest2d.copy_vert_no(vindex[v_id], nearest.no, nearest2d.userdata); elem = SCE_SNAP_MODE_VERTEX; + if (r_no) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata); + mul_transposed_mat3_m4_v3(imat, r_no); + normalize_v3(r_no); + } } } } @@ -1726,10 +1731,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, vmid, &nearest.dist_sq, nearest.co)) { - float v_nor[2][3]; - nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata); - nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata); - mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]); nearest.index = *r_index; elem = SCE_SNAP_MODE_EDGE_MIDPOINT; } @@ -1757,11 +1758,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, v_near, &nearest.dist_sq, nearest.co)) { - float v_nor[2][3]; - nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata); - nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata); - mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]); - nearest.index = *r_index; elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR; } @@ -1778,15 +1774,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, mul_m4_v3(obmat, r_loc); } - if (r_no) { - float imat[4][4]; - invert_m4_m4(imat, obmat); - - copy_v3_v3(r_no, nearest.no); - mul_transposed_mat3_m4_v3(imat, r_no); - normalize_v3(r_no); - } - *r_index = nearest.index; } @@ -2863,13 +2850,12 @@ static short snapObjectsRay(SnapObjectContext *sctx, /** \name Public Object Snapping API * \{ */ -SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *scene, int flag) +SnapObjectContext *ED_transform_snap_object_context_create(Scene *scene, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); sctx->flag = flag; - sctx->bmain = bmain; sctx->scene = scene; sctx->cache.object_map = BLI_ghash_ptr_new(__func__); @@ -2880,14 +2866,13 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *s return sctx; } -SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain, - Scene *scene, +SnapObjectContext *ED_transform_snap_object_context_create_view3d(Scene *scene, int flag, /* extra args for view3d */ const ARegion *region, const View3D *v3d) { - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, flag); sctx->use_v3d = true; sctx->v3d_data.region = region; diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index f22e18de7a1..2df26abe8b3 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -216,7 +216,7 @@ static void memfile_undosys_step_decode(struct bContext *C, FOREACH_MAIN_ID_BEGIN (bmain, id) { if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) { BKE_library_foreach_ID_link( - bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY); + bmain, id, memfile_undosys_step_id_reused_cb, NULL, IDWALK_READONLY); } /* Tag depsgraph to update data-block for changes that happened between the diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c index c072220842e..edfbfd0cdc3 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -58,8 +58,7 @@ /* UV Utilities */ -static int uvedit_center( - Scene *scene, Object **objects, uint objects_len, Image *ima, float center[2]) +static int uvedit_center(Scene *scene, Object **objects, uint objects_len, float center[2]) { BMFace *f; BMLoop *l; @@ -75,7 +74,7 @@ static int uvedit_center( const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, f)) { + if (!uvedit_face_visible_test(scene, f)) { continue; } @@ -97,8 +96,10 @@ static int uvedit_center( return tot; } -static void uvedit_translate( - Scene *scene, Object **objects, uint objects_len, Image *ima, const float delta[2]) +static void uvedit_translate(Scene *scene, + Object **objects, + uint objects_len, + const float delta[2]) { BMFace *f; BMLoop *l; @@ -112,7 +113,7 @@ static void uvedit_translate( const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, f)) { + if (!uvedit_face_visible_test(scene, f)) { continue; } @@ -134,7 +135,6 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); - Image *ima = sima->image; float center[2]; int imx, imy, step, digits; float width = 8 * UI_UNIT_X; @@ -144,7 +144,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) ED_space_image_get_size(sima, &imx, &imy); - if (uvedit_center(scene, objects, objects_len, ima, center)) { + if (uvedit_center(scene, objects, objects_len, center)) { float range_xy[2][2] = { {-10.0f, 10.0f}, {-10.0f, 10.0f}, @@ -212,7 +212,6 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); - Image *ima = sima->image; float center[2], delta[2]; int imx, imy; @@ -225,7 +224,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len); ED_space_image_get_size(sima, &imx, &imy); - uvedit_center(scene, objects, objects_len, ima, center); + uvedit_center(scene, objects, objects_len, center); if (sima->flag & SI_COORDFLOATS) { delta[0] = uvedit_old_center[0] - center[0]; @@ -236,7 +235,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) delta[1] = uvedit_old_center[1] / imy - center[1]; } - uvedit_translate(scene, objects, objects_len, ima, delta); + uvedit_translate(scene, objects, objects_len, delta); WM_event_add_notifier(C, NC_IMAGE, sima->image); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 959ca1eeef1..f8cef95c776 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -216,13 +216,14 @@ static void uvedit_get_batches(Object *ob, } } -static void draw_uvs_shadow(SpaceImage *UNUSED(sima), +static void draw_uvs_shadow(SpaceImage *sima, const Scene *scene, Object *obedit, Depsgraph *depsgraph) { Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit); Mesh *me = ob_eval->data; + const float overlay_alpha = sima->uv_opacity; float col[4]; UI_GetThemeColor4fv(TH_UV_SHADOW, col); @@ -231,9 +232,26 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima), DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false); if (edges) { + if (sima->flag & SI_SMOOTH_UV) { + GPU_line_smooth(true); + GPU_blend(true); + } + else if (overlay_alpha < 1.0f) { + GPU_blend(true); + } + + col[3] = overlay_alpha; GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR); GPU_batch_uniform_4fv(edges, "color", col); GPU_batch_draw(edges); + + if (sima->flag & SI_SMOOTH_UV) { + GPU_line_smooth(false); + GPU_blend(false); + } + else if (overlay_alpha < 1.0f) { + GPU_blend(false); + } } } diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index ffab5bd094f..31384d6df17 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -57,13 +57,11 @@ typedef struct UvNearestHit { } bool uv_find_nearest_vert(struct Scene *scene, - struct Image *ima, struct Object *obedit, const float co[2], const float penalty_dist, struct UvNearestHit *hit_final); bool uv_find_nearest_vert_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], @@ -71,24 +69,20 @@ bool uv_find_nearest_vert_multi(struct Scene *scene, struct UvNearestHit *hit_final); bool uv_find_nearest_edge(struct Scene *scene, - struct Image *ima, struct Object *obedit, const float co[2], struct UvNearestHit *hit_final); bool uv_find_nearest_edge_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], struct UvNearestHit *hit_final); bool uv_find_nearest_face(struct Scene *scene, - struct Image *ima, struct Object *obedit, const float co[2], struct UvNearestHit *hit_final); bool uv_find_nearest_face_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len, const float co[2], @@ -116,14 +110,11 @@ void UV_OT_stitch(struct wmOperatorType *ot); /* uvedit_select.c */ -bool uvedit_select_is_any_selected(struct Scene *scene, struct Image *ima, struct Object *obedit); +bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit); bool uvedit_select_is_any_selected_multi(struct Scene *scene, - struct Image *ima, struct Object **objects, const uint objects_len); const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene, - struct Object *obedit, - struct Image *ima, struct BMVert *eve, const int cd_loop_uv_offset); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index a99e05cb52b..78b6cfc44ac 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -252,12 +252,8 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as } } -bool ED_uvedit_minmax_multi(const Scene *scene, - Image *ima, - Object **objects_edit, - uint objects_len, - float r_min[2], - float r_max[2]) +bool ED_uvedit_minmax_multi( + const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]) { bool changed = false; INIT_MINMAX2(r_min, r_max); @@ -274,7 +270,7 @@ bool ED_uvedit_minmax_multi(const Scene *scene, const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -290,10 +286,9 @@ bool ED_uvedit_minmax_multi(const Scene *scene, return changed; } -bool ED_uvedit_minmax( - const Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2]) +bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2]) { - return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max); + return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max); } /* Be careful when using this, it bypasses all synchronization options */ @@ -314,8 +309,10 @@ void ED_uvedit_select_all(BMesh *bm) } } -static bool ED_uvedit_median_multi( - const Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2]) +static bool ED_uvedit_median_multi(const Scene *scene, + Object **objects_edit, + uint objects_len, + float co[2]) { uint sel = 0; zero_v2(co); @@ -332,7 +329,7 @@ static bool ED_uvedit_median_multi( const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -351,24 +348,20 @@ static bool ED_uvedit_median_multi( return (sel != 0); } -bool ED_uvedit_center_multi(const Scene *scene, - Image *ima, - Object **objects_edit, - uint objects_len, - float cent[2], - char mode) +bool ED_uvedit_center_multi( + const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode) { bool changed = false; if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */ float min[2], max[2]; - if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) { + if (ED_uvedit_minmax_multi(scene, objects_edit, objects_len, min, max)) { mid_v2_v2v2(cent, min, max); changed = true; } } else { - if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) { + if (ED_uvedit_median_multi(scene, objects_edit, objects_len, cent)) { changed = true; } } @@ -392,8 +385,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima, uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - *r_has_select = uvedit_select_is_any_selected_multi( - scene, sima->image, objects, objects_len); + *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len); MEM_freeN(objects); } break; @@ -402,7 +394,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima, uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - changed = ED_uvedit_center_multi(scene, sima->image, objects, objects_len, r_center, mode); + changed = ED_uvedit_center_multi(scene, objects, objects_len, r_center, mode); MEM_freeN(objects); if (r_has_select != NULL) { *r_has_select = changed; @@ -440,7 +432,6 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; float cent[2], min[2], max[2]; @@ -467,7 +458,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -482,7 +473,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; } - ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0); + ED_uvedit_center_multi(scene, objects, objects_len, cent, 0); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -501,7 +492,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -521,7 +512,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) BMLoop *l; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -548,7 +539,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) /* tag verts with a selected UV */ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + if (!uvedit_face_visible_test(scene, l->f)) { continue; } @@ -619,9 +610,9 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) /* we know the returns from these must be valid */ const float *uv_start = uvedit_first_selected_uv_from_vertex( - scene, obedit, ima, eve_line[0], cd_loop_uv_offset); + scene, eve_line[0], cd_loop_uv_offset); const float *uv_end = uvedit_first_selected_uv_from_vertex( - scene, obedit, ima, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset); + scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset); /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ float a = 0.0f; eUVWeldAlign tool_local = tool; @@ -646,7 +637,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) /* go over all verts except for endpoints */ for (i = 0; i < BLI_array_len(eve_line); i++) { BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + if (!uvedit_face_visible_test(scene, l->f)) { continue; } @@ -754,7 +745,6 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const float threshold = RNA_float_get(op->ptr, "threshold"); @@ -808,7 +798,7 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -899,7 +889,6 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const float threshold = RNA_float_get(op->ptr, "threshold"); @@ -939,7 +928,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -972,7 +961,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1086,10 +1075,12 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima) uv_snap_to_pixel(sima->cursor, width, height); } -static bool uv_snap_cursor_to_selection( - Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima) +static bool uv_snap_cursor_to_selection(Scene *scene, + Object **objects_edit, + uint objects_len, + SpaceImage *sima) { - return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around); + return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around); } static int uv_snap_cursor_exec(bContext *C, wmOperator *op) @@ -1105,13 +1096,12 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op) break; case 1: { Scene *scene = CTX_data_scene(C); - Image *ima = CTX_data_edit_image(C); ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima); + changed = uv_snap_cursor_to_selection(scene, objects, objects_len, sima); MEM_freeN(objects); break; } @@ -1155,7 +1145,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot) /** \name Snap Selection Operator * \{ */ -static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2]) +static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -1167,7 +1157,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1183,7 +1173,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons return changed; } -static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2]) +static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -1195,7 +1185,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1211,7 +1201,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f return changed; } -static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit) +static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -1225,7 +1215,7 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object /* index every vert that has a selected UV using it, but only once so as to * get unique indices and to count how much to malloc */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, f)) { + if (uvedit_face_visible_test(scene, f)) { BM_elem_flag_enable(f, BM_ELEM_TAG); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset)); @@ -1269,7 +1259,6 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); - Image *ima = sima->image; BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -1285,7 +1274,7 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit h = (float)height; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1307,7 +1296,6 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ToolSettings *ts = scene->toolsettings; const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; const int target = RNA_enum_get(op->ptr, "target"); @@ -1319,7 +1307,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) if (target == 2) { float center[2]; - if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) { + if (!ED_uvedit_center_multi(scene, objects, objects_len, center, sima->around)) { MEM_freeN(objects); return OPERATOR_CANCELLED; } @@ -1341,13 +1329,13 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) changed = uv_snap_uvs_to_pixels(sima, scene, obedit); break; case 1: - changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor); + changed = uv_snap_uvs_to_cursor(scene, obedit, sima->cursor); break; case 2: - changed = uv_snap_uvs_offset(scene, ima, obedit, offset); + changed = uv_snap_uvs_offset(scene, obedit, offset); break; case 3: - changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit); + changed = uv_snap_uvs_to_adjacent_unselected(scene, obedit); break; } @@ -1398,7 +1386,6 @@ static int uv_pin_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -1423,7 +1410,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op) } BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1501,11 +1488,9 @@ static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop static int uv_hide_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; const bool swap = RNA_boolean_get(op->ptr, "unselected"); - Image *ima = sima ? sima->image : NULL; const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE); uint objects_len = 0; @@ -1532,7 +1517,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op) BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { int hide = 0; - if (!uvedit_face_visible_test(scene, ob, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -2006,8 +1991,6 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot) static int uv_mark_seam_exec(bContext *C, wmOperator *op) { - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = sima ? sima->image : NULL; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; @@ -2038,7 +2021,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ob, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) { BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 6e931b56a85..cc9be9d48c1 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -70,9 +70,11 @@ #include "uvedit_intern.h" -static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action); -static void uv_select_all_perform_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, int action); +static void uv_select_all_perform(Scene *scene, Object *obedit, int action); +static void uv_select_all_perform_multi(Scene *scene, + Object **objects, + const uint objects_len, + int action); static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, @@ -112,7 +114,7 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em, } } -bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa) +bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa) { if (ts->uv_flag & UV_SYNC_SELECTION) { return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); @@ -121,25 +123,9 @@ bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa) return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); } } -bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa) +bool uvedit_face_visible_test(const Scene *scene, BMFace *efa) { - return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa); -} - -bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa) -{ - if (ts->uv_flag & UV_SHOW_SAME_IMAGE) { - Image *face_image; - ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL); - return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false; - } - else { - return uvedit_face_visible_nolocal_ex(ts, efa); - } -} -bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa) -{ - return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa); + return uvedit_face_visible_test_ex(scene->toolsettings, efa); } bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) @@ -437,8 +423,7 @@ void uvedit_uv_select_disable(BMEditMesh *em, /** \name Find Nearest Elements * \{ */ -bool uv_find_nearest_edge( - Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit) +bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -453,7 +438,7 @@ bool uv_find_nearest_edge( BM_mesh_elem_index_ensure(em->bm, BM_VERT); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { @@ -479,7 +464,6 @@ bool uv_find_nearest_edge( } bool uv_find_nearest_edge_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float co[2], @@ -488,7 +472,7 @@ bool uv_find_nearest_edge_multi(Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) { + if (uv_find_nearest_edge(scene, obedit, co, hit_final)) { hit_final->ob = obedit; found = true; } @@ -496,8 +480,7 @@ bool uv_find_nearest_edge_multi(Scene *scene, return found; } -bool uv_find_nearest_face( - Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final) +bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final) { BMEditMesh *em = BKE_editmesh_from_object(obedit); bool found = false; @@ -507,7 +490,7 @@ bool uv_find_nearest_face( /* this will fill in hit.vert1 and hit.vert2 */ float dist_sq_init = hit_final->dist_sq; UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + if (uv_find_nearest_edge(scene, obedit, co, &hit)) { hit.dist_sq = dist_sq_init; hit.l = NULL; hit.luv = hit.luv_next = NULL; @@ -516,7 +499,7 @@ bool uv_find_nearest_face( BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -539,7 +522,6 @@ bool uv_find_nearest_face( } bool uv_find_nearest_face_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float co[2], @@ -548,7 +530,7 @@ bool uv_find_nearest_face_multi(Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) { + if (uv_find_nearest_face(scene, obedit, co, hit_final)) { hit_final->ob = obedit; found = true; } @@ -567,7 +549,6 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_ } bool uv_find_nearest_vert(Scene *scene, - Image *ima, Object *obedit, float const co[2], const float penalty_dist, @@ -578,7 +559,7 @@ bool uv_find_nearest_vert(Scene *scene, /* this will fill in hit.vert1 and hit.vert2 */ float dist_sq_init = hit_final->dist_sq; UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) { + if (uv_find_nearest_edge(scene, obedit, co, &hit)) { hit.dist_sq = dist_sq_init; hit.l = NULL; @@ -593,7 +574,7 @@ bool uv_find_nearest_vert(Scene *scene, const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -639,7 +620,6 @@ bool uv_find_nearest_vert(Scene *scene, } bool uv_find_nearest_vert_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, float const co[2], @@ -649,7 +629,7 @@ bool uv_find_nearest_vert_multi(Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) { + if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit_final)) { hit_final->ob = obedit; found = true; } @@ -657,12 +637,8 @@ bool uv_find_nearest_vert_multi(Scene *scene, return found; } -bool ED_uvedit_nearest_uv(const Scene *scene, - Object *obedit, - Image *ima, - const float co[2], - float *dist_sq, - float r_uv[2]) +bool ED_uvedit_nearest_uv( + const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2]) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMIter iter; @@ -671,7 +647,7 @@ bool ED_uvedit_nearest_uv(const Scene *scene, float dist_best = *dist_sq; const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } BMLoop *l_iter, *l_first; @@ -697,7 +673,6 @@ bool ED_uvedit_nearest_uv(const Scene *scene, } bool ED_uvedit_nearest_uv_multi(const Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float co[2], @@ -707,7 +682,7 @@ bool ED_uvedit_nearest_uv_multi(const Scene *scene, bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) { + if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) { found = true; } } @@ -817,12 +792,8 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, return true; } -static int uv_select_edgeloop(Scene *scene, - Image *ima, - Object *obedit, - UvNearestHit *hit, - const float limit[2], - const bool extend) +static int uv_select_edgeloop( + Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -843,7 +814,7 @@ static int uv_select_edgeloop(Scene *scene, BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); if (!extend) { - uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); + uv_select_all_perform(scene, obedit, SEL_DESELECT); } BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); @@ -867,8 +838,7 @@ static int uv_select_edgeloop(Scene *scene, /* find correct valence edges which are not tagged yet, but connect to tagged one */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && - uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { /* check face not hidden and not tagged */ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) { @@ -930,7 +900,6 @@ static int uv_select_edgeloop(Scene *scene, * \{ */ static void uv_select_linked_multi(Scene *scene, - Image *ima, Object **objects, const uint objects_len, const float limit[2], @@ -980,7 +949,7 @@ static void uv_select_linked_multi(Scene *scene, if (hit_final == NULL) { /* Use existing selection */ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { if (select_faces) { if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { stack[stacksize] = a; @@ -1121,14 +1090,15 @@ static void uv_select_linked_multi(Scene *scene, * \warning This returns first selected UV, * not ideal in many cases since there could be multiple. */ -const float *uvedit_first_selected_uv_from_vertex( - Scene *scene, Object *obedit, Image *ima, BMVert *eve, const int cd_loop_uv_offset) +const float *uvedit_first_selected_uv_from_vertex(Scene *scene, + BMVert *eve, + const int cd_loop_uv_offset) { BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) { + if (!uvedit_face_visible_test(scene, l->f)) { continue; } @@ -1151,7 +1121,6 @@ static int uv_select_more_less(bContext *C, const bool select) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); SpaceImage *sima = CTX_wm_space_image(C); BMFace *efa; @@ -1193,7 +1162,7 @@ static int uv_select_more_less(bContext *C, const bool select) /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { #define IS_SEL 1 #define IS_UNSEL 2 @@ -1233,7 +1202,7 @@ static int uv_select_more_less(bContext *C, const bool select) /* mark loops to be selected */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); @@ -1308,7 +1277,7 @@ void UV_OT_select_less(wmOperatorType *ot) /** \name (De)Select All Operator * \{ */ -bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) +bool uvedit_select_is_any_selected(Scene *scene, Object *obedit) { const ToolSettings *ts = scene->toolsettings; BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -1323,7 +1292,7 @@ bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) else { const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { @@ -1337,15 +1306,12 @@ bool uvedit_select_is_any_selected(Scene *scene, Image *ima, Object *obedit) return false; } -bool uvedit_select_is_any_selected_multi(Scene *scene, - Image *ima, - Object **objects, - const uint objects_len) +bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len) { bool found = false; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - if (uvedit_select_is_any_selected(scene, ima, obedit)) { + if (uvedit_select_is_any_selected(scene, obedit)) { found = true; break; } @@ -1353,7 +1319,7 @@ bool uvedit_select_is_any_selected_multi(Scene *scene, return found; } -static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action) +static void uv_select_all_perform(Scene *scene, Object *obedit, int action) { const ToolSettings *ts = scene->toolsettings; BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -1365,7 +1331,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); if (action == SEL_TOGGLE) { - action = uvedit_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT; + action = uvedit_select_is_any_selected(scene, obedit) ? SEL_DESELECT : SEL_SELECT; } if (ts->uv_flag & UV_SYNC_SELECTION) { @@ -1387,7 +1353,7 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int } else { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1410,17 +1376,19 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int } } -static void uv_select_all_perform_multi( - Scene *scene, Image *ima, Object **objects, const uint objects_len, int action) +static void uv_select_all_perform_multi(Scene *scene, + Object **objects, + const uint objects_len, + int action) { if (action == SEL_TOGGLE) { - action = uvedit_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : - SEL_SELECT; + action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT : + SEL_SELECT; } for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - uv_select_all_perform(scene, ima, obedit, action); + uv_select_all_perform(scene, obedit, action); } } @@ -1429,7 +1397,6 @@ static int uv_select_all_exec(bContext *C, wmOperator *op) Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); ViewLayer *view_layer = CTX_data_view_layer(C); int action = RNA_enum_get(op->ptr, "action"); @@ -1438,7 +1405,7 @@ static int uv_select_all_exec(bContext *C, wmOperator *op) Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - uv_select_all_perform_multi(scene, ima, objects, objects_len, action); + uv_select_all_perform_multi(scene, objects, objects_len, action); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -1510,7 +1477,6 @@ static int uv_mouse_select_multi(bContext *C, SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -1563,12 +1529,11 @@ static int uv_mouse_select_multi(bContext *C, /* find nearest element */ if (loop) { /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); } else if (selectmode == UV_SELECT_VERTEX) { /* find vertex */ - found_item = uv_find_nearest_vert_multi( - scene, ima, objects, objects_len, co, penalty_dist, &hit); + found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { @@ -1585,7 +1550,7 @@ static int uv_mouse_select_multi(bContext *C, } else if (selectmode == UV_SELECT_EDGE) { /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { @@ -1604,7 +1569,7 @@ static int uv_mouse_select_multi(bContext *C, } else if (selectmode == UV_SELECT_FACE) { /* find face */ - found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { @@ -1628,13 +1593,13 @@ static int uv_mouse_select_multi(bContext *C, } } else if (selectmode == UV_SELECT_ISLAND) { - found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit); + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); } if (!found_item) { if (deselect_all) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -1654,19 +1619,18 @@ static int uv_mouse_select_multi(bContext *C, if (loop) { if (!extend) { /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } - flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend); + flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend); } else if (selectmode == UV_SELECT_ISLAND) { if (!extend) { /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } /* Current behavior of 'extend' * is actually toggling, so pass extend flag as 'toggle' here */ - uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, false, false, extend, false); + uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false); } else if (extend) { if (selectmode == UV_SELECT_VERTEX) { @@ -1701,7 +1665,7 @@ static int uv_mouse_select_multi(bContext *C, BM_mesh_elem_index_ensure(em->bm, BM_VERT); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1719,7 +1683,7 @@ static int uv_mouse_select_multi(bContext *C, } else { /* deselect all */ - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); if (selectmode == UV_SELECT_VERTEX) { /* select vertex */ @@ -1739,7 +1703,7 @@ static int uv_mouse_select_multi(bContext *C, /* select sticky uvs */ if (sticky != SI_STICKY_DISABLE) { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -1946,7 +1910,6 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); float limit[2]; bool extend = true; bool deselect = false; @@ -1986,18 +1949,17 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent RNA_float_get_array(op->ptr, "location", co); } - if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) { + if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) { MEM_freeN(objects); return OPERATOR_CANCELLED; } } if (!extend) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } uv_select_linked_multi(scene, - ima, objects, objects_len, limit, @@ -2117,7 +2079,6 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; @@ -2147,7 +2108,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) bool is_sel = false; bool is_unsel = false; - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -2483,7 +2444,6 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); const ARegion *region = CTX_wm_region(C); BMFace *efa; BMLoop *l; @@ -2518,7 +2478,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) view_layer, ((View3D *)NULL), &objects_len); if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } /* don't indent to avoid diff noise! */ @@ -2539,7 +2499,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) /* assume not touched */ BM_elem_flag_disable(efa, BM_ELEM_TAG); - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (uvedit_face_visible_test(scene, efa)) { uv_poly_center(efa, cent, cd_loop_uv_offset); if (BLI_rctf_isect_pt_v(&rectf, cent)) { BM_elem_flag_enable(efa, BM_ELEM_TAG); @@ -2558,7 +2518,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -2594,7 +2554,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } bool has_selected = false; @@ -2623,7 +2583,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) .efa = efa, }; uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + scene, objects, objects_len, limit, &hit, true, !select, false, false); } } @@ -2708,7 +2668,6 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; @@ -2757,7 +2716,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } for (uint ob_index = 0; ob_index < objects_len; ob_index++) { @@ -2792,7 +2751,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -2826,7 +2785,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } bool has_selected = false; @@ -2847,7 +2806,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) .efa = efa, }; uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + scene, objects, objects_len, limit, &hit, true, !select, false, false); } } @@ -2920,7 +2879,6 @@ static bool do_lasso_select_mesh_uv(bContext *C, { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; @@ -2952,7 +2910,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, view_layer, ((View3D *)NULL), &objects_len); if (use_pre_deselect) { - uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT); + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } /* don't indent to avoid diff noise! */ @@ -2988,7 +2946,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -3025,7 +2983,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } bool has_selected = false; @@ -3047,7 +3005,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, .efa = efa, }; uv_select_linked_multi( - scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + scene, objects, objects_len, limit, &hit, true, !select, false, false); } } @@ -3116,7 +3074,6 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); BMFace *efa; BMLoop *l; BMIter iter, liter; @@ -3134,7 +3091,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) bool changed = false; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + if (!uvedit_face_visible_test(scene, efa)) { continue; } @@ -3208,7 +3165,6 @@ static int uv_select_overlap(bContext *C, const bool extend) Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Image *ima = CTX_data_edit_image(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -3224,13 +3180,13 @@ static int uv_select_overlap(bContext *C, const bool extend) BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); if (!extend) { - uv_select_all_perform(scene, ima, obedit, SEL_DESELECT); + uv_select_all_perform(scene, obedit, SEL_DESELECT); } BMIter iter; BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { + if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { continue; } uv_tri_len += efa->len - 2; @@ -3261,7 +3217,7 @@ static int uv_select_overlap(bContext *C, const bool extend) int face_index; BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { - if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) { + if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { continue; } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 3a4f12acf9c..594847b7249 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -2550,12 +2550,11 @@ static StitchState *stitch_select(bContext *C, float co[2]; UvNearestHit hit = UV_NEAREST_HIT_INIT; ARegion *region = CTX_wm_region(C); - Image *ima = CTX_data_edit_image(C); UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); if (ssc->mode == STITCH_VERT) { - if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) { + if (uv_find_nearest_vert_multi(scene, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) { /* Add vertex to selection, deselect all common uv's of vert other than selected and * update the preview. This behavior was decided so that you can do stuff like deselect * the opposite stitchable vertex and the initial still gets deselected */ @@ -2576,7 +2575,7 @@ static StitchState *stitch_select(bContext *C, return state; } } - else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) { + else if (uv_find_nearest_edge_multi(scene, ssc->objects, ssc->objects_len, co, &hit)) { /* find StitchState from hit->ob */ StitchState *state = NULL; for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index 66195745cbb..253d62ea3dc 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -923,19 +923,16 @@ Render *Controller::RenderStrokes(Render *re, bool render) cout << "Stroke rendering : " << d << endl; uintptr_t mem_in_use = MEM_get_memory_in_use(); - uintptr_t mmap_in_use = MEM_get_mapped_memory_in_use(); uintptr_t peak_memory = MEM_get_peak_memory(); - float megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0); - float mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0); + float megs_used_memory = (mem_in_use) / (1024.0 * 1024.0); float megs_peak_memory = (peak_memory) / (1024.0 * 1024.0); - printf("%d objs, %d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n", + printf("%d objs, %d verts, %d faces, mem %.2fM (peak %.2fM)\n", totmesh, freestyle_render->i.totvert, freestyle_render->i.totface, megs_used_memory, - mmap_used_memory, megs_peak_memory); } delete blenderRenderer; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 82f9d9a323d..73328d7dd31 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -170,9 +170,12 @@ static void deformStroke(GpencilModifierData *md, float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ? noise_table(len, seed) : NULL; float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ? noise_table(len, seed + 4) : NULL; - /* calculate stroke normal*/ + /* Calculate stroke normal. */ if (gps->totpoints > 2) { BKE_gpencil_stroke_normal(gps, normal); + if (is_zero_v3(normal)) { + copy_v3_fl(normal, 1.0f); + } } else { copy_v3_fl(normal, 1.0f); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index e5a6a8ffde8..3fb48292000 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -39,13 +39,6 @@ struct Main; /* OpenGL drawing functions related to shading. */ -/* Initialize - * - sets the default Blender opengl state, if in doubt, check - * the contents of this function - * - this is called when starting Blender, for opengl rendering. */ - -void GPU_state_init(void); - /* Mipmap settings * - these will free textures on changes */ diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 9ce91d31d69..4daf3f8dba5 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -40,6 +40,12 @@ typedef enum eGPUFilterFunction { GPU_LINEAR, } eGPUFilterFunction; +/* Initialize + * - sets the default Blender opengl state, if in doubt, check + * the contents of this function + * - this is called when starting Blender, for opengl rendering. */ +void GPU_state_init(void); + void GPU_blend(bool enable); void GPU_blend_set_func(eGPUBlendFunction sfactor, eGPUBlendFunction dfactor); void GPU_blend_set_func_separate(eGPUBlendFunction src_rgb, diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index e9061f1a029..cef90d57ef5 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -151,7 +151,10 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) /* Initialize vertex buffer (match 'VertexBufferFormat'). */ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC); } - GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); + if (buffers->vert_buf->data == NULL || buffers->vert_buf->vertex_len != vert_len) { + /* Allocate buffer if not allocated yet or size changed. */ + GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); + } #endif return buffers->vert_buf->data != NULL; @@ -1083,13 +1086,24 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers) return buffers->material_index; } +static void gpu_pbvh_buffers_clear(GPU_PBVH_Buffers *buffers) +{ + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); +} + void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) { /* Free empty bmesh node buffers. */ if (buffers->clear_bmesh_on_flush) { - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + gpu_pbvh_buffers_clear(buffers); buffers->clear_bmesh_on_flush = false; } @@ -1102,16 +1116,7 @@ void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); - + gpu_pbvh_buffers_clear(buffers); MEM_freeN(buffers); } } diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 5f3822c794e..7871907a7d4 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -1481,66 +1481,3 @@ void GPU_free_images_old(Main *bmain) ima = ima->id.next; } } - -static void gpu_disable_multisample(void) -{ -#ifdef __linux__ - /* changing multisample from the default (enabled) causes problems on some - * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */ - bool toggle_ok = true; - - if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) { - int samples = 0; - glGetIntegerv(GL_SAMPLES, &samples); - - if (samples == 0) { - toggle_ok = false; - } - } - - if (toggle_ok) { - glDisable(GL_MULTISAMPLE); - } -#else - glDisable(GL_MULTISAMPLE); -#endif -} - -/* Default OpenGL State - * - * This is called on startup, for opengl offscreen render. - * Generally we should always return to this state when - * temporarily modifying the state for drawing, though that are (undocumented) - * exceptions that we should try to get rid of. */ - -void GPU_state_init(void) -{ - GPU_program_point_size(false); - - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - - glDepthFunc(GL_LEQUAL); - - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDisable(GL_COLOR_LOGIC_OP); - glDisable(GL_STENCIL_TEST); - - glDepthRange(0.0, 1.0); - - glFrontFace(GL_CCW); - glCullFace(GL_BACK); - glDisable(GL_CULL_FACE); - - gpu_disable_multisample(); - - /* This is a bit dangerous since addons could change this. */ - glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex((GLuint)0xFFFFFFFF); - - /* TODO: Should become default. But needs at least GL 4.3 */ - if (GLEW_ARB_ES3_compatibility) { - /* Takes predecence over GL_PRIMITIVE_RESTART */ - glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); - } -} diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e3632b82778..ff745787630 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -304,6 +304,14 @@ void gpu_extensions_init(void) GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary; } + /* Special fix for theses specific GPUs. Without thoses workaround, blender crashes on strartup. + * (see T72098) */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && + (strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) { + GG.mip_render_workaround = true; + GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary; + } + /* df/dy calculation factors, those are dependent on driver */ GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = 1.0; diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index e6092b55fc4..5af9364b92c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -541,10 +541,6 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb) } #endif - if (fb->multisample) { - glEnable(GL_MULTISAMPLE); - } - glViewport(0, 0, fb->width, fb->height); } diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index 1caa88d18ae..3218d12bc0d 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -261,7 +261,9 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) continue; } - shaderface->enabled_attr_mask |= (1 << input->location); + if (input->location != -1) { + shaderface->enabled_attr_mask |= (1 << input->location); + } set_input_name(shaderface, input, name, name_len); diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c index d6f044a79e3..908f5fa5771 100644 --- a/source/blender/gpu/intern/gpu_state.c +++ b/source/blender/gpu/intern/gpu_state.c @@ -370,4 +370,44 @@ void gpuPopAttr(void) #undef Attr #undef AttrStack +/* Default OpenGL State + * + * This is called on startup, for opengl offscreen render. + * Generally we should always return to this state when + * temporarily modifying the state for drawing, though that are (undocumented) + * exceptions that we should try to get rid of. */ + +void GPU_state_init(void) +{ + GPU_program_point_size(false); + + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_COLOR_LOGIC_OP); + glDisable(GL_STENCIL_TEST); + glDisable(GL_DITHER); + + glDepthFunc(GL_LEQUAL); + glDepthRange(0.0, 1.0); + + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + glDisable(GL_CULL_FACE); + + /* Is default but better be explicit. */ + glEnable(GL_MULTISAMPLE); + + /* This is a bit dangerous since addons could change this. */ + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex((GLuint)0xFFFFFFFF); + + /* TODO: Should become default. But needs at least GL 4.3 */ + if (GLEW_ARB_ES3_compatibility) { + /* Takes predecence over GL_PRIMITIVE_RESTART */ + glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + } +} + /** \} */ diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index fd01ddf8597..38ba8bc612f 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -94,6 +94,7 @@ struct GPUTexture { }; static uint gpu_get_bytesize(eGPUTextureFormat data_type); +static void gpu_texture_framebuffer_ensure(GPUTexture *tex); /* ------ Memory Management ------- */ /* Records every texture allocation / free @@ -1570,25 +1571,117 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat gpu_data_format, const void *color) { - if (GLEW_ARB_clear_texture) { - GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag); + BLI_assert(color != NULL); /* Do not accept NULL as parameter. */ + gpu_validate_data_format(tex->format, gpu_data_format); + + if (false && GLEW_ARB_clear_texture) { GLenum data_type = gpu_get_gl_datatype(gpu_data_format); + GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag); glClearTexImage(tex->bindcode, 0, data_format, data_type, color); + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + } + else if (GPU_texture_depth(tex)) { + switch (gpu_data_format) { + case GPU_DATA_FLOAT: + case GPU_DATA_UNSIGNED_INT: + break; + default: + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + break; + } + } + else { + switch (gpu_data_format) { + case GPU_DATA_FLOAT: + case GPU_DATA_UNSIGNED_INT: + case GPU_DATA_UNSIGNED_BYTE: + break; + default: + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + break; + } + } } else { - size_t buffer_len = gpu_texture_memory_footprint_compute(tex); - unsigned char *pixels = MEM_mallocN(buffer_len, __func__); - if (color) { - const size_t bytesize = (size_t)gpu_get_bytesize(tex->format); - for (size_t byte = 0; byte < buffer_len; byte += bytesize) { - memcpy(&pixels[byte], color, bytesize); + /* Fallback for older GL. */ + GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); + + gpu_texture_framebuffer_ensure(tex); + /* This means that this function can only be used in one context for each texture. */ + BLI_assert(tex->copy_fb_ctx == GPU_context_active_get()); + + glBindFramebuffer(GL_FRAMEBUFFER, tex->copy_fb); + glViewport(0, 0, tex->w, tex->h); + + /* Watch: Write mask could prevent the clear. + * glClearTexImage does not change the state so we don't do it here either. */ + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + /* TODO(clem) implement. */ + BLI_assert(0); + } + else if (GPU_texture_depth(tex)) { + float depth; + switch (gpu_data_format) { + case GPU_DATA_FLOAT: { + depth = *(float *)color; + break; + } + case GPU_DATA_UNSIGNED_INT: { + depth = *(uint *)color / (float)UINT_MAX; + break; + } + default: + BLI_assert(!"Unhandled data format"); + depth = 0.0f; + break; } + glClearDepth(depth); + glClear(GL_DEPTH_BUFFER_BIT); } else { - memset(pixels, 0, buffer_len); + float r, g, b, a; + switch (gpu_data_format) { + case GPU_DATA_FLOAT: { + float *f_color = (float *)color; + r = f_color[0]; + g = (tex->components > 1) ? f_color[1] : 0.0f; + b = (tex->components > 2) ? f_color[2] : 0.0f; + a = (tex->components > 3) ? f_color[3] : 0.0f; + break; + } + case GPU_DATA_UNSIGNED_INT: { + uint *u_color = (uint *)color; + r = u_color[0] / (float)UINT_MAX; + g = (tex->components > 1) ? u_color[1] / (float)UINT_MAX : 0.0f; + b = (tex->components > 2) ? u_color[2] / (float)UINT_MAX : 0.0f; + a = (tex->components > 3) ? u_color[3] / (float)UINT_MAX : 0.0f; + break; + } + case GPU_DATA_UNSIGNED_BYTE: { + uchar *ub_color = (uchar *)color; + r = ub_color[0] / 255.0f; + g = (tex->components > 1) ? ub_color[1] / 255.0f : 0.0f; + b = (tex->components > 2) ? ub_color[2] / 255.0f : 0.0f; + a = (tex->components > 3) ? ub_color[3] / 255.0f : 0.0f; + break; + } + default: + BLI_assert(!"Unhandled data format"); + r = g = b = a = 0.0f; + break; + } + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); + } + + if (prev_fb) { + GPU_framebuffer_bind(prev_fb); } - GPU_texture_update(tex, gpu_data_format, pixels); - MEM_freeN(pixels); } } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl index 0b2bc08944e..d7cc851556b 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -12,42 +12,15 @@ /* 4bits for corner id */ #define CORNER_VEC_OFS 2u #define CORNER_VEC_RANGE BIT_RANGE(4) -const vec2 cornervec[36] = vec2[36](vec2(0.0, 1.0), - vec2(0.02, 0.805), - vec2(0.067, 0.617), - vec2(0.169, 0.45), - vec2(0.293, 0.293), - vec2(0.45, 0.169), - vec2(0.617, 0.076), - vec2(0.805, 0.02), - vec2(1.0, 0.0), - vec2(-1.0, 0.0), - vec2(-0.805, 0.02), - vec2(-0.617, 0.067), - vec2(-0.45, 0.169), - vec2(-0.293, 0.293), - vec2(-0.169, 0.45), - vec2(-0.076, 0.617), - vec2(-0.02, 0.805), - vec2(0.0, 1.0), - vec2(0.0, -1.0), - vec2(-0.02, -0.805), - vec2(-0.067, -0.617), - vec2(-0.169, -0.45), - vec2(-0.293, -0.293), - vec2(-0.45, -0.169), - vec2(-0.617, -0.076), - vec2(-0.805, -0.02), - vec2(-1.0, 0.0), - vec2(1.0, 0.0), - vec2(0.805, -0.02), - vec2(0.617, -0.067), - vec2(0.45, -0.169), - vec2(0.293, -0.293), - vec2(0.169, -0.45), - vec2(0.076, -0.617), - vec2(0.02, -0.805), - vec2(0.0, -1.0)); +const vec2 cornervec[9] = vec2[9](vec2(0.0, 1.0), + vec2(0.02, 0.805), + vec2(0.067, 0.617), + vec2(0.169, 0.45), + vec2(0.293, 0.293), + vec2(0.45, 0.169), + vec2(0.617, 0.076), + vec2(0.805, 0.02), + vec2(1.0, 0.0)); /* 4bits for jitter id */ #define JIT_OFS 6u @@ -189,26 +162,26 @@ vec2 do_widget(void) { uint cflag = vflag & CNR_FLAG_RANGE; uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE; - - vec2 v = cornervec[cflag * 9u + vofs]; - bool is_inner = (vflag & INNER_FLAG) != 0u; + vec2 v = cornervec[vofs]; /* Scale by corner radius */ v *= roundCorners[cflag] * ((is_inner) ? radsi : rads); - - /* Position to corner */ + /* Flip in the right direction and osition to corner */ vec4 rct = (is_inner) ? recti : rect; if (cflag == BOTTOM_LEFT) { v += rct.xz; } else if (cflag == BOTTOM_RIGHT) { + v = vec2(-v.y, v.x); v += rct.yz; } else if (cflag == TOP_RIGHT) { + v = -v; v += rct.yw; } else /* (cflag == TOP_LEFT) */ { + v = vec2(v.y, -v.x); v += rct.xw; } @@ -238,7 +211,7 @@ vec2 do_widget(void) } bool is_emboss = (vflag & EMBOSS_FLAG) != 0u; - v.y -= (is_emboss) ? 1.0f : 0.0; + v.y -= (is_emboss) ? (recti.z - rect.z) : 0.0; return v; } diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 6c17254e697..4b3858e6d5a 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -380,7 +380,7 @@ void *imb_alloc_pixels( } size_t size = (size_t)x * (size_t)y * (size_t)channels * typesize; - return MEM_mapallocN(size, name); + return MEM_callocN(size, name); } bool imb_addrectfloatImBuf(ImBuf *ibuf) diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c index 176b41d2706..23ce9bd7818 100644 --- a/source/blender/imbuf/intern/cache.c +++ b/source/blender/imbuf/intern/cache.c @@ -427,8 +427,8 @@ void IMB_tiles_to_rect(ImBuf *ibuf) /* don't call imb_addrectImBuf, it frees all mipmaps */ if (!mipbuf->rect) { - if ((mipbuf->rect = MEM_mapallocN(ibuf->x * ibuf->y * sizeof(unsigned int), - "imb_addrectImBuf"))) { + if ((mipbuf->rect = MEM_callocN(ibuf->x * ibuf->y * sizeof(unsigned int), + "imb_addrectImBuf"))) { mipbuf->mall |= IB_rect; mipbuf->flags |= IB_rect; } diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index e068a84aab0..bcc8488089d 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -788,7 +788,7 @@ void IMB_float_from_rect(ImBuf *ibuf) size = size * 4 * sizeof(float); ibuf->channels = 4; - rect_float = MEM_mapallocN(size, "IMB_float_from_rect"); + rect_float = MEM_callocN(size, "IMB_float_from_rect"); if (rect_float == NULL) { return; diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 62cc2e605e5..882808cbc14 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1598,8 +1598,8 @@ static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) { for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) { if (pass->totchan) { - pass->rect = (float *)MEM_mapallocN(width * height * pass->totchan * sizeof(float), - "pass rect"); + pass->rect = (float *)MEM_callocN(width * height * pass->totchan * sizeof(float), + "pass rect"); if (pass->totchan == 1) { echan = pass->chan[0]; echan->rect = pass->rect; diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 40a057f9a20..62f6a52f7cf 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -144,7 +144,7 @@ const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, Custom * - (optional due to its behavior) tag as UV using Alembic::AbcGeom::SetIsUV */ static void write_uv(const OCompoundProperty &prop, - const CDStreamConfig &config, + CDStreamConfig &config, void *data, const char *name) { @@ -157,13 +157,18 @@ static void write_uv(const OCompoundProperty &prop, return; } - OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1); + std::string uv_map_name(name); + OV2fGeomParam param = config.abc_uv_maps[uv_map_name]; + if (!param.valid()) { + param = OV2fGeomParam(prop, name, true, kFacevaryingScope, 1); + } OV2fGeomParam::Sample sample(V2fArraySample(&uvs.front(), uvs.size()), UInt32ArraySample(&indices.front(), indices.size()), kFacevaryingScope); - param.set(sample); + + config.abc_uv_maps[uv_map_name] = param; } /* Convention to write Vertex Colors: @@ -217,7 +222,7 @@ static void write_mcol(const OCompoundProperty &prop, } void write_custom_data(const OCompoundProperty &prop, - const CDStreamConfig &config, + CDStreamConfig &config, CustomData *data, int data_type) { diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h index 04572c736af..96b57b08681 100644 --- a/source/blender/io/alembic/intern/abc_customdata.h +++ b/source/blender/io/alembic/intern/abc_customdata.h @@ -27,6 +27,8 @@ #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> +#include <map> + struct CustomData; struct MLoop; struct MLoopUV; @@ -70,6 +72,12 @@ struct CDStreamConfig { const char **modifier_error_message; + /* Alembic needs Blender to keep references to C++ objects (the destructors + * finalize the writing to ABC). This map stores OV2fGeomParam objects for the + * 2nd and subsequent UV maps; the primary UV map is kept alive by the Alembic + * mesh sample itself. */ + std::map<std::string, Alembic::AbcGeom::OV2fGeomParam> abc_uv_maps; + CDStreamConfig() : mloop(NULL), totloop(0), @@ -95,7 +103,7 @@ struct CDStreamConfig { const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data); void write_custom_data(const OCompoundProperty &prop, - const CDStreamConfig &config, + CDStreamConfig &config, CustomData *data, int data_type); diff --git a/source/blender/io/alembic/intern/abc_reader_nurbs.cc b/source/blender/io/alembic/intern/abc_reader_nurbs.cc index 10d9a35a8e1..5b9954b3ff6 100644 --- a/source/blender/io/alembic/intern/abc_reader_nurbs.cc +++ b/source/blender/io/alembic/intern/abc_reader_nurbs.cc @@ -71,7 +71,7 @@ bool AbcNurbsReader::valid() const static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots) { - if (!knots || knots->size() == 0) { + if (!knots || knots->size() < 2) { return false; } diff --git a/source/blender/io/alembic/intern/abc_writer_archive.cc b/source/blender/io/alembic/intern/abc_writer_archive.cc index 5aae1f05f4b..e7dee536cb9 100644 --- a/source/blender/io/alembic/intern/abc_writer_archive.cc +++ b/source/blender/io/alembic/intern/abc_writer_archive.cc @@ -52,7 +52,7 @@ static OArchive create_archive(std::ostream *ostream, abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender"); abc_metadata.set(Alembic::Abc::kUserDescriptionKey, scene_name); - abc_metadata.set("blender_version", versionstr); + abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string()); abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps)); time_t raw_time; diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index 987a3cacb3b..6ca9e82a26c 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -875,8 +875,7 @@ bool ABC_import(bContext *C, bool validate_meshes, bool as_background_job) { - /* Using new here since MEM_* funcs do not call ctor to properly initialize - * data. */ + /* Using new here since MEM_* functions do not call constructor to properly initialize data. */ ImportJobData *job = new ImportJobData(); job->bmain = CTX_data_main(C); job->scene = CTX_data_scene(C); diff --git a/source/blender/io/avi/intern/avi_mjpeg.c b/source/blender/io/avi/intern/avi_mjpeg.c index ac622d8b0e4..70ddca28060 100644 --- a/source/blender/io/avi/intern/avi_mjpeg.c +++ b/source/blender/io/avi/intern/avi_mjpeg.c @@ -30,6 +30,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_math_base.h" #include "IMB_imbuf.h" #include "jerror.h" @@ -45,14 +46,16 @@ static size_t numbytes; static void add_huff_table(j_decompress_ptr dinfo, JHUFF_TBL **htblptr, const UINT8 *bits, - const UINT8 *val) + const size_t bits_size, + const UINT8 *val, + const size_t val_size) { if (*htblptr == NULL) { *htblptr = jpeg_alloc_huff_table((j_common_ptr)dinfo); } - memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits)); - memcpy((*htblptr)->huffval, val, sizeof((*htblptr)->huffval)); + memcpy((*htblptr)->bits, bits, min_zz(sizeof((*htblptr)->bits), bits_size)); + memcpy((*htblptr)->huffval, val, min_zz(sizeof((*htblptr)->huffval), val_size)); /* Initialize sent_table false so table will be written to JPEG file. */ (*htblptr)->sent_table = false; @@ -200,10 +203,30 @@ static void std_huff_tables(j_decompress_ptr dinfo) 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, }; - add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[0], bits_dc_luminance, val_dc_luminance); - add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[0], bits_ac_luminance, val_ac_luminance); - add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[1], bits_dc_chrominance, val_dc_chrominance); - add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[1], bits_ac_chrominance, val_ac_chrominance); + add_huff_table(dinfo, + &dinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, + sizeof(bits_dc_luminance), + val_dc_luminance, + sizeof(val_dc_luminance)); + add_huff_table(dinfo, + &dinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, + sizeof(bits_ac_luminance), + val_ac_luminance, + sizeof(val_ac_luminance)); + add_huff_table(dinfo, + &dinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, + sizeof(bits_dc_chrominance), + val_dc_chrominance, + sizeof(val_dc_chrominance)); + add_huff_table(dinfo, + &dinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, + sizeof(bits_ac_chrominance), + val_ac_chrominance, + sizeof(val_ac_chrominance)); } static int Decode_JPEG(unsigned char *inBuffer, diff --git a/source/blender/io/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp index b890d4cf018..0578bf45f04 100644 --- a/source/blender/io/collada/DocumentExporter.cpp +++ b/source/blender/io/collada/DocumentExporter.cpp @@ -243,20 +243,13 @@ int DocumentExporter::exportCurrentScene() #ifdef WITH_BUILDINFO BLI_snprintf(version_buf, sizeof(version_buf), - "Blender %d.%02d.%d commit date:%s, commit time:%s, hash:%s", - BLENDER_VERSION / 100, - BLENDER_VERSION % 100, - BLENDER_SUBVERSION, + "Blender %s commit date:%s, commit time:%s, hash:%s", + BKE_blender_version_string(), build_commit_date, build_commit_time, build_hash); #else - BLI_snprintf(version_buf, - sizeof(version_buf), - "Blender %d.%02d.%d", - BLENDER_VERSION / 100, - BLENDER_VERSION % 100, - BLENDER_SUBVERSION); + BLI_snprintf(version_buf, sizeof(version_buf), "Blender %s", BKE_blender_version_string()); #endif asset.getContributor().mAuthoringTool = version_buf; asset.add(); diff --git a/source/blender/io/collada/ErrorHandler.h b/source/blender/io/collada/ErrorHandler.h index 9789e93cee9..0c082a3b9dd 100644 --- a/source/blender/io/collada/ErrorHandler.h +++ b/source/blender/io/collada/ErrorHandler.h @@ -46,7 +46,7 @@ class ErrorHandler : public COLLADASaxFWL::IErrorHandler { } private: - /** Disable default copy ctor. */ + /** Disable default copy constructor. */ ErrorHandler(const ErrorHandler &pre); /** Disable default assignment operator. */ const ErrorHandler &operator=(const ErrorHandler &pre); diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc index e382fa6bb1d..ab83ea2c3c4 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc @@ -53,7 +53,7 @@ bool HierarchyContext::operator<(const HierarchyContext &other) const if (object != other.object) { return object < other.object; } - if (duplicator != NULL && duplicator == other.duplicator) { + if (duplicator != nullptr && duplicator == other.duplicator) { // Only resort to string comparisons when both objects are created by the same duplicator. return export_name < other.export_name; } diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc index f8e0a03abfa..cf962446d04 100644 --- a/source/blender/io/usd/intern/usd_capi.cc +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -91,7 +91,8 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z)); usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit, pxr::VtValue(scene->unit.scale_length)); - usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender ") + versionstr); + usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender v") + + BKE_blender_version_string()); // Set up the stage for animated data. if (data->params.export_animation) { @@ -185,7 +186,7 @@ bool USD_export(bContext *C, /* setup job */ WM_jobs_customdata_set(wm_job, job, MEM_freeN); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, USD::export_startjob, NULL, NULL, USD::export_endjob); + WM_jobs_callbacks(wm_job, USD::export_startjob, nullptr, nullptr, USD::export_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 909869d2af1..841501bcf42 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -79,7 +79,7 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context) bool needsfree = false; Mesh *mesh = get_export_mesh(object_eval, needsfree); - if (mesh == NULL) { + if (mesh == nullptr) { return; } @@ -100,7 +100,7 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context) void USDGenericMeshWriter::free_export_mesh(Mesh *mesh) { - BKE_id_free(NULL, mesh); + BKE_id_free(nullptr, mesh); } struct USDMeshData { diff --git a/source/blender/io/usd/intern/usd_writer_transform.cc b/source/blender/io/usd/intern/usd_writer_transform.cc index 038f2b17b1a..0694d873002 100644 --- a/source/blender/io/usd/intern/usd_writer_transform.cc +++ b/source/blender/io/usd/intern/usd_writer_transform.cc @@ -50,7 +50,7 @@ void USDTransformWriter::do_write(HierarchyContext &context) bool USDTransformWriter::check_is_animated(const HierarchyContext &context) const { - if (context.duplicator != NULL) { + if (context.duplicator != nullptr) { /* This object is being duplicated, so could be emitted by a particle system and thus * influenced by forces. TODO(Sybren): Make this more strict. Probably better to get from the * depsgraph whether this object instance has a time source. */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 39f22fb9555..4f2bbc4ee73 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -327,7 +327,7 @@ typedef struct Library { /* Temp data needed by read/write code. */ int temp_index; - /** See BLENDER_VERSION, BLENDER_SUBVERSION, needed for do_versions. */ + /** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */ short versionfile, subversionfile; } Library; diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index e9db43e9ba8..a747ed3be11 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -331,6 +331,11 @@ typedef enum eBrushClothForceFalloffType { BRUSH_CLOTH_FORCE_FALLOFF_PLANE = 1, } eBrushClothForceFalloffType; +typedef enum eBrushPoseDeformType { + BRUSH_POSE_DEFORM_ROTATE_TWIST = 0, + BRUSH_POSE_DEFORM_SCALE_TRASLATE = 1, +} eBrushPoseDeformType; + typedef enum eBrushPoseOriginType { BRUSH_POSE_ORIGIN_TOPOLOGY = 0, BRUSH_POSE_ORIGIN_FACE_SETS = 1, @@ -488,7 +493,7 @@ typedef struct Brush { char gpencil_sculpt_tool; /** Active grease pencil weight tool. */ char gpencil_weight_tool; - char _pad1[6]; + char _pad1[2]; float autosmooth_factor; @@ -520,6 +525,7 @@ typedef struct Brush { float elastic_deform_volume_preservation; /* pose */ + int pose_deform_type; float pose_offset; int pose_smooth_iterations; int pose_ik_segments; diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 6a081a7f5a7..b2902407a15 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -496,11 +496,11 @@ typedef enum eBezTriple_KeyframeType { #define BEZT_ISSEL_ALL(bezt) \ (((bezt)->f2 & SELECT) && ((bezt)->f1 & SELECT) && ((bezt)->f3 & SELECT)) #define BEZT_ISSEL_ALL_HIDDENHANDLES(v3d, bezt) \ - ((((v3d) != NULL) && ((v3d)->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) ? \ + ((((v3d) != NULL) && ((v3d)->overlay.handle_display == CURVE_HANDLE_NONE)) ? \ (bezt)->f2 & SELECT : \ BEZT_ISSEL_ALL(bezt)) #define BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) \ - ((((v3d) != NULL) && ((v3d)->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) ? \ + ((((v3d) != NULL) && ((v3d)->overlay.handle_display == CURVE_HANDLE_NONE)) ? \ (bezt)->f2 & SELECT : \ BEZT_ISSEL_ANY(bezt)) diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index e99d7fd5609..ef3b2015758 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -76,7 +76,8 @@ typedef struct CustomData { * MUST be >= CD_NUMTYPES, but we cant use a define here. * Correct size is ensured in CustomData_update_typemap assert(). */ - int typemap[47]; + int typemap[48]; + char _pad[4]; /** Number of layers, size of layers array. */ int totlayer, maxlayer; /** In editmode, total size of all data layers. */ @@ -153,7 +154,9 @@ typedef enum CustomDataType { CD_HAIRCURVE = 45, CD_HAIRMAPPING = 46, - CD_NUMTYPES = 47, + CD_PROP_COLOR = 47, + + CD_NUMTYPES = 48, } CustomDataType; /* Bits for CustomDataMask */ @@ -202,6 +205,7 @@ typedef enum CustomDataType { #define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL) #define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL) #define CD_MASK_SCULPT_FACE_SETS (1LL << CD_SCULPT_FACE_SETS) +#define CD_MASK_PROP_COLOR (1LL << CD_PROP_COLOR) /** Data types that may be defined for all mesh elements types. */ #define CD_MASK_GENERIC_DATA (CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR) diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 6583aa2eeee..7da33a369f3 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -215,39 +215,54 @@ enum { #define FLUID_DOMAIN_SMOKE_SCRIPT "smoke_script.py" #define FLUID_DOMAIN_LIQUID_SCRIPT "liquid_script.py" -#define FLUID_DOMAIN_FILE_CONFIG "config_####" - -#define FLUID_DOMAIN_FILE_DENSITY "density_####" -#define FLUID_DOMAIN_FILE_SHADOW "shadow_####" -#define FLUID_DOMAIN_FILE_VEL "vel_####" -#define FLUID_DOMAIN_FILE_HEAT "heat_####" -#define FLUID_DOMAIN_FILE_COLORR "color_r_####" -#define FLUID_DOMAIN_FILE_COLORG "color_g_####" -#define FLUID_DOMAIN_FILE_COLORB "color_b_####" -#define FLUID_DOMAIN_FILE_FLAME "flame_####" -#define FLUID_DOMAIN_FILE_FUEL "fuel_####" -#define FLUID_DOMAIN_FILE_REACT "react_####" - -#define FLUID_DOMAIN_FILE_PHI "phi_####" -#define FLUID_DOMAIN_FILE_PP "pp_####" -#define FLUID_DOMAIN_FILE_PVEL "pVel_####" - -#define FLUID_DOMAIN_FILE_DENSITYNOISE "density_noise_####" -#define FLUID_DOMAIN_FILE_COLORRNOISE "color_r_noise_####" -#define FLUID_DOMAIN_FILE_COLORGNOISE "color_g_noise_####" -#define FLUID_DOMAIN_FILE_COLORBNOISE "color_b_noise_####" -#define FLUID_DOMAIN_FILE_FLAMENOISE "flame_noise_####" -#define FLUID_DOMAIN_FILE_FUELNOISE "fuel_noise_####" -#define FLUID_DOMAIN_FILE_REACTNOISE "react_noise_####" - -#define FLUID_DOMAIN_FILE_MESH "lMesh_####" -#define FLUID_DOMAIN_FILE_MESHVEL "lVelMesh_####" - -#define FLUID_DOMAIN_FILE_PPSND "ppSnd_####" -#define FLUID_DOMAIN_FILE_PVELSND "pVelSnd_####" -#define FLUID_DOMAIN_FILE_PLIFESND "pLifeSnd_####" - -#define FLUID_DOMAIN_FILE_GUIDEVEL "guidevel_####" +#define FLUID_FILENAME_CONFIG "config_####" + +#define FLUID_FILENAME_DATA "fluid_data_####" +#define FLUID_FILENAME_NOISE "fluid_noise_####" +#define FLUID_FILENAME_DENSITY "density_####" +#define FLUID_FILENAME_SHADOW "shadow_####" +#define FLUID_FILENAME_VELOCITY "vel_####" +#define FLUID_FILENAME_HEAT "heat_####" +#define FLUID_FILENAME_COLORR "color_r_####" +#define FLUID_FILENAME_COLORG "color_g_####" +#define FLUID_FILENAME_COLORB "color_b_####" +#define FLUID_FILENAME_FLAME "flame_####" +#define FLUID_FILENAME_FUEL "fuel_####" +#define FLUID_FILENAME_REACT "react_####" +#define FLUID_FILENAME_PHI "phi_####" +#define FLUID_FILENAME_PP "pp_####" +#define FLUID_FILENAME_PVEL "pVel_####" +#define FLUID_FILENAME_DENSITYNOISE "density_noise_####" +#define FLUID_FILENAME_COLORRNOISE "color_r_noise_####" +#define FLUID_FILENAME_COLORGNOISE "color_g_noise_####" +#define FLUID_FILENAME_COLORBNOISE "color_b_noise_####" +#define FLUID_FILENAME_FLAMENOISE "flame_noise_####" +#define FLUID_FILENAME_FUELNOISE "fuel_noise_####" +#define FLUID_FILENAME_REACTNOISE "react_noise_####" +#define FLUID_FILENAME_MESH "lMesh_####" +#define FLUID_FILENAME_MESHVEL "lVelMesh_####" +#define FLUID_FILENAME_PPSND "ppSnd_####" +#define FLUID_FILENAME_PVELSND "pVelSnd_####" +#define FLUID_FILENAME_PLIFESND "pLifeSnd_####" +#define FLUID_FILENAME_GUIDEVEL "guidevel_####" + +#define FLUID_GRIDNAME_DENSITY "density" +#define FLUID_GRIDNAME_SHADOW "shadow" +#define FLUID_GRIDNAME_VELOCITY "velocity" +#define FLUID_GRIDNAME_HEAT "heat" +#define FLUID_GRIDNAME_COLORR "color_r" +#define FLUID_GRIDNAME_COLORG "color_g" +#define FLUID_GRIDNAME_COLORB "color_b" +#define FLUID_GRIDNAME_FLAME "flame" +#define FLUID_GRIDNAME_FUEL "fuel" +#define FLUID_GRIDNAME_REACT "react" +#define FLUID_GRIDNAME_DENSITYNOISE "density_noise" +#define FLUID_GRIDNAME_COLORRNOISE "color_r_noise" +#define FLUID_GRIDNAME_COLORGNOISE "color_g_noise" +#define FLUID_GRIDNAME_COLORBNOISE "color_b_noise" +#define FLUID_GRIDNAME_FLAMENOISE "flame_noise" +#define FLUID_GRIDNAME_FUELNOISE "fuel_noise" +#define FLUID_GRIDNAME_REACTNOISE "react_noise" #define FLUID_DOMAIN_EXTENSION_UNI ".uni" #define FLUID_DOMAIN_EXTENSION_OPENVDB ".vdb" @@ -256,6 +271,17 @@ enum { #define FLUID_DOMAIN_EXTENSION_BINOBJ ".bobj.gz" enum { + FLUID_DOMAIN_GRID_FLOAT = 0, + FLUID_DOMAIN_GRID_INT = 1, + FLUID_DOMAIN_GRID_VEC3F = 2, +}; + +enum { + FLUID_DOMAIN_CACHE_FILES_SINGLE = 0, + FLUID_DOMAIN_CACHE_FILES_COMBINED = 1, +}; + +enum { FLUID_DOMAIN_CACHE_REPLAY = 0, FLUID_DOMAIN_CACHE_MODULAR = 1, FLUID_DOMAIN_CACHE_FINAL = 2, diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index dc1a2b5ff1d..029352f3d85 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -112,7 +112,20 @@ typedef struct Mesh_Runtime { * In the future we may leave the mesh-data empty * since its not needed if we can use edit-mesh data. */ char is_original; - char _pad[6]; + + /** #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; + + char _pad[4]; + + /** Needed in case we need to lazily initialize the mesh. */ + CustomData_MeshMasks cd_mask_extra; + } Mesh_Runtime; typedef struct Mesh { @@ -228,6 +241,15 @@ 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, + /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */ +} eMeshWrapperType; + /* texflag */ enum { ME_AUTOSPACE = 1, diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index f48024cd55a..04deecde43e 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -344,6 +344,10 @@ typedef struct MLoopCol { unsigned char r, g, b, a; } MLoopCol; +typedef struct MPropCol { + float col[4]; +} MPropCol; + /** Multi-Resolution loop data. */ typedef struct MDisps { /* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 972ef197954..13972ae032d 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1416,7 +1416,7 @@ typedef struct WeightVGEditModifierData { /* WeightVGEdit flags. */ enum { - /* (1 << 0) is free for future use! */ + MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0), MOD_WVG_INVERT_FALLOFF = (1 << 1), MOD_WVG_EDIT_INVERT_VGROUP_MASK = (1 << 2), /** Add vertices with higher weight than threshold to vgroup. */ @@ -1504,6 +1504,9 @@ enum { /* WeightVGMix->flag */ enum { MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0), + MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1), + MOD_WVG_MIX_INVERT_VGROUP_A = (1 << 2), + MOD_WVG_MIX_INVERT_VGROUP_B = (1 << 3), }; typedef struct WeightVGProximityModifierData { @@ -1566,6 +1569,7 @@ enum { MOD_WVG_PROXIMITY_GEOM_FACES = (1 << 2), MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK = (1 << 3), MOD_WVG_PROXIMITY_INVERT_FALLOFF = (1 << 4), + MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE = (1 << 3), }; /* Defines common to all WeightVG modifiers. */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ecd2f115e4a..18cd3872d1f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -553,13 +553,14 @@ typedef struct BakeData { short margin, flag; float cage_extrusion; + float max_ray_distance; int pass_filter; char normal_swizzle[3]; char normal_space; char save_mode; - char _pad[3]; + char _pad[7]; struct Object *cage_object; } BakeData; diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 8497d363179..07cba2bad1c 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -132,7 +132,9 @@ typedef struct ScrAreaMap { typedef struct Panel_Runtime { /* Applied to Panel.ofsx, but saved separately so we can track changes between redraws. */ int region_ofsx; - char _pad[4]; + + /* For instanced panels: Index of the list item the panel corresponds to. */ + int list_index; } Panel_Runtime; /** The part from uiBlock that needs saved in file. */ @@ -531,6 +533,8 @@ enum { PNL_OVERLAP = (1 << 4), PNL_PIN = (1 << 5), PNL_POPOVER = (1 << 6), + /** The panel has been drag-drop reordered and the instanced panel list needs to be rebuilt. */ + PNL_INSTANCED_LIST_ORDER_CHANGED = (1 << 7), }; /** #Panel.snap - for snapping to screen edges */ @@ -543,9 +547,17 @@ enum { /* #define PNL_SNAP_DIST 9.0 */ /* paneltype flag */ -#define PNL_DEFAULT_CLOSED 1 -#define PNL_NO_HEADER 2 -#define PNL_LAYOUT_VERT_BAR 4 +enum { + PNL_DEFAULT_CLOSED = (1 << 0), + PNL_NO_HEADER = (1 << 1), + /** Makes buttons in the header shrink/stretch to fill full layout width. */ + PNL_LAYOUT_HEADER_EXPAND = (1 << 2), + PNL_LAYOUT_VERT_BAR = (1 << 3), + /** This panel type represents data external to the UI. */ + PNL_INSTANCED = (1 << 4), + /** Draw panel like a box widget. */ + PNL_DRAW_BOX = (1 << 6), +}; /* Fallback panel category (only for old scripts which need updating) */ #define PNL_CATEGORY_FALLBACK "Misc" diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 282fa5f6b90..d3d86216843 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -835,9 +835,10 @@ typedef enum eFileSel_Params_RenameFlag { FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE = 1 << 3, } eFileSel_Params_RenameFlag; -/* files in filesel list: file types - * Note we could use mere values (instead of bitflags) for file types themselves, - * but since we do not lack of bytes currently... +/** + * Files in the file selector list: file types + * Note we could use mere values (instead of bit-flags) for file types themselves, + * but since we do not lack of bytes currently. */ typedef enum eFileSel_File_Types { FILE_TYPE_BLENDER = (1 << 2), diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h index afade37d0c8..10eadf368ef 100644 --- a/source/blender/makesdna/DNA_view3d_defaults.h +++ b/source/blender/makesdna/DNA_view3d_defaults.h @@ -64,8 +64,8 @@ .edit_flag = V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | \ V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | \ V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | \ - V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | \ - V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS, \ + V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS, \ + .handle_display = CURVE_HANDLE_SELECTED, \ \ .gpencil_paper_opacity = 0.5f, \ .gpencil_grid_opacity = 0.9f, \ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 6d8d16c4313..ef174f5858f 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -228,9 +228,20 @@ typedef struct View3DOverlay { /** Factor for mixing vertex paint with original color */ float gpencil_vertex_paint_opacity; - char _pad4[4]; + /** Handles display type for curves. */ + int handle_display; } View3DOverlay; +/* View3DOverlay->handle_display */ +typedef enum eHandleDisplay { + /* Display only selected points. */ + CURVE_HANDLE_SELECTED = 0, + /* Display all handles. */ + CURVE_HANDLE_ALL = 1, + /* No display handles. */ + CURVE_HANDLE_NONE = 2, +} eHandleDisplay; + typedef struct View3D_Runtime { /** Nkey panel stores stuff here. */ void *properties_storage; @@ -522,7 +533,9 @@ enum { V3D_OVERLAY_EDIT_FACE_AREA = (1 << 18), V3D_OVERLAY_EDIT_INDICES = (1 << 19), - V3D_OVERLAY_EDIT_CU_HANDLES = (1 << 20), + /* Deprecated. */ + /* V3D_OVERLAY_EDIT_CU_HANDLES = (1 << 20), */ + V3D_OVERLAY_EDIT_CU_NORMALS = (1 << 21), }; diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 1b0bf086269..01e3971a216 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -58,6 +58,10 @@ setup_platform_linker_flags() add_executable(makesdna ${SRC} ${SRC_DNA_INC}) +if(WIN32 AND NOT UNIX) + target_link_libraries(makesdna ${PTHREADS_LIBRARIES}) +endif() + # Output dna.c add_custom_command( OUTPUT diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 7c4fda88eca..709b47e73c3 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -71,6 +71,7 @@ extern StructRNA RNA_BackgroundImage; extern StructRNA RNA_BevelModifier; extern StructRNA RNA_BezierSplinePoint; extern StructRNA RNA_BlendData; +extern StructRNA RNA_BlendDataLibraries; extern StructRNA RNA_BlendTexture; extern StructRNA RNA_BlenderRNA; extern StructRNA RNA_BoidRule; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 8413552c54d..a83c8697329 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -399,6 +399,10 @@ add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC}) target_link_libraries(makesrna bf_dna) target_link_libraries(makesrna bf_dna_blenlib) +if(WIN32 AND NOT UNIX) + target_link_libraries(makesrna ${PTHREADS_LIBRARIES}) +endif() + # Output rna_*_gen.c # note (linux only): with crashes try add this after COMMAND: valgrind --leak-check=full --track-origins=yes add_custom_command( diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index cc55f379718..85bd17c737e 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1823,6 +1823,10 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) case PROP_ENUM: { EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop; + if (!eprop->get && !eprop->set) { + rna_set_raw_property(dp, prop); + } + eprop->get = (void *)rna_def_property_get_func(f, srna, prop, dp, (const char *)eprop->get); eprop->set = (void *)rna_def_property_set_func(f, srna, prop, dp, (const char *)eprop->set); break; @@ -4706,7 +4710,8 @@ static const char *cpp_classes = " DynamicArray() : data(NULL), length(0) {}\n" " DynamicArray(int new_length) : data(NULL), length(new_length) { data = (T " "*)malloc(sizeof(T) * new_length); }\n" - " DynamicArray(const DynamicArray<T>& other) { copy_from(other); }\n" + " DynamicArray(const DynamicArray<T>& other) : data(NULL), length(0) { copy_from(other); " + "}\n" " const DynamicArray<T>& operator = (const DynamicArray<T>& other) { copy_from(other); " "return *this; }\n" "\n" diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 85892758a88..f14e81a38df 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4386,8 +4386,8 @@ static int rna_raw_access(ReportList *reports, /* check type */ itemtype = RNA_property_type(itemprop); - if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { - BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported"); + if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) { + BKE_report(reports, RPT_ERROR, "Only boolean, int float and enum properties supported"); return 0; } diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index a3a89db66be..facbf8d59cc 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -345,14 +345,14 @@ static void rna_def_dopesheet(BlenderRNA *brna) prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLYSEL); RNA_def_property_ui_text( - prop, "Only Selected", "Only include channels relating to selected objects and data"); + prop, "Only Show Selected", "Only include channels relating to selected objects and data"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); prop = RNA_def_property(srna, "show_hidden", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_INCL_HIDDEN); RNA_def_property_ui_text( - prop, "Display Hidden", "Include channels from objects/bone that are not visible"); + prop, "Show Hidden", "Include channels from objects/bone that are not visible"); RNA_def_property_ui_icon(prop, ICON_OBJECT_HIDDEN, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); @@ -368,8 +368,9 @@ static void rna_def_dopesheet(BlenderRNA *brna) /* Debug Filtering Settings */ prop = RNA_def_property(srna, "show_only_errors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLY_ERRORS); - RNA_def_property_ui_text( - prop, "Show Errors", "Only include F-Curves and drivers that are disabled or have errors"); + RNA_def_property_ui_text(prop, + "Only Show Errors", + "Only include F-Curves and drivers that are disabled or have errors"); RNA_def_property_ui_icon(prop, ICON_ERROR, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 3afbd0405fe..8454d5c125f 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -176,6 +176,20 @@ static void rna_Armature_redraw_data(Main *UNUSED(bmain), Scene *UNUSED(scene), WM_main_add_notifier(NC_GEOM | ND_DATA, id); } +/* Unselect bones when hidden */ +static void rna_Bone_hide_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + bArmature *arm = (bArmature *)ptr->owner_id; + Bone *bone = (Bone *)ptr->data; + + if (bone->flag & BONE_HIDDEN_P) { + bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + + WM_main_add_notifier(NC_OBJECT | ND_POSE, arm); + DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); +} + /* called whenever a bone is renamed */ static void rna_Bone_update_renamed(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -301,8 +315,7 @@ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values) Bone *bone = (Bone *)ptr->data; rna_bone_layer_set(&bone->layer, values); - - BKE_armature_refresh_layer_used(arm); + BKE_armature_refresh_layer_used(NULL, arm); } /* TODO: remove the deprecation stubs. */ @@ -1144,7 +1157,8 @@ static void rna_def_bone(BlenderRNA *brna) prop, "Hide", "Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes)"); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); + RNA_def_property_update(prop, 0, "rna_Bone_hide_update"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED); @@ -1313,7 +1327,7 @@ static void rna_def_edit_bone(BlenderRNA *brna) prop, "Editbone Matrix", "Matrix combining loc/rot of the bone (head position, direction and roll), " - "in armature space (WARNING: does not include/support bone's length/size)"); + "in armature space (does not include/support bone's length/size)"); RNA_def_property_float_funcs(prop, "rna_EditBone_matrix_get", "rna_EditBone_matrix_set", NULL); RNA_api_armature_edit_bone(srna); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index d3b607fcb76..9e78eec9c25 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1960,6 +1960,12 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_pose_deform_type_items[] = { + {BRUSH_POSE_DEFORM_ROTATE_TWIST, "ROTATE_TWIST", 0, "Rotate/Twist", ""}, + {BRUSH_POSE_DEFORM_SCALE_TRASLATE, "SCALE_TRANSLATE", 0, "Scale/Translate", ""}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_pose_origin_type_items[] = { {BRUSH_POSE_ORIGIN_TOPOLOGY, "TOPOLOGY", @@ -2095,6 +2101,11 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "pose_deform_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_pose_deform_type_items); + RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "pose_origin_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, brush_pose_origin_type_items); RNA_def_property_ui_text(prop, diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index fff39326ada..93c7c1f3480 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -1725,7 +1725,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) "resolution of the domain). For best meshing, it is recommended to " "adjust the mesh particle radius alongside this value"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset"); prop = RNA_def_property(srna, "mesh_generator", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mesh_generator"); @@ -1754,7 +1754,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) "Caches velocities of mesh vertices. These will be used " "(automatically) when rendering with motion blur enabled"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset"); prop = RNA_def_property(srna, "mesh_particle_radius", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0, 10.0); @@ -2516,7 +2516,7 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_inflow", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_INFLOW); - RNA_def_property_ui_text(prop, "Enabled", "Control when to apply inflow"); + RNA_def_property_ui_text(prop, "Use Flow", "Control when to apply fluid flow"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset"); prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 33bf174be79..a52811a9a9a 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -121,7 +121,7 @@ static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = { {eGplBlendMode_Divide, "DIVIDE", 0, "Divide", ""}, {0, NULL, 0, NULL, NULL}}; -static EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { +static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { {GP_STROKE_CAP_ROUND, "ROUND", 0, "Rounded", ""}, {GP_STROKE_CAP_FLAT, "FLAT", 0, "Flat", ""}, {0, NULL, 0, NULL, NULL}, @@ -1187,7 +1187,6 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna) * (this is a special flag for fill brush). */ prop = RNA_def_property(srna, "is_nofill_stroke", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_NOFILL); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "No Fill", "Special stroke to use as boundary for filling areas"); RNA_def_property_update(prop, 0, "rna_GPencil_update"); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 48e3c47208f..f5a437b7892 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2813,7 +2813,7 @@ static void rna_def_modifier_array(BlenderRNA *brna) prop, NULL, "rna_ArrayModifier_start_cap_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "end_cap", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "End Cap", "Mesh object to use as an end cap"); @@ -4888,6 +4888,14 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert Falloff", "Invert the resulting falloff weight"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "edit_flags", MOD_WVG_EDIT_WEIGHTS_NORMALIZE); + RNA_def_property_ui_text( + prop, + "Normalize Weights", + "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "map_curve", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "cmap_curve"); RNA_def_property_ui_text(prop, "Mapping Curve", "Custom mapping curve"); @@ -5004,6 +5012,16 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna) RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGMixModifier_defgrp_name_b_set"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "invert_vertex_group_a", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_A); + RNA_def_property_ui_text(prop, "Invert Weights A", "Invert the influence of vertex group A"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_vertex_group_b", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_B); + RNA_def_property_ui_text(prop, "Invert Weights B", "Invert the influence of vertex group B"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "default_weight_a", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1); @@ -5045,6 +5063,14 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_MASK); RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_WEIGHTS_NORMALIZE); + RNA_def_property_ui_text( + prop, + "Normalize Weights", + "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) @@ -5151,6 +5177,15 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invert Falloff", "Invert the resulting falloff weight"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, NULL, "proximity_flags", MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE); + RNA_def_property_ui_text( + prop, + "Normalize Weights", + "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + /* Common masking properties. */ rna_def_modifier_weightvg_mask(brna, srna, diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index d7e5085e1c5..1fffd6530e6 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2994,6 +2994,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "matrix_parent_inverse", PROP_FLOAT, PROP_MATRIX); RNA_def_property_float_sdna(prop, NULL, "parentinv"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Parent Inverse Matrix", "Inverse of object's parent matrix at time of parenting"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 2c9bdd31141..3b80714bcc5 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -41,6 +41,8 @@ #include "DEG_depsgraph.h" +#include "ED_outliner.h" + #include "rna_internal.h" /* own include */ static const EnumPropertyItem space_items[] = { @@ -114,6 +116,7 @@ static void rna_Object_select_set( Scene *scene = CTX_data_scene(C); DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); + ED_outliner_select_sync_from_object_tag(C); } static bool rna_Object_select_get(Object *ob, bContext *C, ViewLayer *view_layer) diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 17e5f3d3649..8f28fc56712 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -295,6 +295,18 @@ static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value) ED_armature_bone_rename(G_MAIN, ob->data, oldname, newname); } +/* See rna_Bone_update_renamed() */ +static void rna_PoseChannel_name_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + + /* redraw view */ + WM_main_add_notifier(NC_GEOM | ND_DATA, id); + + /* update animation channels */ + WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN, id); +} + static PointerRNA rna_PoseChannel_bone_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->owner_id; @@ -996,6 +1008,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Name", ""); RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable"); RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, 0, "rna_PoseChannel_name_update"); /* Baked Bone Path cache data */ rna_def_motionpath_common(srna); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index c7734e5ec2d..e65d3eb18b0 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3437,14 +3437,15 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_keyframe_insert_auto", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_mode", AUTOKEY_ON); RNA_def_property_ui_text( - prop, "Auto Keying", "Automatic keyframe insertion for Objects and Bones"); + prop, "Auto Keying", "Automatic keyframe insertion for Objects, Bones and Masks"); RNA_def_property_ui_icon(prop, ICON_REC, 0); prop = RNA_def_property(srna, "auto_keying_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "autokey_mode"); RNA_def_property_enum_items(prop, auto_key_items); - RNA_def_property_ui_text( - prop, "Auto-Keying Mode", "Mode of automatic keyframe insertion for Objects and Bones"); + RNA_def_property_ui_text(prop, + "Auto-Keying Mode", + "Mode of automatic keyframe insertion for Objects, Bones and Masks"); prop = RNA_def_property(srna, "use_record_with_nla", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", ANIMRECORD_FLAG_WITHNLA); @@ -4947,13 +4948,23 @@ static void rna_def_bake_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "max_ray_distance", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); + RNA_def_property_ui_text(prop, + "Max Ray Distance", + "The maximum ray distance for matching points between the active and " + "selected objects. If zero, there is no limit"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "cage_extrusion", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_range(prop, 0.0, FLT_MAX); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); RNA_def_property_ui_text( prop, "Cage Extrusion", - "Distance to use for the inward ray cast when using selected to active"); + "Inflate the active object by the specified distance for baking. This helps matching to " + "points nearer to the outside of the selected object meshes"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "normal_space", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index e770b669ca2..1d03b16d5bb 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -160,7 +160,7 @@ static void rna_Scene_ray_cast(Scene *scene, normalize_v3(direction); Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, 0); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, 0); bool ret = ED_transform_snap_object_project_ray_ex(sctx, depsgraph, diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index fd8ddfff14f..45d7bc24017 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -874,13 +874,6 @@ static void rna_Sequence_reopen_files_update(Main *bmain, Scene *UNUSED(scene), } } -static void rna_Sequence_mute_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -{ - Scene *scene = (Scene *)ptr->owner_id; - - DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); -} - static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; @@ -1690,7 +1683,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1); RNA_def_property_ui_text( prop, "Mute", "Disable strip so that it cannot be viewed in the output"); - RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_mute_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_LOCK); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 88c65604cec..a7c2feebc40 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -485,6 +485,13 @@ const EnumPropertyItem rna_enum_file_sort_items[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_enum_curve_display_handle_items[] = { + {CURVE_HANDLE_NONE, "NONE", 0, "None", ""}, + {CURVE_HANDLE_SELECTED, "SELECTED", 0, "Selected", ""}, + {CURVE_HANDLE_ALL, "ALL", 0, "All", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "DNA_anim_types.h" @@ -3831,9 +3838,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop, "Indices", "Display the index numbers of selected vertices, edges, and faces"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "show_curve_handles", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CU_HANDLES); - RNA_def_property_ui_text(prop, "Draw Handles", "Display Bezier handles in editmode"); + prop = RNA_def_property(srna, "display_handle", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "overlay.handle_display"); + RNA_def_property_enum_items(prop, rna_enum_curve_display_handle_items); + RNA_def_property_ui_text( + prop, "Display Handles", "Limit the display of curve handles in edit mode"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_curve_normals", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 46b8d8647de..9184c54ae88 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -1565,7 +1565,11 @@ static void rna_def_texture(BlenderRNA *brna) prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_COLORBAND); RNA_def_property_boolean_funcs(prop, NULL, "rna_Texture_use_color_ramp_set"); - RNA_def_property_ui_text(prop, "Use Color Ramp", "Toggle color ramp operations"); + RNA_def_property_ui_text(prop, + "Use Color Ramp", + "Map the texture intensity to the color ramp. " + "Note that the alpha value is used for image textures, " + "enable \"Calculate Alpha\" for images without an alpha channel"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index ca466ce2821..1449c410d18 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1285,6 +1285,18 @@ static void rna_def_panel(BlenderRNA *brna) "Hide Header", "If set to False, the panel shows a header, which contains a clickable " "arrow to collapse the panel and the label (see bl_label)"}, + {PNL_INSTANCED, + "INSTANCED", + 0, + "Instanced Panel", + "Multiple panels with this type can be used as part of a list depending on data external " + "to the UI. Used to create panels for the modifiers and other stacks."}, + {PNL_LAYOUT_HEADER_EXPAND, + "HEADER_LAYOUT_EXPAND", + 0, + "Expand Header Layout", + "Allow buttons in the header to stretch and shrink to fill the entire layout width"}, + {PNL_DRAW_BOX, "DRAW_BOX", 0, "Box Style", "Draw panel with the box widget theme"}, {0, NULL, 0, NULL, NULL}, }; @@ -1332,6 +1344,11 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "drawname"); RNA_def_property_ui_text(prop, "Text", "XXX todo"); + prop = RNA_def_int( + srna, "list_panel_index", 0, 0, INT_MAX, "Instanced Panel Data Index", "", 0, INT_MAX); + RNA_def_property_int_sdna(prop, NULL, "runtime.list_index"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->idname"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 00d3189dcbe..479d0a0d1a7 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -4716,7 +4716,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop = RNA_def_property(srna, "use_text_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA); - RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); + RNA_def_property_ui_text(prop, "Text Anti-Aliasing", "Draw user interface text anti-aliased"); RNA_def_property_update(prop, 0, "rna_userdef_text_update"); prop = RNA_def_property(srna, "text_hinting", PROP_ENUM, PROP_NONE); @@ -5798,8 +5798,9 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop = RNA_def_property(srna, "ndof_fly_helicopter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_FLY_HELICOPTER); - RNA_def_property_ui_text( - prop, "Helicopter Mode", "Device up/down directly controls your Z position"); + RNA_def_property_ui_text(prop, + "Helicopter Mode", + "Device up/down directly controls the Z position of the 3D viewport"); /* let Python know whether NDOF is enabled */ prop = RNA_def_boolean(srna, "use_ndof", true, "", ""); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index deeb4f5789c..6749aa9495a 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -450,7 +450,7 @@ static const EnumPropertyItem operator_flag_items[] = { "UNDO_GROUPED", 0, "Grouped Undo", - "Push a single undo event for repetead instances of this operator"}, + "Push a single undo event for repeated instances of this operator"}, {OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"}, {OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"}, {OPTYPE_GRAB_CURSOR_XY, diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index 826d4039c55..742d3da27ac 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -401,12 +401,14 @@ RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_offset_scale, flag, WM_GIZMO_DRAW_OF RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(flag_use_draw_scale, flag, WM_GIZMO_DRAW_OFFSET_SCALE); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_GIZMO_HIDDEN); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide_select, flag, WM_GIZMO_HIDDEN_SELECT); +RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide_keymap, flag, WM_GIZMO_HIDDEN_KEYMAP); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_grab_cursor, flag, WM_GIZMO_MOVE_CURSOR); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_select_background, flag, WM_GIZMO_SELECT_BACKGROUND); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_operator_tool_properties, flag, WM_GIZMO_OPERATOR_TOOL_INIT); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_event_handle_all, flag, WM_GIZMO_EVENT_HANDLE_ALL); +RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(flag_use_tooltip, flag, WM_GIZMO_NO_TOOLTIP); /* wmGizmo.state */ RNA_GIZMO_FLAG_RO_DEF(state_is_highlight, state, WM_GIZMO_STATE_HIGHLIGHT); @@ -1202,6 +1204,12 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) prop, "rna_Gizmo_flag_hide_select_get", "rna_Gizmo_flag_hide_select_set"); RNA_def_property_ui_text(prop, "Hide Select", ""); RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); + /* WM_GIZMO_HIDDEN_KEYMAP */ + prop = RNA_def_property(srna, "hide_keymap", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Gizmo_flag_hide_keymap_get", "rna_Gizmo_flag_hide_keymap_set"); + RNA_def_property_ui_text(prop, "Hide Keymap", "Ignore the key-map for this gizmo"); + RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_MOVE_CURSOR */ prop = RNA_def_property(srna, "use_grab_cursor", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( @@ -1271,6 +1279,13 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) "do not pass events through to be handled by other keymaps"); RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); + /* WM_GIZMO_NO_TOOLTIP (negated) */ + prop = RNA_def_property(srna, "use_tooltip", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Gizmo_flag_use_tooltip_get", "rna_Gizmo_flag_use_tooltip_set"); + RNA_def_property_ui_text(prop, "Use Tooltip", "Use tool-tips when hovering over this gizmo"); + /* No update needed. */ + /* wmGizmo.state (readonly) */ /* WM_GIZMO_STATE_HIGHLIGHT */ prop = RNA_def_property(srna, "is_highlight", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index 32e348ea72f..5f110189dd6 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -59,7 +59,7 @@ static void rna_window_update_all(Main *UNUSED(bmain), void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { WorkSpace *workspace = (WorkSpace *)ptr->owner_id; - rna_iterator_listbase_begin(iter, BKE_workspace_layouts_get(workspace), NULL); + rna_iterator_listbase_begin(iter, &workspace->layouts, NULL); } static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *iter) diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 29d456e5126..99ce447236b 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -162,6 +162,11 @@ static void deformVertsEM(ModifierData *md, ArmatureModifierData *amd = (ArmatureModifierData *)md; Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ armature_deform_verts(amd->object, diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 5f2043d8c09..ef8530557d7 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -502,10 +502,15 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } - if (mesh_src) { + if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { BLI_assert(mesh_src->totvert == numVerts); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + if (cmd->type == MOD_CAST_TYPE_CUBOID) { cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); } diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 6224cf6b1fc..3b2268ea14d 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -756,6 +756,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + correctivesmooth_modifier_do( md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData); diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index 238c8223799..eec87a918ec 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -142,6 +142,11 @@ static void deformVertsEM(ModifierData *md, { Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + deformVerts(md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 3958713f7a8..2bd33af7582 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -73,7 +73,7 @@ static DecimateModifierData *getOriginalModifierData(const DecimateModifierData const ModifierEvalContext *ctx) { Object *ob_orig = DEG_get_original_object(ctx->object); - return (DecimateModifierData *)BKE_modifiers_findny_name(ob_orig, dmd->modifier.name); + return (DecimateModifierData *)BKE_modifiers_findby_name(ob_orig, dmd->modifier.name); } static void updateFaceCount(const ModifierEvalContext *ctx, diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 514ea185ede..0cb882d0532 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -407,6 +407,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index 095ca95594b..0ca8bc55fb8 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -35,6 +35,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_particle.h" @@ -783,6 +784,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + LaplacianDeformModifier_do( (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index 2fefca68bad..643afc5b5fc 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -559,6 +559,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + laplaciansmoothModifier_do( (LaplacianSmoothModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts); diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index 8dd507d51a4..0a7aa006fcc 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -125,6 +125,11 @@ static void deformVertsEM(ModifierData *md, struct Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, em, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + deformVerts(md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index a458e4dd8bc..18b88864926 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -366,6 +366,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * copy_masked_polys_to_new_mesh( *mesh, *result, vertex_map, edge_map, masked_poly_indices, new_loop_starts); + BKE_mesh_calc_edges_loose(result); /* Tag to recalculate normals later. */ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index c5ed6363415..57b5f3891b2 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -479,6 +479,11 @@ static void deformVertsEM(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get( ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index fc5359c953f..e72a484e3a0 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -216,7 +216,7 @@ static void deformVerts(ModifierData *md, if (DEG_is_active(ctx->depsgraph)) { Object *object_orig = DEG_get_original_object(ctx->object); - ModifierData *md_orig = BKE_modifiers_findny_name(object_orig, psmd->modifier.name); + ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name); BLI_assert(md_orig != NULL); ParticleSystemModifierData *psmd_orig = (ParticleSystemModifierData *)md_orig; psmd_orig->flag = psmd->flag; diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index bb8519b01ea..11dc0a92769 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -142,6 +142,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + struct MDeformVert *dvert = NULL; int defgrp_index = -1; if (swmd->vgroup_name[0] != '\0') { diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 0bd16a318ae..a81b42905e3 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -440,6 +440,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index 5b13bee7dac..7ac6690e3a7 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -216,6 +216,9 @@ static void deformVertsEM(ModifierData *md, /* mesh_src is needed for vgroups, and taking edges into account. */ mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + /* TODO(campbell): use edit-mode data only (remove this line). */ + BKE_mesh_wrapper_ensure_mdata(mesh_src); + smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index bd453c24a31..4999c77c355 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -196,7 +196,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, } else if (ob->type == OB_MESH) { if (em) { - mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data); + mesh = BKE_mesh_wrapper_from_editmesh_with_coords(em, NULL, vertexCos, ob->data); } else { /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether @@ -209,9 +209,12 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, mesh->runtime.deformed_only = 1; } + if (em != NULL) { + /* pass */ + } /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether * we really need vertexCos here. */ - if (vertexCos) { + else if (vertexCos) { BKE_mesh_vert_coords_apply(mesh, vertexCos); mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; } @@ -241,7 +244,9 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, } } - BLI_assert(mesh == NULL || mesh->totvert == num_verts); + if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) { + BLI_assert(mesh->totvert == num_verts); + } return mesh; } diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 458e2d0caea..692f0ca18f0 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -381,6 +381,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index fc4b65a7e5c..90d9f451f75 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -353,6 +353,11 @@ static void deformVertsEM(ModifierData *md, mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); } + /* TODO(Campbell): use edit-mode data only (remove this line). */ + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts); if (!ELEM(mesh_src, NULL, mesh)) { diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index 5dae6bb8505..1a38787777f 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -272,16 +272,45 @@ void weightvg_update_vg(MDeformVert *dvert, const bool do_add, const float add_thresh, const bool do_rem, - const float rem_thresh) + const float rem_thresh, + const bool do_normalize) { int i; + float min_w = weights[0]; + float norm_fac = 1.0f; + if (do_normalize) { + float max_w = weights[0]; + for (i = 1; i < num; i++) { + const float w = weights[i]; + + /* No need to clamp here, normalization will ensure we stay within [0.0, 1.0] range. */ + if (w < min_w) { + min_w = w; + } + else if (w > max_w) { + max_w = w; + } + } + + const float range = max_w - min_w; + if (fabsf(range) > FLT_EPSILON) { + norm_fac = 1.0f / range; + } + else { + min_w = 0.0f; + } + } + for (i = 0; i < num; i++) { float w = weights[i]; MDeformVert *dv = &dvert[indices ? indices[i] : i]; MDeformWeight *dw = dws ? dws[i] : ((defgrp_idx >= 0) ? BKE_defvert_find_index(dv, defgrp_idx) : NULL); + if (do_normalize) { + w = (w - min_w) * norm_fac; + } /* Never allow weights out of [0.0, 1.0] range. */ CLAMP(w, 0.0f, 1.0f); diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h index 09a6a1afb3e..50597d43112 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.h +++ b/source/blender/modifiers/intern/MOD_weightvg_util.h @@ -86,6 +86,7 @@ void weightvg_update_vg(struct MDeformVert *dvert, const bool do_add, const float add_thresh, const bool do_rem, - const float rem_thresh); + const float rem_thresh, + const bool do_normalize); #endif /* __MOD_WEIGHTVG_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 1ff8dfbdcca..8ce1aaee942 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -239,6 +239,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Do mapping. */ const bool do_invert_mapping = (wmd->edit_flags & MOD_WVG_INVERT_FALLOFF) != 0; + const bool do_normalize = (wmd->edit_flags & MOD_WVG_EDIT_WEIGHTS_NORMALIZE) != 0; if (do_invert_mapping || wmd->falloff_type != MOD_WVG_MAPPING_NONE) { RNG *rng = NULL; @@ -283,7 +284,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * do_add, wmd->add_threshold, do_rem, - wmd->rem_threshold); + wmd->rem_threshold, + do_normalize); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index f1db8502d74..a71b1d9d0e8 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -224,6 +224,17 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * int numIdx = 0; int i; const bool invert_vgroup_mask = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_MASK) != 0; + const bool do_normalize = (wmd->flag & MOD_WVG_MIX_WEIGHTS_NORMALIZE) != 0; + + /* + * Note that we only invert the weight values within provided vgroups, the selection based on + * which vertice is affected because it belongs or not to a group remains unchanged. + * In other words, vertices not belonging to a group won't be affected, even though their + * inverted 'virtual' weight would be 1.0f. + */ + const bool invert_vgroup_a = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_A) != 0; + const bool invert_vgroup_b = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_B) != 0; + /* Flags. */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; @@ -378,8 +389,18 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Mix weights. */ for (i = 0; i < numIdx; i++) { float weight2; - org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; - weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; + if (invert_vgroup_a) { + org_w[i] = 1.0f - (dw1[i] ? dw1[i]->weight : wmd->default_weight_a); + } + else { + org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a; + } + if (invert_vgroup_b) { + weight2 = 1.0f - (dw2[i] ? dw2[i]->weight : wmd->default_weight_b); + } + else { + weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b; + } new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode); } @@ -408,7 +429,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup. */ weightvg_update_vg( - dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f); + dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f, do_normalize); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 3e746403050..e3f833ff81e 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -429,6 +429,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * int i; const bool invert_vgroup_mask = (wmd->proximity_flags & MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK) != 0; + const bool do_normalize = (wmd->proximity_flags & MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE) != 0; /* Flags. */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; @@ -604,7 +605,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * invert_vgroup_mask); /* Update vgroup. Note we never add nor remove vertices from vgroup here. */ - weightvg_update_vg(dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f); + weightvg_update_vg( + dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f, do_normalize); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 382459993b7..53ea02ff8a7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -311,8 +311,7 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree, if ((scene->r.mode & R_EDGE_FRS) && (view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS)) { - ntreeCompositRegisterPass( - scene->nodetree, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA); + ntreeCompositRegisterPass(ntree, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA); } MEM_freeN(data); diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 280f09d67c9..311cf2b8c73 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -40,6 +40,7 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "GPU_context.h" #include "GPU_framebuffer.h" #include "GPU_texture.h" @@ -84,7 +85,7 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args { BPYGPU_IS_INIT_OR_ERROR_OBJ; - GPUOffScreen *ofs; + GPUOffScreen *ofs = NULL; int width, height, samples = 0; char err_out[256]; @@ -94,7 +95,12 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args return NULL; } - ofs = GPU_offscreen_create(width, height, samples, true, false, err_out); + if (GPU_context_active_get()) { + ofs = GPU_offscreen_create(width, height, samples, true, false, err_out); + } + else { + strncpy(err_out, "No active GPU context found", 256); + } if (ofs == NULL) { PyErr_Format(PyExc_RuntimeError, diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 9d0ee0bb500..de8fd87db58 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -380,10 +380,7 @@ void BPy_init_modules(void) PyModule_AddObject(mod, "types", BPY_rna_types()); /* needs to be first so bpy_types can run */ - BPY_library_load_module(mod); - BPY_library_write_module(mod); - - BPY_rna_id_collection_module(mod); + BPY_library_load_type_ready(); BPY_rna_gizmo_module(mod); diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index a9bdef1c3e4..957d49eb04e 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -82,10 +82,10 @@ extern char build_system[]; static PyTypeObject BlenderAppType; static PyStructSequence_Field app_info_fields[] = { - {"version", "The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"}, + {"version", "The Blender version as a tuple of 3 numbers. eg. (2, 83, 1)"}, {"version_string", "The Blender version formatted as a string"}, - {"version_char", "The Blender version character (for minor releases)"}, {"version_cycle", "The release status of this build alpha/beta/rc/release"}, + {"version_char", "Deprecated, always an empty string"}, {"binary_path", "The location of Blender's executable, useful for utilities that open new instances"}, {"background", @@ -160,12 +160,12 @@ static PyObject *make_app_info(void) #define SetBytesItem(str) PyStructSequence_SET_ITEM(app_info, pos++, PyBytes_FromString(str)) #define SetObjItem(obj) PyStructSequence_SET_ITEM(app_info, pos++, obj) - SetObjItem(PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); - SetObjItem(PyUnicode_FromFormat( - "%d.%02d (sub %d)", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + SetObjItem( + PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_VERSION_PATCH)); + SetStrItem(BKE_blender_version_string()); - SetStrItem(STRINGIFY(BLENDER_VERSION_CHAR)); SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE)); + SetStrItem(""); SetStrItem(BKE_appdir_program_path()); SetObjItem(PyBool_FromLong(G.background)); SetObjItem(PyBool_FromLong(G.factory_startup)); diff --git a/source/blender/python/intern/bpy_library.h b/source/blender/python/intern/bpy_library.h index 3fd116d7028..6840807d2b0 100644 --- a/source/blender/python/intern/bpy_library.h +++ b/source/blender/python/intern/bpy_library.h @@ -21,7 +21,9 @@ #ifndef __BPY_LIBRARY_H__ #define __BPY_LIBRARY_H__ -int BPY_library_load_module(PyObject *mod_par); -int BPY_library_write_module(PyObject *mod_par); +int BPY_library_load_type_ready(void); +extern PyMethodDef BPY_library_load_method_def; + +extern PyMethodDef BPY_library_write_method_def; #endif /* __BPY_LIBRARY_H__ */ diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 989b7931444..05cbc9af601 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -459,15 +459,15 @@ static PyObject *bpy_lib_dir(BPy_Library *self) return PyDict_Keys(self->dict); } -int BPY_library_load_module(PyObject *mod_par) +PyMethodDef BPY_library_load_method_def = { + "load", + (PyCFunction)bpy_lib_load, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_lib_load_doc, +}; + +int BPY_library_load_type_ready(void) { - static PyMethodDef load_meth = { - "load", - (PyCFunction)bpy_lib_load, - METH_STATIC | METH_VARARGS | METH_KEYWORDS, - bpy_lib_load_doc, - }; - PyModule_AddObject(mod_par, "_library_load", PyCFunction_New(&load_meth, NULL)); /* some compilers don't like accessing this directly, delay assignment */ bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr; diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index 6c8f1deb126..fec0cef7b05 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -204,16 +204,9 @@ finally: return ret; } -int BPY_library_write_module(PyObject *mod_par) -{ - static PyMethodDef write_meth = { - "write", - (PyCFunction)bpy_lib_write, - METH_STATIC | METH_VARARGS | METH_KEYWORDS, - bpy_lib_write_doc, - }; - - PyModule_AddObject(mod_par, "_library_write", PyCFunction_New(&write_meth, NULL)); - - return 0; -} +PyMethodDef BPY_library_write_method_def = { + "write", + (PyCFunction)bpy_lib_write, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_lib_write_doc, +}; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 39485f322d4..179daad2f60 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -9040,32 +9040,41 @@ void pyrna_struct_type_extend_capi(struct StructRNA *srna, struct PyMethodDef *method, struct PyGetSetDef *getset) { - PyObject *cls = pyrna_srna_Subtype(srna); + /* See 'add_methods' in Python's 'typeobject.c'. */ + PyTypeObject *type = (PyTypeObject *)pyrna_srna_Subtype(srna); + PyObject *dict = type->tp_dict; if (method != NULL) { for (; method->ml_name != NULL; method++) { - PyObject *func = PyCFunction_New(method, NULL); - PyObject *args = PyTuple_New(1); - PyTuple_SET_ITEM(args, 0, func); - PyObject *classmethod = PyObject_CallObject((PyObject *)&PyClassMethod_Type, args); + PyObject *py_method; - PyObject_SetAttrString(cls, method->ml_name, classmethod); + if (method->ml_flags & METH_CLASS) { + PyObject *cfunc = PyCFunction_New(method, (PyObject *)type); + py_method = PyClassMethod_New(cfunc); + Py_DECREF(cfunc); + } + else { + /* Currently only static and class methods are used. */ + BLI_assert(method->ml_flags & METH_STATIC); + py_method = PyCFunction_New(method, NULL); + } - Py_DECREF(classmethod); - Py_DECREF(args); /* Clears 'func' too. */ + int err = PyDict_SetItemString(dict, method->ml_name, py_method); + Py_DECREF(py_method); + BLI_assert(!(err < 0)); + UNUSED_VARS_NDEBUG(err); } } if (getset != NULL) { - PyObject *dict = ((PyTypeObject *)cls)->tp_dict; for (; getset->name != NULL; getset++) { - PyObject *descr = PyDescr_NewGetSet((PyTypeObject *)cls, getset); + PyObject *descr = PyDescr_NewGetSet(type, getset); /* Ensure we're not overwriting anything that already exists. */ BLI_assert(PyDict_GetItem(dict, PyDescr_NAME(descr)) == NULL); PyDict_SetItem(dict, PyDescr_NAME(descr), descr); Py_DECREF(descr); } } - Py_DECREF(cls); + Py_DECREF(type); } /* Access to 'owner_id' internal global. */ diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 6b6ffa97995..b607f1635e6 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -385,32 +385,21 @@ static PyObject *bpy_orphans_purge(PyObject *UNUSED(self), return Py_None; } -int BPY_rna_id_collection_module(PyObject *mod_par) -{ - static PyMethodDef user_map = { - "user_map", (PyCFunction)bpy_user_map, METH_VARARGS | METH_KEYWORDS, bpy_user_map_doc}; - - PyModule_AddObject(mod_par, "_rna_id_collection_user_map", PyCFunction_New(&user_map, NULL)); - - static PyMethodDef batch_remove = { - "batch_remove", - (PyCFunction)bpy_batch_remove, - METH_VARARGS | METH_KEYWORDS, - bpy_batch_remove_doc, - }; - - PyModule_AddObject( - mod_par, "_rna_id_collection_batch_remove", PyCFunction_New(&batch_remove, NULL)); - - static PyMethodDef orphans_purge = { - "orphans_purge", - (PyCFunction)bpy_orphans_purge, - METH_VARARGS | METH_KEYWORDS, - bpy_orphans_purge_doc, - }; - - PyModule_AddObject( - mod_par, "_rna_id_collection_orphans_purge", PyCFunction_New(&orphans_purge, NULL)); - - return 0; -} +PyMethodDef BPY_rna_id_collection_user_map_method_def = { + "user_map", + (PyCFunction)bpy_user_map, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_user_map_doc, +}; +PyMethodDef BPY_rna_id_collection_batch_remove_method_def = { + "batch_remove", + (PyCFunction)bpy_batch_remove, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_batch_remove_doc, +}; +PyMethodDef BPY_rna_id_collection_orphans_purge_method_def = { + "orphans_purge", + (PyCFunction)bpy_orphans_purge, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_orphans_purge_doc, +}; diff --git a/source/blender/python/intern/bpy_rna_id_collection.h b/source/blender/python/intern/bpy_rna_id_collection.h index 8cb375960a9..ee8f4c666a8 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.h +++ b/source/blender/python/intern/bpy_rna_id_collection.h @@ -21,6 +21,8 @@ #ifndef __BPY_RNA_ID_COLLECTION_H__ #define __BPY_RNA_ID_COLLECTION_H__ -int BPY_rna_id_collection_module(PyObject *); +extern PyMethodDef BPY_rna_id_collection_user_map_method_def; +extern PyMethodDef BPY_rna_id_collection_batch_remove_method_def; +extern PyMethodDef BPY_rna_id_collection_orphans_purge_method_def; #endif /* __BPY_RNA_ID_COLLECTION_H__ */ diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c index cfd6b7f54a8..5a2ba4a5cdb 100644 --- a/source/blender/python/intern/bpy_rna_types_capi.c +++ b/source/blender/python/intern/bpy_rna_types_capi.c @@ -33,8 +33,10 @@ #include "BLI_utildefines.h" +#include "bpy_library.h" #include "bpy_rna.h" #include "bpy_rna_callback.h" +#include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" #include "../generic/py_capi_utils.h" @@ -46,6 +48,31 @@ #include "WM_api.h" /* -------------------------------------------------------------------- */ +/** \name Blend Data + * \{ */ + +static struct PyMethodDef pyrna_blenddata_methods[] = { + {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */ + {NULL, NULL, 0, NULL}, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend Data Libraries + * \{ */ + +static struct PyMethodDef pyrna_blenddatalibraries_methods[] = { + {NULL, NULL, 0, NULL}, /* #BPY_library_load_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_library_write_method_def */ + {NULL, NULL, 0, NULL}, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Window Manager Clipboard Property * * Avoid using the RNA API because this value may change between checking it's length @@ -86,11 +113,11 @@ static int pyrna_WindowManager_clipboard_set(PyObject *UNUSED(self), static struct PyMethodDef pyrna_windowmanager_methods[] = { {"draw_cursor_add", (PyCFunction)pyrna_callback_classmethod_add, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, ""}, {"draw_cursor_remove", (PyCFunction)pyrna_callback_classmethod_remove, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, ""}, {NULL, NULL, 0, NULL}, }; @@ -147,11 +174,11 @@ PyDoc_STRVAR(pyrna_draw_handler_remove_doc, static struct PyMethodDef pyrna_space_methods[] = { {"draw_handler_add", (PyCFunction)pyrna_callback_classmethod_add, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, pyrna_draw_handler_add_doc}, {"draw_handler_remove", (PyCFunction)pyrna_callback_classmethod_remove, - METH_VARARGS | METH_STATIC, + METH_VARARGS | METH_CLASS, pyrna_draw_handler_remove_doc}, {NULL, NULL, 0, NULL}, }; @@ -164,7 +191,24 @@ static struct PyMethodDef pyrna_space_methods[] = { void BPY_rna_types_extend_capi(void) { + /* BlendData */ + ARRAY_SET_ITEMS(pyrna_blenddata_methods, + BPY_rna_id_collection_user_map_method_def, + BPY_rna_id_collection_batch_remove_method_def, + BPY_rna_id_collection_orphans_purge_method_def); + BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4); + pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL); + + /* BlendDataLibraries */ + ARRAY_SET_ITEMS( + pyrna_blenddatalibraries_methods, BPY_library_load_method_def, BPY_library_write_method_def); + BLI_assert(ARRAY_SIZE(pyrna_blenddatalibraries_methods) == 3); + pyrna_struct_type_extend_capi(&RNA_BlendDataLibraries, pyrna_blenddatalibraries_methods, NULL); + + /* Space */ pyrna_struct_type_extend_capi(&RNA_Space, pyrna_space_methods, NULL); + + /* WindowManager */ pyrna_struct_type_extend_capi( &RNA_WindowManager, pyrna_windowmanager_methods, pyrna_windowmanager_getset); } diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index a1dd9b3d5b0..f49c68a258d 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -108,4 +108,6 @@ if(APPLE) endif() endif() +add_definitions(${GL_DEFINITIONS}) + blender_add_lib_nolist(bf_render "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h index 59e34404074..3bab9179f84 100644 --- a/source/blender/render/extern/include/RE_bake.h +++ b/source/blender/render/extern/include/RE_bake.h @@ -84,6 +84,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, + const float max_ray_distance, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage); diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 82b45ba9d4a..77a60854616 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -68,7 +68,6 @@ struct bNodeTree; #define RE_ENGINE_DO_UPDATE 8 #define RE_ENGINE_RENDERING 16 #define RE_ENGINE_HIGHLIGHT_TILES 32 -#define RE_ENGINE_USED_FOR_VIEWPORT 64 extern ListBase R_engines; @@ -159,7 +158,6 @@ typedef struct RenderEngine { } RenderEngine; RenderEngine *RE_engine_create(RenderEngineType *type); -RenderEngine *RE_engine_create_ex(RenderEngineType *type, bool use_for_viewport); void RE_engine_free(RenderEngine *engine); void RE_layer_load_from_file( diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index b963021dfd9..f9d2e915fad 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -160,8 +160,7 @@ typedef struct RenderResult { typedef struct RenderStats { int cfra; - int totface, totvert, totstrand, tothalo, totlamp, totpart; - short curfield, curblur, curpart, partsdone, convertdone, curfsa; + int totface, totvert, totlamp, totpart; bool localview; double starttime, lastframetime; const char *infostr, *statstr; diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c index e823a481d59..06f77854595 100644 --- a/source/blender/render/intern/source/bake_api.c +++ b/source/blender/render/intern/source/bake_api.c @@ -321,11 +321,16 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData, const float co[3], const float dir[3], const int pixel_id, - const int tot_highpoly) + const int tot_highpoly, + const float max_ray_distance) { int i; int hit_mesh = -1; - float hit_distance = FLT_MAX; + float hit_distance = max_ray_distance; + if (hit_distance == 0.0f) { + /* No ray distance set, use maximum. */ + hit_distance = FLT_MAX; + } BVHTreeRayHit *hits; hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays"); @@ -520,6 +525,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, + const float max_ray_distance, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage) @@ -623,7 +629,8 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low, co, dir, i, - tot_highpoly)) { + tot_highpoly, + max_ray_distance)) { /* if it fails mask out the original pixel array */ pixel_array_from[i].primitive_id = -1; } diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 4d88bb82dd9..af3a6fdd384 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -132,20 +132,9 @@ bool RE_engine_is_opengl(RenderEngineType *render_type) RenderEngine *RE_engine_create(RenderEngineType *type) { - return RE_engine_create_ex(type, false); -} - -RenderEngine *RE_engine_create_ex(RenderEngineType *type, bool use_for_viewport) -{ RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine"); engine->type = type; - if (use_for_viewport) { - engine->flag |= RE_ENGINE_USED_FOR_VIEWPORT; - - BLI_threaded_malloc_begin(); - } - BLI_mutex_init(&engine->update_render_passes_mutex); return engine; @@ -159,10 +148,6 @@ void RE_engine_free(RenderEngine *engine) } #endif - if (engine->flag & RE_ENGINE_USED_FOR_VIEWPORT) { - BLI_threaded_malloc_end(); - } - BLI_mutex_end(&engine->update_render_passes_mutex); MEM_freeN(engine); @@ -689,7 +674,7 @@ bool RE_bake_engine(Render *re, /* set render info */ re->i.cfra = re->scene->r.cfra; BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name) - 2); - re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0; + re->i.totface = re->i.totvert = re->i.totlamp = 0; /* render */ engine = re->engine; @@ -827,7 +812,7 @@ int RE_engine_render(Render *re, int do_all) /* set render info */ re->i.cfra = re->scene->r.cfra; BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name)); - re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0; + re->i.totface = re->i.totvert = re->i.totlamp = 0; /* render */ engine = re->engine; diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 138d95af055..2e9f30397db 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -270,8 +270,6 @@ void RE_parts_init(Render *re) /* this is render info for caller, is not reset when parts are freed! */ re->i.totpart = 0; - re->i.curpart = 0; - re->i.partsdone = 0; /* just for readable code.. */ xminb = re->disprect.xmin; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index d68f74751ec..c66c43ec467 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -187,32 +187,22 @@ static int default_break(void *UNUSED(arg)) static void stats_background(void *UNUSED(arg), RenderStats *rs) { - uintptr_t mem_in_use, mmap_in_use, peak_memory; - float megs_used_memory, mmap_used_memory, megs_peak_memory; + uintptr_t mem_in_use, peak_memory; + float megs_used_memory, megs_peak_memory; char info_time_str[32]; mem_in_use = MEM_get_memory_in_use(); - mmap_in_use = MEM_get_mapped_memory_in_use(); peak_memory = MEM_get_peak_memory(); - megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0); - mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0); + megs_used_memory = (mem_in_use) / (1024.0 * 1024.0); megs_peak_memory = (peak_memory) / (1024.0 * 1024.0); fprintf(stdout, - TIP_("Fra:%d Mem:%.2fM (%.2fM, Peak %.2fM) "), + TIP_("Fra:%d Mem:%.2fM (Peak %.2fM) "), rs->cfra, megs_used_memory, - mmap_used_memory, megs_peak_memory); - if (rs->curfield) { - fprintf(stdout, TIP_("Field %d "), rs->curfield); - } - if (rs->curblur) { - fprintf(stdout, TIP_("Blur %d "), rs->curblur); - } - BLI_timecode_string_from_time_simple( info_time_str, sizeof(info_time_str), PIL_check_seconds_timer() - rs->starttime); fprintf(stdout, TIP_("| Time:%s | "), info_time_str); @@ -221,23 +211,12 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) fprintf(stdout, "%s", rs->infostr); } else { - if (rs->tothalo) { - fprintf(stdout, - TIP_("Sce: %s Ve:%d Fa:%d Ha:%d La:%d"), - rs->scene_name, - rs->totvert, - rs->totface, - rs->tothalo, - rs->totlamp); - } - else { - fprintf(stdout, - TIP_("Sce: %s Ve:%d Fa:%d La:%d"), - rs->scene_name, - rs->totvert, - rs->totface, - rs->totlamp); - } + fprintf(stdout, + TIP_("Sce: %s Ve:%d Fa:%d La:%d"), + rs->scene_name, + rs->totvert, + rs->totface, + rs->totlamp); } /* Flush stdout to be sure python callbacks are printing stuff after blender. */ diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index d829033656a..4b74bfb3e5c 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -255,7 +255,7 @@ RenderPass *render_layer_add_pass(RenderResult *rr, float *rect; int x; - rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, name); + rpass->rect = MEM_callocN(sizeof(float) * rectsize, name); if (rpass->rect == NULL) { MEM_freeN(rpass); return NULL; diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 22fd55cd49a..7c749c60168 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -168,10 +168,6 @@ if(WITH_BUILDINFO) add_definitions(-DWITH_BUILDINFO) endif() -if(WITH_OPENSUBDIV) - add_definitions(-DWITH_OPENSUBDIV) -endif() - if(WITH_INPUT_NDOF) add_definitions(-DWITH_INPUT_NDOF) endif() diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index ae2810dfb4d..53a3fd5ebda 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -82,7 +82,7 @@ wmKeyMap *WM_keymap_find_all_spaceid_or_empty(struct wmWindowManager *wm, const char *idname, int spaceid, int regionid); -wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap); +wmKeyMap *WM_keymap_active(const struct wmWindowManager *wm, struct wmKeyMap *keymap); bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap); bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap); diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index 955fb959e92..346ed131c59 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -67,28 +67,33 @@ typedef enum eWM_GizmoFlag { WM_GIZMO_DRAW_VALUE = (1 << 2), WM_GIZMO_HIDDEN = (1 << 3), WM_GIZMO_HIDDEN_SELECT = (1 << 4), + /** Ignore the key-map for this gizmo. */ + WM_GIZMO_HIDDEN_KEYMAP = (1 << 5), /** * When set 'scale_final' value also scales the offset. * Use when offset is to avoid screen-space overlap instead of absolute positioning. */ - WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 5), + WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 6), /** * User should still use 'scale_final' for any handles and UI elements. * This simply skips scale when calculating the final matrix. * Needed when the gizmo needs to align with the interface underneath it. */ - WM_GIZMO_DRAW_NO_SCALE = (1 << 6), + WM_GIZMO_DRAW_NO_SCALE = (1 << 7), /** * Hide the cursor and lock it's position while interacting with this gizmo. */ - WM_GIZMO_MOVE_CURSOR = (1 << 7), + WM_GIZMO_MOVE_CURSOR = (1 << 8), /** Don't write into the depth buffer when selecting. */ - WM_GIZMO_SELECT_BACKGROUND = (1 << 8), + WM_GIZMO_SELECT_BACKGROUND = (1 << 9), /** Use the active tools operator properties when running as an operator. */ - WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 9), + WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 10), /** Don't pass through events to other handlers * (allows click/drag not to have it's events stolen by press events in other keymaps). */ - WM_GIZMO_EVENT_HANDLE_ALL = (1 << 10), + WM_GIZMO_EVENT_HANDLE_ALL = (1 << 11), + + /** Don't use tool-tips for this gizmo (can be distracting). */ + WM_GIZMO_NO_TOOLTIP = (1 << 12), } eWM_GizmoFlag; /** diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 54e6735175d..0032a341610 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -44,8 +44,10 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BKE_screen.h" #include "BKE_workspace.h" #include "WM_api.h" @@ -73,6 +75,28 @@ static void window_manager_free_data(ID *id) wm_close_and_free(NULL, (wmWindowManager *)id); } +static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data) +{ + wmWindowManager *wm = (wmWindowManager *)id; + + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + BKE_LIB_FOREACHID_PROCESS(data, win->scene, IDWALK_CB_USER_ONE); + + /* This pointer can be NULL during old files reading, better be safe than sorry. */ + if (win->workspace_hook != NULL) { + ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); + BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP); + /* allow callback to set a different workspace */ + BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); + } + if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { + LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { + BKE_screen_foreach_id_screen_area(data, area); + } + } + } +} + IDTypeInfo IDType_ID_WM = { .id_code = ID_WM, .id_filter = 0, @@ -87,6 +111,7 @@ IDTypeInfo IDType_ID_WM = { .copy_data = NULL, .free_data = window_manager_free_data, .make_local = NULL, + .foreach_id = window_manager_foreach_id, }; #define MAX_OP_REGISTERED 32 @@ -359,11 +384,11 @@ void wm_add_default(Main *bmain, bContext *C) WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace); CTX_wm_manager_set(C, wm); - win = wm_window_new(bmain, wm, NULL); + win = wm_window_new(bmain, wm, NULL, false); win->scene = CTX_data_scene(C); STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name); BKE_workspace_active_set(win->workspace_hook, workspace); - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); screen->winid = win->winid; wm->winactive = win; diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 58ca3bf1b95..07d7ccf31db 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -145,6 +145,16 @@ void WM_cursor_set(wmWindow *win, int curs) return; /* Can't set custom cursor before Window init */ } + if (curs == WM_CURSOR_DEFAULT && win->modalcursor) { + curs = win->modalcursor; + } + + if (win->cursor == curs) { + return; /* Cursor is already set */ + } + + win->cursor = curs; + if (curs == WM_CURSOR_NONE) { GHOST_SetCursorVisibility(win->ghostwin, 0); return; @@ -152,12 +162,6 @@ void WM_cursor_set(wmWindow *win, int curs) GHOST_SetCursorVisibility(win->ghostwin, 1); - if (curs == WM_CURSOR_DEFAULT && win->modalcursor) { - curs = win->modalcursor; - } - - win->cursor = curs; - if (curs < 0 || curs >= WM_CURSOR_NUM) { BLI_assert(!"Invalid cursor number"); return; diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index a01ab1377c1..4cc9f4ee7d1 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -848,6 +848,7 @@ static void wm_draw_window(bContext *C, wmWindow *win) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture)); + wmWindowViewport(win); if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) { wm_stereo3d_draw_sidebyside(win, view); } @@ -982,10 +983,6 @@ void wm_draw_update(bContext *C) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; -#ifdef WITH_OPENSUBDIV - BKE_subsurf_free_unused_buffers(); -#endif - GPU_free_unused_buffers(bmain); for (win = wm->windows.first; win; win = win->next) { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 61c99d72695..e5f288b1963 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -602,6 +602,12 @@ static int wm_handler_ui_call(bContext *C, } } + /* Don't block file-select events. Those are triggered by a separate file browser window. + * See T75292. */ + if (event->type == EVT_FILESELECT) { + return WM_UI_HANDLER_CONTINUE; + } + /* we set context to where ui handler came from */ if (handler->context.area) { CTX_wm_area_set(C, handler->context.area); @@ -640,11 +646,11 @@ static int wm_handler_ui_call(bContext *C, return WM_HANDLER_CONTINUE; } -static void wm_handler_ui_cancel(bContext *C) +void wm_event_handler_ui_cancel_ex(bContext *C, + wmWindow *win, + ARegion *region, + bool reactivate_button) { - wmWindow *win = CTX_wm_window(C); - ARegion *region = CTX_wm_region(C); - if (!region) { return; } @@ -656,11 +662,19 @@ static void wm_handler_ui_cancel(bContext *C) wmEvent event; wm_event_init_from_window(win, &event); event.type = EVT_BUT_CANCEL; + event.val = reactivate_button ? 0 : 1; handler->handle_fn(C, &event, handler->user_data); } } } +static void wm_event_handler_ui_cancel(bContext *C) +{ + wmWindow *win = CTX_wm_window(C); + ARegion *region = CTX_wm_region(C); + wm_event_handler_ui_cancel_ex(C, win, region, true); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1365,7 +1379,7 @@ static int wm_operator_invoke(bContext *C, * while dragging the view or worse, that stay there permanently * after the modal operator has swallowed all events and passed * none to the UI handler */ - wm_handler_ui_cancel(C); + wm_event_handler_ui_cancel(C); } else { WM_operator_free(op); @@ -2576,7 +2590,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { if (gz != NULL) { - if (U.flag & USER_TOOLTIPS) { + if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) { WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); } } @@ -2588,7 +2602,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (handle_keymap) { /* Handle highlight gizmo. */ - if (gz != NULL) { + if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) { bool keymap_poll = false; wmGizmoGroup *gzgroup = gz->parent_gzgroup; wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap); @@ -2661,6 +2675,12 @@ static int wm_handlers_do_gizmo_handler(bContext *C, return action; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Handle Single Event (All Handler Types) + * \{ */ + static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers) { const bool do_debug_handler = @@ -2962,6 +2982,14 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) return action; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Queue Utilities + * + * Utilities used by #wm_event_do_handlers. + * \{ */ + static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect) { if (wm_event_always_pass(event)) { @@ -3126,6 +3154,14 @@ static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Main Event Queue (Every Window) + * + * Handle events for all windows, run from the #WM_main event loop. + * \{ */ + /* called in main loop */ /* goes over entire hierarchy: events -> window -> screen -> area -> region */ void wm_event_do_handlers(bContext *C) @@ -3434,19 +3470,13 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); const bool is_temp_screen = WM_window_is_temp_screen(win); - const bool opens_window = (U.filebrowser_display_type == USER_TEMP_SPACE_DISPLAY_WINDOW); - /* Don't add the file handler to the temporary window if one is opened, or else it owns the - * handlers for itself, causing dangling pointers once it's destructed through a handler. It has - * a parent which should hold the handlers itself. */ - ListBase *modalhandlers = (is_temp_screen && opens_window) ? &win->parent->modalhandlers : - &win->modalhandlers; /* Close any popups, like when opening a file browser from the splash. */ - UI_popup_handlers_remove_all(C, modalhandlers); + UI_popup_handlers_remove_all(C, &win->modalhandlers); if (!is_temp_screen) { /* only allow 1 file selector open per window */ - LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, modalhandlers) { + LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) { if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; if (handler->is_fileselect == false) { @@ -3487,7 +3517,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) handler->context.area = CTX_wm_area(C); handler->context.region = CTX_wm_region(C); - BLI_addhead(modalhandlers, handler); + BLI_addhead(&win->modalhandlers, handler); /* check props once before invoking if check is available * ensures initial properties are valid */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index b9f0e3686db..cc81e4f2715 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1212,6 +1212,7 @@ static ImBuf *blend_file_thumb(const bContext *C, ImBuf *ibuf; BlendThumbnail *thumb; wmWindowManager *wm = CTX_wm_manager(C); + const float pixelsize_old = U.pixelsize; wmWindow *windrawable_old = wm->windrawable; char err_out[256] = "unknown"; @@ -1246,6 +1247,10 @@ static ImBuf *blend_file_thumb(const bContext *C, /* gets scaled to BLEN_THUMB_SIZE */ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + /* Note that with scaling, this ends up being 0.5, + * as it's a thumbnail, we don't need object centers and friends to be 1:1 size. */ + U.pixelsize = 1.0f; + if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene, @@ -1276,6 +1281,8 @@ static ImBuf *blend_file_thumb(const bContext *C, err_out); } + U.pixelsize = pixelsize_old; + /* Reset to old drawable. */ if (windrawable_old) { wm_window_make_drawable(wm, windrawable_old); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index a93d4c7bf37..fc3f0c87b69 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -125,6 +125,8 @@ #include "GPU_material.h" #include "BKE_sound.h" +#include "BKE_subdiv.h" + #include "COM_compositor.h" #include "DEG_depsgraph.h" @@ -132,10 +134,6 @@ #include "DRW_engine.h" -#ifdef WITH_OPENSUBDIV -# include "BKE_subsurf.h" -#endif - CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator"); CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_HANDLERS, "wm.handler"); CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_EVENTS, "wm.event"); @@ -193,9 +191,8 @@ void WM_init_opengl(Main *bmain) GPU_pass_cache_init(); -#ifdef WITH_OPENSUBDIV - BKE_subsurf_osd_init(); -#endif + BKE_subdiv_init(); + opengl_is_init = true; } @@ -576,11 +573,9 @@ void WM_exit_ex(bContext *C, const bool do_python) COM_deinitialize(); #endif - if (opengl_is_init) { -#ifdef WITH_OPENSUBDIV - BKE_subsurf_osd_cleanup(); -#endif + BKE_subdiv_exit(); + if (opengl_is_init) { GPU_free_unused_buffers(G_MAIN); } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 5f2b492088e..d7102a1e8af 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1936,7 +1936,7 @@ void WM_keyconfig_update(wmWindowManager *wm) * During event handling this function is called to get the keymap from the final configuration. * \{ */ -wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap) +wmKeyMap *WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap) { wmKeyMap *km; diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 8445fac0498..b75609fd28f 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -96,39 +96,7 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, UI_block_emboss_set(block, UI_EMBOSS); } -static void get_version_string(char *ver, const int max_length) -{ - /* Version number. */ - const char *version_cycle = NULL; - - if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) { - version_cycle = " Alpha"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) { - version_cycle = " Beta"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) { - version_cycle = " Release Candidate"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { - version_cycle = STRINGIFY(BLENDER_VERSION_CHAR); - } - - const char *version_cycle_number = ""; - if (strlen(STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER))) { - version_cycle_number = " " STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER); - } - - BLI_snprintf(ver, - max_length, - "%d.%d.%d%s%s", - BLENDER_VERSION / 100, - BLENDER_VERSION % 100, - BLENDER_SUBVERSION, - version_cycle, - version_cycle_number); -} - +#ifndef WITH_HEADLESS static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) { uchar *rct = (uchar *)ibuf->rect; @@ -179,6 +147,7 @@ static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) } } } +#endif /* WITH_HEADLESS */ static ImBuf *wm_block_splash_image(int width, int *r_height) { @@ -219,6 +188,7 @@ static ImBuf *wm_block_splash_image(int width, int *r_height) return ibuf; #else + UNUSED_VARS(width, r_height); return NULL; #endif } @@ -249,9 +219,8 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE UI_but_func_set(but, wm_block_close, block, NULL); UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); - char version_buf[256] = "\0"; - get_version_string(version_buf, sizeof(version_buf)); - wm_block_splash_add_label(block, version_buf, splash_width, splash_height - 13.0 * U.dpi_fac); + wm_block_splash_add_label( + block, BKE_blender_version_string(), splash_width, splash_height - 13.0 * U.dpi_fac); const int layout_margin_x = U.dpi_fac * 26; uiLayout *layout = UI_block_layout(block, @@ -329,9 +298,7 @@ static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED uiItemL_ex(layout, "Blender", ICON_NONE, true, false); /* Version. */ - char str_buf[256] = "\0"; - get_version_string(str_buf, sizeof(str_buf)); - uiItemL(layout, str_buf, ICON_NONE); + uiItemL(layout, BKE_blender_version_string(), ICON_NONE); uiItemS_ex(layout, 3.0f); @@ -339,6 +306,7 @@ static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[]; + char str_buf[256] = "\0"; BLI_snprintf(str_buf, sizeof(str_buf), "Date: %s %s", build_commit_date, build_commit_time); uiItemL(layout, str_buf, ICON_NONE); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index b1eee7509b7..02b50af0ac3 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -84,11 +84,11 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_context.h" -#include "GPU_draw.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_init_exit.h" #include "GPU_platform.h" +#include "GPU_state.h" #include "UI_resources.h" @@ -286,14 +286,15 @@ static int find_free_winid(wmWindowManager *wm) } /* don't change context itself */ -wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent) +wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog) { wmWindow *win = MEM_callocN(sizeof(wmWindow), "window"); BLI_addtail(&wm->windows, win); win->winid = find_free_winid(wm); - win->parent = (parent && parent->parent) ? parent->parent : parent; + /* Dialogs may have a child window as parent. Otherwise, a child must not be a parent too. */ + win->parent = (!dialog && parent && parent->parent) ? parent->parent : parent; win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)"); win->workspace_hook = BKE_workspace_instance_hook_create(bmain); @@ -307,8 +308,9 @@ wmWindow *wm_window_copy(Main *bmain, const bool duplicate_layout, const bool child) { + const bool is_dialog = GHOST_IsDialogWindow(win_src->ghostwin); wmWindow *win_parent = (child) ? win_src : win_src->parent; - wmWindow *win_dst = wm_window_new(bmain, wm, win_parent); + wmWindow *win_dst = wm_window_new(bmain, wm, win_parent, is_dialog); WorkSpace *workspace = WM_window_get_active_workspace(win_src); WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src); WorkSpaceLayout *layout_new; @@ -324,7 +326,7 @@ wmWindow *wm_window_copy(Main *bmain, layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old; - BKE_workspace_hook_layout_for_workspace_set(win_dst->workspace_hook, workspace, layout_new); + BKE_workspace_active_layout_set(win_dst->workspace_hook, workspace, layout_new); *win_dst->stereo3d_format = *win_src->stereo3d_format; @@ -417,7 +419,6 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { wmWindow *win_other; - const bool is_dialog = (G.background == false) ? GHOST_IsDialogWindow(win->ghostwin) : false; /* First check if there is another main window remaining. */ for (win_other = wm->windows.first; win_other; win_other = win_other->next) { @@ -431,20 +432,11 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) return; } - /* Close child windows and bring windows back to front that dialogs have pushed behind the main - * window. */ - LISTBASE_FOREACH (wmWindow *, iter_win, &wm->windows) { + /* Close child windows */ + LISTBASE_FOREACH_MUTABLE (wmWindow *, iter_win, &wm->windows) { if (iter_win->parent == win) { wm_window_close(C, wm, iter_win); } - else { - if (G.background == false) { - if (is_dialog && iter_win != win && iter_win->parent && - (GHOST_GetWindowState(iter_win->ghostwin) != GHOST_kWindowStateMinimized)) { - wm_window_raise(iter_win); - } - } - } } bScreen *screen = WM_window_get_active_screen(win); @@ -834,7 +826,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win_prev = CTX_wm_window(C); - wmWindow *win = wm_window_new(CTX_data_main(C), wm, win_prev); + wmWindow *win = wm_window_new(CTX_data_main(C), wm, win_prev, false); win->posx = rect->xmin; win->posy = rect->ymin; @@ -905,7 +897,7 @@ wmWindow *WM_window_open_temp(bContext *C, /* add new window? */ if (win == NULL) { - win = wm_window_new(bmain, wm, win_prev); + win = wm_window_new(bmain, wm, win_prev, dialog); win->posx = rect.xmin; win->posy = rect.ymin; @@ -2367,7 +2359,7 @@ WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win) } void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout) { - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); } /** diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index ffa5baae9f1..efcf40d03eb 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -149,6 +149,11 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file); void wm_event_do_refresh_wm_and_depsgraph(bContext *C); void wm_event_do_notifiers(bContext *C); +void wm_event_handler_ui_cancel_ex(bContext *C, + wmWindow *win, + ARegion *region, + bool reactivate_button); + /* wm_event_query.c */ float wm_pressure_curve(float raw_pressure); void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index f16056cc91e..ffed86abfe7 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -333,6 +333,7 @@ enum { EVT_BUT_OPEN = 0x5021, /* 20513 */ EVT_MODAL_MAP = 0x5022, /* 20514 */ EVT_DROP = 0x5023, /* 20515 */ + /* When value is 0, re-activate, when 1, don't re-activate the button under the cursor. */ EVT_BUT_CANCEL = 0x5024, /* 20516 */ /* could become gizmo callback */ diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 45cfe1431d7..5ca5711b4f2 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -33,7 +33,10 @@ void wm_ghost_exit(void); void wm_get_screensize(int *r_width, int *r_height); void wm_get_desktopsize(int *r_width, int *r_height); -wmWindow *wm_window_new(const struct Main *bmain, wmWindowManager *wm, wmWindow *parent); +wmWindow *wm_window_new(const struct Main *bmain, + wmWindowManager *wm, + wmWindow *parent, + bool dialog); wmWindow *wm_window_copy(struct Main *bmain, wmWindowManager *wm, wmWindow *win_src, diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c index 69c9034d51f..90f30809136 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr.c +++ b/source/blender/windowmanager/xr/intern/wm_xr.c @@ -126,7 +126,12 @@ void wm_xr_exit(wmWindowManager *wm) bool wm_xr_events_handle(wmWindowManager *wm) { if (wm->xr.runtime && wm->xr.runtime->context) { - return GHOST_XrEventsHandle(wm->xr.runtime->context); + GHOST_XrEventsHandle(wm->xr.runtime->context); + + /* wm_window_process_events() uses the return value to determine if it can put the main thread + * to sleep for some milliseconds. We never want that to happen while the VR session runs on + * the main thread. So always return true. */ + return true; } return false; } diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index b3e83b1412f..aed2a9350bb 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -687,6 +687,13 @@ elseif(WIN32) ) endif() + if(WITH_FFTW3) + install( + FILES ${LIBDIR}/fftw3/lib/libfftw3-3.dll + DESTINATION "." + ) + endif() + if(WITH_WINDOWS_PDB) if(WITH_WINDOWS_STRIPPED_PDB) # Icky hack for older cmake from https://stackoverflow.com/a/21198501 @@ -936,8 +943,8 @@ elseif(APPLE) set_target_properties(blender PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${OSX_APP_SOURCEDIR}/Contents/Info.plist - MACOSX_BUNDLE_SHORT_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR}" - MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR} ${BLENDER_DATE}") + MACOSX_BUNDLE_SHORT_VERSION_STRING "${BLENDER_VERSION}.${BLENDER_VERSION_PATCH}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}.${BLENDER_VERSION_PATCH} ${BLENDER_DATE}") # Gather the date in finder-style execute_process(COMMAND date "+%m/%d/%Y/%H:%M" diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index bd56d86784e..a2389b02d8f 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -460,7 +460,7 @@ static void arg_py_context_restore(bContext *C, struct BlendePyContextStore *c_p static void print_version_full(void) { - printf(BLEND_VERSION_STRING_FMT); + printf("Blender %s\n", BKE_blender_version_string()); # ifdef BUILD_DATE printf("\tbuild date: %s\n", build_date); printf("\tbuild time: %s\n", build_time); @@ -481,13 +481,13 @@ static void print_version_short(void) # ifdef BUILD_DATE /* NOTE: We include built time since sometimes we need to tell broken from * working built of the same hash. */ - printf(BLEND_VERSION_FMT " (hash %s built %s %s)\n", - BLEND_VERSION_ARG, + printf("Blender %s (hash %s built %s %s)\n", + BKE_blender_version_string(), build_hash, build_date, build_time); # else - printf(BLEND_VERSION_STRING_FMT); + printf("Blender %s\n", BKE_blender_version_string()); # endif } @@ -513,7 +513,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo { bArgs *ba = (bArgs *)data; - printf(BLEND_VERSION_STRING_FMT); + printf("Blender %s\n", BKE_blender_version_string()); printf("Usage: blender [args ...] [file] [args ...]\n\n"); printf("Render Options:\n"); @@ -907,7 +907,7 @@ static const char arg_handle_debug_mode_set_doc[] = static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *data) { G.debug |= G_DEBUG; /* std output printf's */ - printf(BLEND_VERSION_STRING_FMT); + printf("Blender %s\n", BKE_blender_version_string()); MEM_set_memory_debug(); # ifndef NDEBUG BLI_mempool_set_memory_debug(); @@ -959,7 +959,7 @@ static const char arg_handle_debug_mode_generic_set_doc_jobs[] = "Enable time profiling for background jobs."; static const char arg_handle_debug_mode_generic_set_doc_gpu[] = "\n\t" - "Enable gpu debug context and information for OpenGL 4.3+."; + "Enable GPU debug context and information for OpenGL 4.3+."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] = "\n\t" "Enable all debug messages from dependency graph."; @@ -995,7 +995,7 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), static const char arg_handle_debug_mode_io_doc[] = "\n\t" - "Enable debug messages for I/O (collada, ...)."; + "Enable debug messages for I/O (Collada, ...)."; static int arg_handle_debug_mode_io(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) @@ -1124,7 +1124,7 @@ static int arg_handle_factory_startup_set(int UNUSED(argc), static const char arg_handle_disable_override_library_doc[] = "\n\t" - "Enable Library Override features in the UI."; + "Disable Library Override features in the UI."; static int arg_handle_disable_override_library(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) @@ -1497,7 +1497,7 @@ static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data static const char arg_handle_verbosity_set_doc[] = "<verbose>\n" - "\tSet logging verbosity level for debug messages which supports it."; + "\tSet the logging verbosity level for debug messages that support it."; static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(data)) { const char *arg_id = "--verbose"; @@ -1592,7 +1592,6 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data) } re = RE_NewSceneRender(scene); - BLI_threaded_malloc_begin(); BKE_reports_init(&reports, RPT_STORE); RE_SetReports(re, &reports); for (int i = 0; i < frames_range_len; i++) { @@ -1608,7 +1607,6 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data) } RE_SetReports(re, NULL); BKE_reports_clear(&reports); - BLI_threaded_malloc_end(); MEM_freeN(frame_range_arr); return 1; } @@ -1634,13 +1632,11 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg Main *bmain = CTX_data_main(C); Render *re = RE_NewSceneRender(scene); ReportList reports; - BLI_threaded_malloc_begin(); BKE_reports_init(&reports, RPT_STORE); RE_SetReports(re, &reports); RE_RenderAnim(re, bmain, scene, NULL, NULL, scene->r.sfra, scene->r.efra, scene->r.frame_step); RE_SetReports(re, NULL); BKE_reports_clear(&reports); - BLI_threaded_malloc_end(); } else { printf("\nError: no blend loaded. cannot use '-a'.\n"); diff --git a/source/creator/creator_intern.h b/source/creator/creator_intern.h index 959fb71d218..9c7d3d95498 100644 --- a/source/creator/creator_intern.h +++ b/source/creator/creator_intern.h @@ -55,10 +55,8 @@ extern struct ApplicationState app_state; /* creator.c */ /* for the callbacks: */ #ifndef WITH_PYTHON_MODULE -# define BLEND_VERSION_FMT "Blender %d.%02d (sub %d)" -# define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION -/* pass directly to printf */ -# define BLEND_VERSION_STRING_FMT BLEND_VERSION_FMT "\n", BLEND_VERSION_ARG +# define BLEND_VERSION_FMT "Blender %d.%02d.%d" +# define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_VERSION_PATCH #endif #ifdef WITH_BUILDINFO_HEADER diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 80d749c7040..0ee3b500fdf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,7 +19,11 @@ elseif(APPLE) set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/Blender.app/Contents/MacOS/Blender) set(_default_test_python_exe ${PYTHON_EXECUTABLE}) else() - set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/blender) + if(WITH_INSTALL_PORTABLE) + set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/blender) + else() + set(TEST_BLENDER_EXE ${TEST_INSTALL_DIR}/bin/blender) + endif() set(_default_test_python_exe ${PYTHON_EXECUTABLE}) endif() diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc index ed00fb759cd..1002ff7d2df 100644 --- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc +++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc @@ -277,7 +277,7 @@ static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int unsigned int i; { - RNG *rng = BLI_rng_new(0); + RNG *rng = BLI_rng_new(1); for (i = nbr, dt = data; i--; dt++) { *dt = BLI_rng_get_uint(rng); } @@ -386,7 +386,7 @@ static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nb unsigned int i, j; { - RNG *rng = BLI_rng_new(0); + RNG *rng = BLI_rng_new(1); for (i = nbr, dt = data; i--; dt++) { for (j = 4; j--;) { (*dt)[j] = BLI_rng_get_uint(rng); @@ -493,7 +493,7 @@ static void int2_ghash_tests(GHash *ghash, const char *id, const unsigned int nb unsigned int i, j; { - RNG *rng = BLI_rng_new(0); + RNG *rng = BLI_rng_new(1); for (i = nbr, dt = data; i--; dt++) { for (j = 2; j--;) { (*dt)[j] = BLI_rng_get_uint(rng); @@ -604,7 +604,7 @@ static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned { printf("\n========== STARTING %s ==========\n", id); - RNG *rng = BLI_rng_new(0); + RNG *rng = BLI_rng_new(1); TIMEIT_START(multi_small_ghash); diff --git a/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc index 023d02e5075..d1a527d57ac 100644 --- a/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc +++ b/tests/gtests/blenlib/BLI_linklist_lockfree_test.cc @@ -87,9 +87,7 @@ TEST(LockfreeLinkList, InsertMultipleConcurrent) BLI_task_pool_push(pool, concurrent_insert, POINTER_FROM_INT(i), false, NULL); } /* Run all the tasks. */ - BLI_threaded_malloc_begin(); BLI_task_pool_work_and_wait(pool); - BLI_threaded_malloc_end(); /* Verify we've got all the data properly inserted. */ EXPECT_EQ(list.head, &list.dummy_node); bool *visited_nodes = (bool *)MEM_callocN(sizeof(bool) * num_nodes, "visited nodes"); diff --git a/tests/gtests/blenlib/BLI_task_graph_test.cc b/tests/gtests/blenlib/BLI_task_graph_test.cc new file mode 100644 index 00000000000..efcbf923625 --- /dev/null +++ b/tests/gtests/blenlib/BLI_task_graph_test.cc @@ -0,0 +1,188 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_task.h" + +struct TaskData { + int value; + int store; +}; + +static void TaskData_increase_value(void *taskdata) +{ + TaskData *data = (TaskData *)taskdata; + data->value += 1; +} +static void TaskData_decrease_value(void *taskdata) +{ + TaskData *data = (TaskData *)taskdata; + data->value -= 1; +} +static void TaskData_multiply_by_two_value(void *taskdata) +{ + TaskData *data = (TaskData *)taskdata; + data->value *= 2; +} + +static void TaskData_multiply_by_two_store(void *taskdata) +{ + TaskData *data = (TaskData *)taskdata; + data->store *= 2; +} + +static void TaskData_store_value(void *taskdata) +{ + TaskData *data = (TaskData *)taskdata; + data->store = data->value; +} + +static void TaskData_square_value(void *taskdata) +{ + TaskData *data = (TaskData *)taskdata; + data->value *= data->value; +} + +/* Sequential Test for using `BLI_task_graph` */ +TEST(task, GraphSequential) +{ + TaskData data = {0}; + TaskGraph *graph = BLI_task_graph_create(); + + /* 0 => 1 */ + TaskNode *node_a = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL); + /* 1 => 2 */ + TaskNode *node_b = BLI_task_graph_node_create( + graph, TaskData_multiply_by_two_value, &data, NULL); + /* 2 => 1 */ + TaskNode *node_c = BLI_task_graph_node_create(graph, TaskData_decrease_value, &data, NULL); + /* 2 => 1 */ + TaskNode *node_d = BLI_task_graph_node_create(graph, TaskData_square_value, &data, NULL); + /* 1 => 1 */ + TaskNode *node_e = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL); + /* 1 => 2 */ + const int expected_value = 2; + + BLI_task_graph_edge_create(node_a, node_b); + BLI_task_graph_edge_create(node_b, node_c); + BLI_task_graph_edge_create(node_c, node_d); + BLI_task_graph_edge_create(node_d, node_e); + + EXPECT_TRUE(BLI_task_graph_node_push_work(node_a)); + BLI_task_graph_work_and_wait(graph); + + EXPECT_EQ(expected_value, data.value); + BLI_task_graph_free(graph); +} + +TEST(task, GraphStartAtAnyNode) +{ + TaskData data = {4}; + TaskGraph *graph = BLI_task_graph_create(); + + TaskNode *node_a = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL); + TaskNode *node_b = BLI_task_graph_node_create( + graph, TaskData_multiply_by_two_value, &data, NULL); + TaskNode *node_c = BLI_task_graph_node_create(graph, TaskData_decrease_value, &data, NULL); + TaskNode *node_d = BLI_task_graph_node_create(graph, TaskData_square_value, &data, NULL); + TaskNode *node_e = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL); + + // ((4 - 1) * (4 - 1)) + 1 + const int expected_value = 10; + + BLI_task_graph_edge_create(node_a, node_b); + BLI_task_graph_edge_create(node_b, node_c); + BLI_task_graph_edge_create(node_c, node_d); + BLI_task_graph_edge_create(node_d, node_e); + + EXPECT_TRUE(BLI_task_graph_node_push_work(node_c)); + BLI_task_graph_work_and_wait(graph); + + EXPECT_EQ(expected_value, data.value); + BLI_task_graph_free(graph); +} + +TEST(task, GraphSplit) +{ + TaskData data = {1}; + + TaskGraph *graph = BLI_task_graph_create(); + TaskNode *node_a = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL); + TaskNode *node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data, NULL); + TaskNode *node_c = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL); + TaskNode *node_d = BLI_task_graph_node_create( + graph, TaskData_multiply_by_two_store, &data, NULL); + BLI_task_graph_edge_create(node_a, node_b); + BLI_task_graph_edge_create(node_b, node_c); + BLI_task_graph_edge_create(node_b, node_d); + EXPECT_TRUE(BLI_task_graph_node_push_work(node_a)); + BLI_task_graph_work_and_wait(graph); + + EXPECT_EQ(3, data.value); + EXPECT_EQ(4, data.store); + BLI_task_graph_free(graph); +} + +TEST(task, GraphForest) +{ + TaskData data1 = {1}; + TaskData data2 = {3}; + + TaskGraph *graph = BLI_task_graph_create(); + + { + TaskNode *tree1_node_a = BLI_task_graph_node_create( + graph, TaskData_increase_value, &data1, NULL); + TaskNode *tree1_node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data1, NULL); + TaskNode *tree1_node_c = BLI_task_graph_node_create( + graph, TaskData_increase_value, &data1, NULL); + TaskNode *tree1_node_d = BLI_task_graph_node_create( + graph, TaskData_multiply_by_two_store, &data1, NULL); + BLI_task_graph_edge_create(tree1_node_a, tree1_node_b); + BLI_task_graph_edge_create(tree1_node_b, tree1_node_c); + BLI_task_graph_edge_create(tree1_node_b, tree1_node_d); + EXPECT_TRUE(BLI_task_graph_node_push_work(tree1_node_a)); + } + + { + TaskNode *tree2_node_a = BLI_task_graph_node_create( + graph, TaskData_increase_value, &data2, NULL); + TaskNode *tree2_node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data2, NULL); + TaskNode *tree2_node_c = BLI_task_graph_node_create( + graph, TaskData_increase_value, &data2, NULL); + TaskNode *tree2_node_d = BLI_task_graph_node_create( + graph, TaskData_multiply_by_two_store, &data2, NULL); + BLI_task_graph_edge_create(tree2_node_a, tree2_node_b); + BLI_task_graph_edge_create(tree2_node_b, tree2_node_c); + BLI_task_graph_edge_create(tree2_node_b, tree2_node_d); + EXPECT_TRUE(BLI_task_graph_node_push_work(tree2_node_a)); + } + + BLI_task_graph_work_and_wait(graph); + + EXPECT_EQ(3, data1.value); + EXPECT_EQ(4, data1.store); + EXPECT_EQ(5, data2.value); + EXPECT_EQ(8, data2.store); + BLI_task_graph_free(graph); +} + +TEST(task, GraphTaskData) +{ + TaskData data = {0}; + TaskGraph *graph = BLI_task_graph_create(); + TaskNode *node_a = BLI_task_graph_node_create( + graph, TaskData_store_value, &data, TaskData_increase_value); + TaskNode *node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data, NULL); + BLI_task_graph_edge_create(node_a, node_b); + EXPECT_TRUE(BLI_task_graph_node_push_work(node_a)); + BLI_task_graph_work_and_wait(graph); + EXPECT_EQ(0, data.value); + EXPECT_EQ(0, data.store); + BLI_task_graph_free(graph); + /* data should be freed once */ + EXPECT_EQ(1, data.value); + EXPECT_EQ(0, data.store); +} diff --git a/tests/gtests/blenlib/BLI_type_construct_mock.hh b/tests/gtests/blenlib/BLI_type_construct_mock.hh new file mode 100644 index 00000000000..72767631608 --- /dev/null +++ b/tests/gtests/blenlib/BLI_type_construct_mock.hh @@ -0,0 +1,63 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ANY_TYPE_MOCK_TEST_H__ +#define __ANY_TYPE_MOCK_TEST_H__ + +#include "BLI_sys_types.h" + +class TypeConstructMock { + public: + bool default_constructed = false; + bool copy_constructed = false; + bool move_constructed = false; + bool copy_assigned = false; + bool move_assigned = false; + + TypeConstructMock() : default_constructed(true) + { + } + + TypeConstructMock(const TypeConstructMock &other) : copy_constructed(true) + { + } + + TypeConstructMock(TypeConstructMock &&other) : move_constructed(true) + { + } + + TypeConstructMock &operator=(const TypeConstructMock &other) + { + if (this == &other) { + return *this; + } + + copy_assigned = true; + return *this; + } + + TypeConstructMock &operator=(TypeConstructMock &&other) + { + if (this == &other) { + return *this; + } + + move_assigned = true; + return *this; + } +}; + +#endif /* __ANY_TYPE_MOCK_TEST_H__ */ diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/tests/gtests/blenlib/BLI_vector_test.cc index e5a1ca2b200..90180feba1f 100644 --- a/tests/gtests/blenlib/BLI_vector_test.cc +++ b/tests/gtests/blenlib/BLI_vector_test.cc @@ -1,19 +1,19 @@ +#include "BLI_type_construct_mock.hh" #include "BLI_vector.hh" #include "testing/testing.h" #include <forward_list> using BLI::Vector; -using IntVector = Vector<int>; TEST(vector, DefaultConstructor) { - IntVector vec; + Vector<int> vec; EXPECT_EQ(vec.size(), 0); } TEST(vector, SizeConstructor) { - IntVector vec(3); + Vector<int> vec(3); EXPECT_EQ(vec.size(), 3); EXPECT_EQ(vec[0], 0); EXPECT_EQ(vec[1], 0); @@ -22,7 +22,7 @@ TEST(vector, SizeConstructor) TEST(vector, SizeValueConstructor) { - IntVector vec(4, 10); + Vector<int> vec(4, 10); EXPECT_EQ(vec.size(), 4); EXPECT_EQ(vec[0], 10); EXPECT_EQ(vec[1], 10); @@ -32,7 +32,7 @@ TEST(vector, SizeValueConstructor) TEST(vector, InitializerListConstructor) { - IntVector vec = {1, 3, 4, 6}; + Vector<int> vec = {1, 3, 4, 6}; EXPECT_EQ(vec.size(), 4); EXPECT_EQ(vec[0], 1); EXPECT_EQ(vec[1], 3); @@ -74,7 +74,7 @@ TEST(vector, ContainerConstructor) list.push_front(1); list.push_front(5); - IntVector vec = IntVector::FromContainer(list); + Vector<int> vec = Vector<int>::FromContainer(list); EXPECT_EQ(vec.size(), 3); EXPECT_EQ(vec[0], 5); EXPECT_EQ(vec[1], 1); @@ -83,8 +83,8 @@ TEST(vector, ContainerConstructor) TEST(vector, CopyConstructor) { - IntVector vec1 = {1, 2, 3}; - IntVector vec2(vec1); + Vector<int> vec1 = {1, 2, 3}; + Vector<int> vec2(vec1); EXPECT_EQ(vec2.size(), 3); EXPECT_EQ(vec2[0], 1); EXPECT_EQ(vec2[1], 2); @@ -133,8 +133,8 @@ TEST(vector, CopyConstructor4) TEST(vector, MoveConstructor) { - IntVector vec1 = {1, 2, 3, 4}; - IntVector vec2(std::move(vec1)); + Vector<int> vec1 = {1, 2, 3, 4}; + Vector<int> vec2(std::move(vec1)); EXPECT_EQ(vec1.size(), 0); EXPECT_EQ(vec2.size(), 4); @@ -179,20 +179,20 @@ TEST(vector, MoveConstructor4) TEST(vector, MoveAssignment) { - IntVector vec = {1, 2}; + Vector<int> vec = {1, 2}; EXPECT_EQ(vec.size(), 2); EXPECT_EQ(vec[0], 1); EXPECT_EQ(vec[1], 2); - vec = IntVector({5}); + vec = Vector<int>({5}); EXPECT_EQ(vec.size(), 1); EXPECT_EQ(vec[0], 5); } TEST(vector, CopyAssignment) { - IntVector vec1 = {1, 2, 3}; - IntVector vec2 = {4, 5}; + Vector<int> vec1 = {1, 2, 3}; + Vector<int> vec2 = {4, 5}; EXPECT_EQ(vec1.size(), 3); EXPECT_EQ(vec2.size(), 2); @@ -206,7 +206,7 @@ TEST(vector, CopyAssignment) TEST(vector, Append) { - IntVector vec; + Vector<int> vec; vec.append(3); vec.append(6); vec.append(7); @@ -218,7 +218,7 @@ TEST(vector, Append) TEST(vector, AppendAndGetIndex) { - IntVector vec; + Vector<int> vec; EXPECT_EQ(vec.append_and_get_index(10), 0); EXPECT_EQ(vec.append_and_get_index(10), 1); EXPECT_EQ(vec.append_and_get_index(10), 2); @@ -228,7 +228,7 @@ TEST(vector, AppendAndGetIndex) TEST(vector, AppendNonDuplicates) { - IntVector vec; + Vector<int> vec; vec.append_non_duplicates(4); EXPECT_EQ(vec.size(), 1); vec.append_non_duplicates(5); @@ -239,7 +239,7 @@ TEST(vector, AppendNonDuplicates) TEST(vector, ExtendNonDuplicates) { - IntVector vec; + Vector<int> vec; vec.extend_non_duplicates({1, 2}); EXPECT_EQ(vec.size(), 2); vec.extend_non_duplicates({3, 4}); @@ -250,7 +250,7 @@ TEST(vector, ExtendNonDuplicates) TEST(vector, Fill) { - IntVector vec(5); + Vector<int> vec(5); vec.fill(3); EXPECT_EQ(vec.size(), 5); EXPECT_EQ(vec[0], 3); @@ -262,7 +262,7 @@ TEST(vector, Fill) TEST(vector, FillIndices) { - IntVector vec(5, 0); + Vector<int> vec(5, 0); vec.fill_indices({1, 2}, 4); EXPECT_EQ(vec[0], 0); EXPECT_EQ(vec[1], 4); @@ -273,7 +273,7 @@ TEST(vector, FillIndices) TEST(vector, Iterator) { - IntVector vec({1, 4, 9, 16}); + Vector<int> vec({1, 4, 9, 16}); int i = 1; for (int value : vec) { EXPECT_EQ(value, i * i); @@ -293,14 +293,14 @@ TEST(vector, BecomeLarge) } } -static IntVector return_by_value_helper() +static Vector<int> return_by_value_helper() { - return IntVector({3, 5, 1}); + return Vector<int>({3, 5, 1}); } TEST(vector, ReturnByValue) { - IntVector vec = return_by_value_helper(); + Vector<int> vec = return_by_value_helper(); EXPECT_EQ(vec.size(), 3); EXPECT_EQ(vec[0], 3); EXPECT_EQ(vec[1], 5); @@ -309,10 +309,10 @@ TEST(vector, ReturnByValue) TEST(vector, VectorOfVectors_Append) { - Vector<IntVector> vec; + Vector<Vector<int>> vec; EXPECT_EQ(vec.size(), 0); - IntVector v({1, 2}); + Vector<int> v({1, 2}); vec.append(v); vec.append({7, 8}); EXPECT_EQ(vec.size(), 2); @@ -324,7 +324,7 @@ TEST(vector, VectorOfVectors_Append) TEST(vector, VectorOfVectors_Fill) { - Vector<IntVector> vec(3); + Vector<Vector<int>> vec(3); vec.fill({4, 5}); EXPECT_EQ(vec[0][0], 4); @@ -337,7 +337,7 @@ TEST(vector, VectorOfVectors_Fill) TEST(vector, RemoveLast) { - IntVector vec = {5, 6}; + Vector<int> vec = {5, 6}; EXPECT_EQ(vec.size(), 2); vec.remove_last(); EXPECT_EQ(vec.size(), 1); @@ -347,7 +347,7 @@ TEST(vector, RemoveLast) TEST(vector, IsEmpty) { - IntVector vec; + Vector<int> vec; EXPECT_TRUE(vec.is_empty()); vec.append(1); EXPECT_FALSE(vec.is_empty()); @@ -357,7 +357,7 @@ TEST(vector, IsEmpty) TEST(vector, RemoveReorder) { - IntVector vec = {4, 5, 6, 7}; + Vector<int> vec = {4, 5, 6, 7}; vec.remove_and_reorder(1); EXPECT_EQ(vec[0], 4); EXPECT_EQ(vec[1], 7); @@ -373,7 +373,7 @@ TEST(vector, RemoveReorder) TEST(vector, RemoveFirstOccurrenceAndReorder) { - IntVector vec = {4, 5, 6, 7}; + Vector<int> vec = {4, 5, 6, 7}; vec.remove_first_occurrence_and_reorder(5); EXPECT_EQ(vec[0], 4); EXPECT_EQ(vec[1], 7); @@ -389,24 +389,24 @@ TEST(vector, RemoveFirstOccurrenceAndReorder) TEST(vector, AllEqual_False) { - IntVector a = {1, 2, 3}; - IntVector b = {1, 2, 4}; - bool result = IntVector::all_equal(a, b); + Vector<int> a = {1, 2, 3}; + Vector<int> b = {1, 2, 4}; + bool result = Vector<int>::all_equal(a, b); EXPECT_FALSE(result); } TEST(vector, AllEqual_True) { - IntVector a = {4, 5, 6}; - IntVector b = {4, 5, 6}; - bool result = IntVector::all_equal(a, b); + Vector<int> a = {4, 5, 6}; + Vector<int> b = {4, 5, 6}; + bool result = Vector<int>::all_equal(a, b); EXPECT_TRUE(result); } TEST(vector, ExtendSmallVector) { - IntVector a = {2, 3, 4}; - IntVector b = {11, 12}; + Vector<int> a = {2, 3, 4}; + Vector<int> b = {11, 12}; b.extend(a); EXPECT_EQ(b.size(), 5); EXPECT_EQ(b[0], 11); @@ -420,7 +420,7 @@ TEST(vector, ExtendArray) { int array[] = {3, 4, 5, 6}; - IntVector a; + Vector<int> a; a.extend(array, 2); EXPECT_EQ(a.size(), 2); @@ -430,13 +430,13 @@ TEST(vector, ExtendArray) TEST(vector, Last) { - IntVector a{3, 5, 7}; + Vector<int> a{3, 5, 7}; EXPECT_EQ(a.last(), 7); } TEST(vector, AppendNTimes) { - IntVector a; + Vector<int> a; a.append_n_times(5, 3); a.append_n_times(2, 2); EXPECT_EQ(a.size(), 5); @@ -460,3 +460,68 @@ TEST(vector, UniquePtrValue) UNUSED_VARS(a, b); } + +TEST(vector, SizeConstructorCallsDefaultConstructor) +{ + Vector<TypeConstructMock> vec(3); + EXPECT_TRUE(vec[0].default_constructed); + EXPECT_TRUE(vec[1].default_constructed); + EXPECT_TRUE(vec[2].default_constructed); +} + +TEST(vector, SizeValueConstructorCallsCopyConstructor) +{ + Vector<TypeConstructMock> vec(3, TypeConstructMock()); + EXPECT_TRUE(vec[0].copy_constructed); + EXPECT_TRUE(vec[1].copy_constructed); + EXPECT_TRUE(vec[2].copy_constructed); +} + +TEST(vector, AppendCallsCopyConstructor) +{ + Vector<TypeConstructMock> vec; + TypeConstructMock value; + vec.append(value); + EXPECT_TRUE(vec[0].copy_constructed); +} + +TEST(vector, AppendCallsMoveConstructor) +{ + Vector<TypeConstructMock> vec; + vec.append(TypeConstructMock()); + EXPECT_TRUE(vec[0].move_constructed); +} + +TEST(vector, SmallVectorCopyCallsCopyConstructor) +{ + Vector<TypeConstructMock, 2> src(2); + Vector<TypeConstructMock, 2> dst(src); + EXPECT_TRUE(dst[0].copy_constructed); + EXPECT_TRUE(dst[1].copy_constructed); +} + +TEST(vector, LargeVectorCopyCallsCopyConstructor) +{ + Vector<TypeConstructMock, 2> src(5); + Vector<TypeConstructMock, 2> dst(src); + EXPECT_TRUE(dst[0].copy_constructed); + EXPECT_TRUE(dst[1].copy_constructed); +} + +TEST(vector, SmallVectorMoveCallsMoveConstructor) +{ + Vector<TypeConstructMock, 2> src(2); + Vector<TypeConstructMock, 2> dst(std::move(src)); + EXPECT_TRUE(dst[0].move_constructed); + EXPECT_TRUE(dst[1].move_constructed); +} + +TEST(vector, LargeVectorMoveCallsNoConstructor) +{ + Vector<TypeConstructMock, 2> src(5); + Vector<TypeConstructMock, 2> dst(std::move(src)); + + EXPECT_TRUE(dst[0].default_constructed); + EXPECT_FALSE(dst[0].move_constructed); + EXPECT_FALSE(dst[0].copy_constructed); +} diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt index a0621448630..6fbb304581d 100644 --- a/tests/gtests/blenlib/CMakeLists.txt +++ b/tests/gtests/blenlib/CMakeLists.txt @@ -72,6 +72,7 @@ BLENDER_TEST(BLI_string_map "bf_blenlib") BLENDER_TEST(BLI_string_ref "bf_blenlib") BLENDER_TEST(BLI_string_utf8 "bf_blenlib") BLENDER_TEST(BLI_task "bf_blenlib;bf_intern_numaapi") +BLENDER_TEST(BLI_task_graph "bf_blenlib;bf_intern_numaapi") BLENDER_TEST(BLI_vector "bf_blenlib") BLENDER_TEST(BLI_vector_set "bf_blenlib") diff --git a/tests/python/alembic_tests.py b/tests/python/alembic_tests.py index 8c0315f1b68..2d477c5a6f0 100644 --- a/tests/python/alembic_tests.py +++ b/tests/python/alembic_tests.py @@ -84,6 +84,7 @@ class AbstractAlembicTest(AbstractBlenderRunnerTest): 'uint8_t': int, 'int16_t': int, 'int32_t': int, + 'uint32_t': int, 'uint64_t': int, 'float64_t': float, 'float32_t': float, @@ -325,6 +326,60 @@ class HairParticlesExportTest(AbstractAlembicTest): self.assertIn('.faceIndices', abcprop) +class UVMapExportTest(AbstractAlembicTest): + @with_tempdir + def test_uvmap_export(self, tempdir: pathlib.Path): + """Minimal test for exporting multiple UV maps on an animated mesh. + + This covers the issue reported in T77021. + """ + basename = 'T77021-multiple-uvmaps-animated-mesh' + abc = tempdir / f'{basename}.abc' + script = f"import bpy; bpy.ops.wm.alembic_export(filepath='{abc.as_posix()}', start=1, end=1, " \ + f"renderable_only=True, visible_objects_only=True, flatten=False)" + self.run_blender(f'{basename}.blend', script) + + self.maxDiff = 1000 + + # The main UV map should be written to .geom + abcprop = self.abcprop(abc, '/Cube/CubeShape/.geom/uv') + self.assertEqual(abcprop['.vals'], [ + [0.625, 0.75], + [0.875, 0.75], + [0.875, 0.5], + [0.625, 0.5], + [0.375, 1.0], + [0.625, 1.0], + [0.375, 0.75], + [0.375, 0.25], + [0.625, 0.25], + [0.625, 0.0], + [0.375, 0.0], + [0.125, 0.75], + [0.375, 0.5], + [0.125, 0.5], + ]) + + # The second UV map should be written to .arbGeomParams + abcprop = self.abcprop(abc, '/Cube/CubeShape/.geom/.arbGeomParams/Secondary') + self.assertEqual(abcprop['.vals'], [ + [0.75, 0.375], + [0.75, 0.125], + [0.5, 0.125], + [0.5, 0.375], + [1.0, 0.625], + [1.0, 0.375], + [0.75, 0.625], + [0.25, 0.625], + [0.25, 0.375], + [0.0, 0.375], + [0.0, 0.625], + [0.75, 0.875], + [0.5, 0.625], + [0.5, 0.875], + ]) + + class LongNamesExportTest(AbstractAlembicTest): @with_tempdir def test_export_long_names(self, tempdir: pathlib.Path): diff --git a/tests/python/bl_constraints.py b/tests/python/bl_constraints.py index 9fce8acc84e..323dd874ac0 100644 --- a/tests/python/bl_constraints.py +++ b/tests/python/bl_constraints.py @@ -56,21 +56,37 @@ class AbstractConstraintTests(unittest.TestCase): actual, expect, places=places, delta=delta, msg=f'Matrix of object {object_name!r} failed: {actual} != {expect} at element [{row}][{col}]') - def matrix(self, object_name: str) -> Matrix: - """Return the evaluated world matrix.""" + def _get_eval_object(self, object_name: str) -> bpy.types.Object: + """Return the evaluated object.""" depsgraph = bpy.context.view_layer.depsgraph depsgraph.update() ob_orig = bpy.context.scene.objects[object_name] ob_eval = ob_orig.evaluated_get(depsgraph) + return ob_eval + + def matrix(self, object_name: str) -> Matrix: + """Return the evaluated world matrix.""" + ob_eval = self._get_eval_object(object_name) return ob_eval.matrix_world + def bone_matrix(self, object_name: str, bone_name: str) -> Matrix: + """Return the evaluated world matrix of the bone.""" + ob_eval = self._get_eval_object(object_name) + bone = ob_eval.pose.bones[bone_name] + return ob_eval.matrix_world @ bone.matrix + def matrix_test(self, object_name: str, expect: Matrix): """Assert that the object's world matrix is as expected.""" actual = self.matrix(object_name) self.assert_matrix(actual, expect, object_name) + def bone_matrix_test(self, object_name: str, bone_name: str, expect: Matrix): + """Assert that the bone's world matrix is as expected.""" + actual = self.bone_matrix(object_name, bone_name) + self.assert_matrix(actual, expect, object_name) + def constraint_context(self, constraint_name: str, owner_name: str='') -> dict: - """Return a context suitable for calling constraint operators. + """Return a context suitable for calling object constraint operators. Assumes the owner is called "{constraint_name}.owner" if owner_name=''. """ @@ -84,6 +100,30 @@ class AbstractConstraintTests(unittest.TestCase): } return context + def bone_constraint_context(self, constraint_name: str, owner_name: str='', bone_name: str='') -> dict: + """Return a context suitable for calling bone constraint operators. + + Assumes the owner's object is called "{constraint_name}.owner" if owner_name=''. + Assumes the bone is called "{constraint_name}.bone" if bone_name=''. + """ + + owner_name = owner_name or f'{constraint_name}.owner' + bone_name = bone_name or f'{constraint_name}.bone' + + owner = bpy.context.scene.objects[owner_name] + pose_bone = owner.pose.bones[bone_name] + + constraint = pose_bone.constraints[constraint_name] + context = { + **bpy.context.copy(), + 'object': owner, + 'active_object': owner, + 'active_pose_bone': pose_bone, + 'constraint': constraint, + 'owner': pose_bone, + } + return context + class ChildOfTest(AbstractConstraintTests): layer_collection = 'Child Of' @@ -153,7 +193,7 @@ class ChildOfTest(AbstractConstraintTests): )) self.matrix_test('Child Of.object.owner', initial_matrix) - context = self.constraint_context('Child Of', owner_name='Child Of.object.owner') + context = self.constraint_context('Child Of', owner_name='Child Of.object.owner',) bpy.ops.constraint.childof_set_inverse(context, constraint='Child Of') self.matrix_test('Child Of.object.owner', Matrix(( (0.9992386102676392, 0.019843991845846176, -0.03359176218509674, 0.10000000149011612), @@ -188,6 +228,29 @@ class ChildOfTest(AbstractConstraintTests): bpy.ops.constraint.childof_clear_inverse(context, constraint='Child Of') self.matrix_test('Child Of.armature.owner', initial_matrix) + def test_bone_owner(self): + """Child Of: bone owns constraint, targeting object.""" + initial_matrix = Matrix(( + (0.9992387890815735, -0.03359174728393555, -0.019843988120555878, -2.999999523162842), + (-0.02588011883199215, -0.1900751143693924, -0.9814283847808838, 2.0), + (0.029196053743362427, 0.9811949133872986, -0.190799742937088, 0.9999999403953552), + (0.0, 0.0, 0.0, 1.0), + )) + self.bone_matrix_test('Child Of.bone.owner', 'Child Of.bone', initial_matrix) + + context = self.bone_constraint_context('Child Of', owner_name='Child Of.bone.owner') + bpy.ops.constraint.childof_set_inverse(context, constraint='Child Of', owner='BONE') + + self.bone_matrix_test('Child Of.bone.owner', 'Child Of.bone', Matrix(( + (0.9659260511398315, 0.2588191032409668, 4.656613428188905e-10, -2.999999761581421), + (-3.725290742551124e-09, 1.4901162970204496e-08, -1.0, 0.9999999403953552), + (-0.2588191032409668, 0.965925931930542, 0.0, 0.9999999403953552), + (0.0, 0.0, 0.0, 1.0), + ))) + + bpy.ops.constraint.childof_clear_inverse(context, constraint='Child Of', owner='BONE') + self.bone_matrix_test('Child Of.bone.owner', 'Child Of.bone', initial_matrix) + def test_vertexgroup_simple_parent(self): """Child Of: simple evaluation of vertex group parent.""" initial_matrix = Matrix(( |