diff options
439 files changed, 7410 insertions, 3089 deletions
diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000000..9c563f2dee0 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,22 @@ +# Configuration for probot-stale - https://github.com/probot/stale +# This file is used on Blender's GitHub mirror to automatically close any pull request +# and invite contributors to join the official development platform on blender.org + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 1 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 1 + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when closing a stale Issue or Pull Request. +closeComment: > + This issue has been automatically closed, because this repository is only + used as a mirror of git.blender.org. Blender development happens on + developer.blender.org. + + To get started contributing code, please read: + https://wiki.blender.org/wiki/Process/Contributing_Code diff --git a/CMakeLists.txt b/CMakeLists.txt index cddb93dd7ab..ba051b82671 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ # # The Original Code is Copyright (C) 2006, Blender Foundation # All rights reserved. +# # ***** END GPL LICENSE BLOCK ***** #----------------------------------------------------------------------------- @@ -460,14 +461,14 @@ mark_as_advanced(WITH_CXX_GUARDEDALLOC) option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_assert()" ON) mark_as_advanced(WITH_ASSERT_ABORT) -option(WITH_BOOST "Enable features depending on boost" ON) +option(WITH_BOOST "Enable features depending on boost" ON) +option(WITH_TBB "Enable features depending on TBB (OpenVDB, OpenImageDenoise, sculpt multithreading)" ON) # Unit testsing option(WITH_GTESTS "Enable GTest unit testing" OFF) option(WITH_OPENGL_RENDER_TESTS "Enable OpenGL render related unit testing (Experimental)" OFF) option(WITH_OPENGL_DRAW_TESTS "Enable OpenGL UI drawing related unit testing (Experimental)" OFF) - # Documentation if(UNIX AND NOT APPLE) option(WITH_DOC_MANPAGE "Create a manual page (Unix manpage)" OFF) @@ -584,6 +585,11 @@ if("${CMAKE_GENERATOR}" MATCHES "Ninja") mark_as_advanced(WITH_NINJA_POOL_JOBS) endif() +if(UNIX AND NOT APPLE) + option(WITH_CXX11_ABI "Use native C++11 ABI of compiler" ON) + mark_as_advanced(WITH_CXX11_ABI) +endif() + # avoid using again option_defaults_clear() @@ -1395,13 +1401,16 @@ if(CMAKE_COMPILER_IS_GNUCC) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_LOGICAL_OP -Wlogical-op) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNDEF -Wundef) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_INIT_SELF -Winit-self) # needs -Wuninitialized - ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_NULL -Wnonnull) # C only ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_TYPE_LIMITS -Wtype-limits) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_FORMAT_SIGN -Wformat-signedness) ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_RESTRICT -Wrestrict) + # C-only. + ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_NULL -Wnonnull) + ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ABSOLUTE_VALUE -Wabsolute-value) + # gcc 4.2 gives annoying warnings on every file with this if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "4.3") ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNINITIALIZED -Wuninitialized) @@ -1638,6 +1647,12 @@ if( set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") endif() +if(UNIX AND NOT APPLE) + if(NOT WITH_CXX11_ABI) + set(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -D_GLIBCXX_USE_CXX11_ABI=0") + endif() +endif() + # Include warnings first, so its possible to disable them with user defined flags # eg: -Wno-uninitialized set(CMAKE_C_FLAGS "${C_WARNINGS} ${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS}") diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index 9756ad28454..c7d8de22890 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -128,6 +128,7 @@ if(NOT WIN32 OR ENABLE_MINGW64) include(cmake/ogg.cmake) include(cmake/vorbis.cmake) include(cmake/theora.cmake) + include(cmake/opus.cmake) include(cmake/vpx.cmake) include(cmake/x264.cmake) include(cmake/xvidcore.cmake) @@ -157,4 +158,9 @@ if(UNIX) include(cmake/sqlite.cmake) endif() +if(UNIX AND NOT APPLE) + include(cmake/libglu.cmake) + include(cmake/mesa.cmake) +endif() + include(cmake/harvest.cmake) diff --git a/build_files/build_environment/cmake/check_software.cmake b/build_files/build_environment/cmake/check_software.cmake index 30dea754e20..f5774551879 100644 --- a/build_files/build_environment/cmake/check_software.cmake +++ b/build_files/build_environment/cmake/check_software.cmake @@ -17,10 +17,16 @@ # ***** END GPL LICENSE BLOCK ***** if(UNIX) + if(APPLE) + set(_libtoolize_name glibtoolize) + else() + set(_libtoolize_name libtoolize) + endif() + set(_required_software autoconf automake - libtoolize + ${_libtoolize_name} nasm yasm tclsh diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake index 27d817e8948..9ff52914f53 100644 --- a/build_files/build_environment/cmake/ffmpeg.cmake +++ b/build_files/build_environment/cmake/ffmpeg.cmake @@ -16,10 +16,10 @@ # # ***** END GPL LICENSE BLOCK ***** -set(FFMPEG_CFLAGS "-I${mingw_LIBDIR}/lame/include -I${mingw_LIBDIR}/openjpeg/include/ -I${mingw_LIBDIR}/ogg/include -I${mingw_LIBDIR}/vorbis/include -I${mingw_LIBDIR}/theora/include -I${mingw_LIBDIR}/vpx/include -I${mingw_LIBDIR}/x264/include -I${mingw_LIBDIR}/xvidcore/include -I${mingw_LIBDIR}/zlib/include") -set(FFMPEG_LDFLAGS "-L${mingw_LIBDIR}/lame/lib -L${mingw_LIBDIR}/openjpeg/lib -L${mingw_LIBDIR}/ogg/lib -L${mingw_LIBDIR}/vorbis/lib -L${mingw_LIBDIR}/theora/lib -L${mingw_LIBDIR}/vpx/lib -L${mingw_LIBDIR}/x264/lib -L${mingw_LIBDIR}/xvidcore/lib -L${mingw_LIBDIR}/zlib/lib") +set(FFMPEG_CFLAGS "-I${mingw_LIBDIR}/lame/include -I${mingw_LIBDIR}/openjpeg/include/ -I${mingw_LIBDIR}/ogg/include -I${mingw_LIBDIR}/vorbis/include -I${mingw_LIBDIR}/theora/include -I${mingw_LIBDIR}/opus/include -I${mingw_LIBDIR}/vpx/include -I${mingw_LIBDIR}/x264/include -I${mingw_LIBDIR}/xvidcore/include -I${mingw_LIBDIR}/zlib/include") +set(FFMPEG_LDFLAGS "-L${mingw_LIBDIR}/lame/lib -L${mingw_LIBDIR}/openjpeg/lib -L${mingw_LIBDIR}/ogg/lib -L${mingw_LIBDIR}/vorbis/lib -L${mingw_LIBDIR}/theora/lib -L${mingw_LIBDIR}/opus/lib -L${mingw_LIBDIR}/vpx/lib -L${mingw_LIBDIR}/x264/lib -L${mingw_LIBDIR}/xvidcore/lib -L${mingw_LIBDIR}/zlib/lib") set(FFMPEG_EXTRA_FLAGS --pkg-config-flags=--static --extra-cflags=${FFMPEG_CFLAGS} --extra-ldflags=${FFMPEG_LDFLAGS}) -set(FFMPEG_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/x264/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR}) +set(FFMPEG_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/x264/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR}:${mingw_LIBDIR}/vpx/lib/pkgconfig:${mingw_LIBDIR}/theora/lib/pkgconfig:${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/opus/lib/pkgconfig:) if(WIN32) set(FFMPEG_ENV set ${FFMPEG_ENV} &&) @@ -73,6 +73,7 @@ ExternalProject_Add(external_ffmpeg --disable-libgsm --disable-libspeex --enable-libvpx + --enable-libopus --prefix=${LIBDIR}/ffmpeg --enable-libtheora --enable-libvorbis @@ -130,6 +131,7 @@ add_dependencies( external_openjpeg external_xvidcore external_x264 + external_opus external_vpx external_theora external_vorbis diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake index 526e72e2e33..cc596b2c786 100644 --- a/build_files/build_environment/cmake/harvest.cmake +++ b/build_files/build_environment/cmake/harvest.cmake @@ -192,6 +192,7 @@ harvest(theora/lib ffmpeg/lib "*.a") harvest(tiff/include tiff/include "*.h") harvest(tiff/lib tiff/lib "*.a") harvest(vorbis/lib ffmpeg/lib "*.a") +harvest(opus/lib ffmpeg/lib "*.a") harvest(vpx/lib ffmpeg/lib "*.a") harvest(webp/lib ffmpeg/lib "*.a") harvest(x264/lib ffmpeg/lib "*.a") @@ -199,4 +200,9 @@ harvest(xvidcore/lib ffmpeg/lib "*.a") harvest(embree/include embree/include "*.h") harvest(embree/lib embree/lib "*.a") +if(UNIX AND NOT APPLE) + harvest(libglu/lib mesa/lib "*.so*") + harvest(mesa/lib mesa/lib "*.so*") +endif() + endif() diff --git a/build_files/build_environment/cmake/libglu.cmake b/build_files/build_environment/cmake/libglu.cmake new file mode 100644 index 00000000000..d1b7647eca3 --- /dev/null +++ b/build_files/build_environment/cmake/libglu.cmake @@ -0,0 +1,40 @@ +# ***** 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(LIBGLU_CFLAGS "-static-libgcc") +set(LIBGLU_CXXFLAGS "-static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a") +set(LIBGLU_LDFLAGS "-pthread -static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a") + +set(LIBGLU_EXTRA_FLAGS + CFLAGS=${LIBGLU_CFLAGS} + CXXFLAGS=${LIBGLU_CXXFLAGS} + LDFLAGS=${LIBGLU_LDFLAGS} +) + +ExternalProject_Add(external_libglu + URL ${LIBGLU_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${LIBGLU_HASH} + PREFIX ${BUILD_DIR}/libglu + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/libglu/src/external_libglu/ && + ${CONFIGURE_COMMAND_NO_TARGET} --prefix=${LIBDIR}/libglu ${LIBGLU_EXTRA_FLAGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/libglu/src/external_libglu/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/libglu/src/external_libglu/ && make install + INSTALL_DIR ${LIBDIR}/libglu +) diff --git a/build_files/build_environment/cmake/mesa.cmake b/build_files/build_environment/cmake/mesa.cmake new file mode 100644 index 00000000000..6994d1c5813 --- /dev/null +++ b/build_files/build_environment/cmake/mesa.cmake @@ -0,0 +1,54 @@ +# ***** 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(MESA_CFLAGS "-static-libgcc") +set(MESA_CXXFLAGS "-static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a") +set(MESA_LDFLAGS "-L${LIBDIR}/zlib/lib -pthread -static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a -l:libz_pic.a") + +set(MESA_EXTRA_FLAGS + CFLAGS=${MESA_CFLAGS} + CXXFLAGS=${MESA_CXXFLAGS} + LDFLAGS=${MESA_LDFLAGS} + --enable-glx=gallium-xlib + --with-gallium-drivers=swrast + --disable-dri + --disable-gbm + --disable-egl + --disable-gles1 + --disable-gles2 + --disable-llvm-shared-libs + --with-llvm-prefix=${LIBDIR}/llvm +) + +ExternalProject_Add(external_mesa + URL ${MESA_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${MESA_HASH} + PREFIX ${BUILD_DIR}/mesa + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/mesa/src/external_mesa/ && + ${CONFIGURE_COMMAND_NO_TARGET} --prefix=${LIBDIR}/mesa ${MESA_EXTRA_FLAGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/mesa/src/external_mesa/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/mesa/src/external_mesa/ && make install + INSTALL_DIR ${LIBDIR}/mesa +) + +add_dependencies( + external_mesa + ll +) diff --git a/build_files/build_environment/cmake/opus.cmake b/build_files/build_environment/cmake/opus.cmake new file mode 100644 index 00000000000..abaad94fa28 --- /dev/null +++ b/build_files/build_environment/cmake/opus.cmake @@ -0,0 +1,35 @@ +# ***** 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 ***** + +ExternalProject_Add(external_opus + URL ${OPUS_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH SHA256=${OPUS_HASH} + PREFIX ${BUILD_DIR}/opus + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/opus + --disable-shared + --enable-static + --with-pic + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && make install + INSTALL_DIR ${LIBDIR}/opus +) + +if(MSVC) + set_target_properties(external_opus PROPERTIES FOLDER Mingw) +endif() diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index c3b713096d6..1c9e5c5a4f6 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -192,6 +192,10 @@ set(VPX_VERSION 1.7.0) set(VPX_URI https://github.com/webmproject/libvpx/archive/v${VPX_VERSION}/libvpx-v${VPX_VERSION}.tar.gz) set(VPX_HASH 1fec931eb5c94279ad219a5b6e0202358e94a93a90cfb1603578c326abfc1238) +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) @@ -306,3 +310,11 @@ set(EMBREE_HASH 3d4a1147002ff43939d45140aa9d6fb8) set(OIDN_VERSION 1.0.0) set(OIDN_URI https://github.com/OpenImageDenoise/oidn/releases/download/v${OIDN_VERSION}/oidn-${OIDN_VERSION}.src.zip) set(OIDN_HASH 19fe67b0164e8f020ac8a4f520defe60) + +set(LIBGLU_VERSION 9.0.1) +set(LIBGLU_URI ftp://ftp.freedesktop.org/pub/mesa/glu/glu-${LIBGLU_VERSION}.tar.xz) +set(LIBGLU_HASH 151aef599b8259efe9acd599c96ea2a3) + +set(MESA_VERSION 18.3.1) +set(MESA_URI ftp://ftp.freedesktop.org/pub/mesa//mesa-${MESA_VERSION}.tar.xz) +set(MESA_HASH d60828056d77bfdbae0970f9b15fb1be) diff --git a/build_files/build_environment/cmake/vpx.cmake b/build_files/build_environment/cmake/vpx.cmake index 1c3a7081b59..741493859e2 100644 --- a/build_files/build_environment/cmake/vpx.cmake +++ b/build_files/build_environment/cmake/vpx.cmake @@ -49,6 +49,8 @@ ExternalProject_Add(external_vpx --disable-avx2 --disable-unit-tests --disable-examples + --enable-vp8 + --enable-vp9 ${VPX_EXTRA_FLAGS} BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make install diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index f594add3a5b..fd3ebe241a2 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -431,6 +431,9 @@ X264_VERSION_MIN=0.118 VPX_USE=false VPX_VERSION_MIN=0.9.7 VPX_DEV="" +OPUS_USE=false +OPUS_VERSION_MIN=1.1.1 +OPUS_DEV="" MP3LAME_USE=false MP3LAME_DEV="" OPENJPEG_USE=false @@ -2754,6 +2757,10 @@ compile_FFmpeg() { extra="$extra --enable-libvpx" fi + if [ "$OPUS_USE" = true ]; then + extra="$extra --enable-libopus" + fi + if [ "$MP3LAME_USE" = true ]; then extra="$extra --enable-libmp3lame" fi @@ -2991,6 +2998,14 @@ install_DEB() { install_packages_DEB $VPX_DEV VPX_USE=true fi + + PRINT "" + OPUS_DEV="libopus-dev" + check_package_version_ge_DEB $OPUS_DEV $OPUS_VERSION_MIN + if [ $? -eq 0 ]; then + install_packages_DEB $OPUS_DEV + OPUS_USE=true + fi fi # Check cmake/glew versions and disable features for older distros. @@ -3601,8 +3616,17 @@ install_RPM() { install_packages_RPM $VPX_DEV VPX_USE=true fi + PRINT "" install_packages_RPM libspnav-devel + + PRINT "" + OPUS_DEV="libopus-devel" + check_package_version_ge_RPM $OPUS_DEV $OPUS_VERSION_MIN + if [ $? -eq 0 ]; then + install_packages_RPM $OPUS_DEV + OPUS_USE=true + fi fi PRINT "" @@ -4077,6 +4101,14 @@ install_ARCH() { install_packages_ARCH $VPX_DEV VPX_USE=true fi + + PRINT "" + OPUS_DEV="opus" + check_package_version_ge_ARCH $OPUS_DEV $OPUS_VERSION_MIN + if [ $? -eq 0 ]; then + install_packages_ARCH $OPUS_DEV + OPUS_USE=true + fi fi @@ -4633,6 +4665,10 @@ print_info_ffmpeglink() { _packages="$_packages $VPX_DEV" fi + if [ "$OPUS_USE" = true ]; then + _packages="$_packages $OPUS_DEV" + fi + if [ "$MP3LAME_USE" = true ]; then _packages="$_packages $MP3LAME_DEV" fi diff --git a/build_files/buildbot/buildbot_utils.py b/build_files/buildbot/buildbot_utils.py index 6891b91aa1e..eded6646671 100644 --- a/build_files/buildbot/buildbot_utils.py +++ b/build_files/buildbot/buildbot_utils.py @@ -20,6 +20,7 @@ import argparse import os +import re import subprocess import sys @@ -27,6 +28,7 @@ class Builder: def __init__(self, name, branch): self.name = name self.branch = branch + self.is_release_branch = re.match("^blender-v(.*)-release$", branch) is not None # Buildbot runs from build/ directory self.blender_dir = os.path.abspath(os.path.join('..', 'blender.git')) diff --git a/build_files/buildbot/config/blender_linux.cmake b/build_files/buildbot/config/blender_linux.cmake index 6806684e88b..2047c28deb9 100644 --- a/build_files/buildbot/config/blender_linux.cmake +++ b/build_files/buildbot/config/blender_linux.cmake @@ -2,33 +2,20 @@ include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/config/blender_release.cmake") -# For libc-2.24 we are using chroot which runs on a 64bit system. -# There we can not use CPU bitness check since it is always 64bit. So instead -# we check for a specific libraries. -# -# Other builders we are running in a bare virtual machine, and the libraries -# are installed to /opt/. -# We assume that only 64bit builders exists in such configuration. -if(EXISTS "/lib/x86_64-linux-gnu/libc-2.24.so") - message(STATUS "Building in GLibc-2.24 environment") - set(LIBDIR_NAME "linux_x86_64") -elseif(EXISTS "/lib/i386-linux-gnu//libc-2.24.so") - message(STATUS "Building in GLibc-2.24 environment") - set(LIBDIR_NAME "linux_i686") -else() - message(STATUS "Building in generic 64bit environment") - set(LIBDIR_NAME "linux_x86_64") -endif() +message(STATUS "Building in CentOS 7 64bit environment") +set(LIBDIR_NAME "linux_centos7_x86_64") # Default to only build Blender set(WITH_BLENDER ON CACHE BOOL "" FORCE) # ######## Linux-specific build options ######## # Options which are specific to Linux-only platforms + set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE) # ######## Official release-specific build options ######## # Options which are specific to Linux release builds only + set(WITH_JACK_DYNLOAD ON CACHE BOOL "" FORCE) set(WITH_SDL_DYNLOAD ON CACHE BOOL "" FORCE) set(WITH_SYSTEM_GLEW OFF CACHE BOOL "" FORCE) @@ -40,7 +27,7 @@ set(WITH_PYTHON_INSTALL_REQUESTS ON CACHE BOOL "" FORCE) # ######## Release environment specific settings ######## -set(LIBDIR "/opt/blender-deps/${LIBDIR_NAME}" CACHE BOOL "" FORCE) +set(LIBDIR "${CMAKE_CURRENT_LIST_DIR}/../../../../lib/${LIBDIR_NAME}" CACHE STRING "" FORCE) # Platform specific configuration, to ensure static linking against everything. diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py index a7729843a0e..5bef2b81739 100644 --- a/build_files/buildbot/slave_pack.py +++ b/build_files/buildbot/slave_pack.py @@ -32,8 +32,9 @@ def get_package_name(builder, platform=None): package_name = 'blender-' + info.full_version if platform: package_name += '-' + platform - if builder.branch != 'master' and info.is_development_build: - package_name = builder.branch + "-" + package_name + if not (builder.branch == 'master' or builder.is_release_branch): + if info.is_development_build: + package_name = builder.branch + "-" + package_name return package_name @@ -47,6 +48,7 @@ def create_buildbot_upload_zip(builder, package_files): try: z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED) for filepath, filename in package_files: + print("Packaged", filename) z.write(filepath, arcname=filename) z.close() except Exception as ex: @@ -147,20 +149,6 @@ def pack_linux(builder): py_target = os.path.join(builder.install_dir, info.version) buildbot_utils.call(builder.command_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';']) - # Copy all specific files which are too specific to be copied by - # the CMake rules themselves - print("Copying extra scripts and libs...") - - extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra') - mesalibs = os.path.join(extra, 'mesalibs' + str(builder.bits) + '.tar.bz2') - software_gl = os.path.join(builder.blender_dir, 'release', 'bin', 'blender-softwaregl') - icons = os.path.join(builder.blender_dir, 'release', 'freedesktop', 'icons') - - os.system('tar -xpf %s -C %s' % (mesalibs, builder.install_dir)) - os.system('cp %s %s' % (software_gl, builder.install_dir)) - os.system('cp -r %s %s' % (icons, builder.install_dir)) - os.system('chmod 755 %s' % (os.path.join(builder.install_dir, 'blender-softwaregl'))) - # Construct package name platform_name = 'linux-' + blender_glibc + '-' + blender_arch package_name = get_package_name(builder, platform_name) diff --git a/build_files/buildbot/slave_update.py b/build_files/buildbot/slave_update.py index 39f449b87bc..36a7ae31c84 100644 --- a/build_files/buildbot/slave_update.py +++ b/build_files/buildbot/slave_update.py @@ -28,4 +28,4 @@ if __name__ == "__main__": # Run make update which handles all libraries and submodules. make_update = os.path.join(builder.blender_dir, "build_files", "utils", "make_update.py") - buildbot_utils.call([sys.executable, make_update, '--no-blender', "--use-tests"]) + buildbot_utils.call([sys.executable, make_update, '--no-blender', "--use-tests", "--use-centos-libraries"]) diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake index 1c98a6456b8..a93e829e6b0 100644 --- a/build_files/cmake/Modules/GTestTesting.cmake +++ b/build_files/cmake/Modules/GTestTesting.cmake @@ -48,6 +48,14 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST) if(WITH_OPENMP_STATIC) target_link_libraries(${TARGET_NAME} ${OpenMP_LIBRARIES}) endif() + + get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(GENERATOR_IS_MULTI_CONFIG) + string(REPLACE "\${BUILD_TYPE}" "$<CONFIG>" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) + else() + string(REPLACE "\${BUILD_TYPE}" "" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) + endif() + set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}" RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}" diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake index 403d38f6a05..4c47c4c4dba 100644 --- a/build_files/cmake/config/blender_full.cmake +++ b/build_files/cmake/config/blender_full.cmake @@ -49,6 +49,7 @@ set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE) set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE) set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE) set(WITH_SDL ON CACHE BOOL "" FORCE) +set(WITH_TBB ON CACHE BOOL "" FORCE) set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE) set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 37cbfa27972..6d0f160c764 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -54,5 +54,6 @@ set(WITH_OPENVDB OFF CACHE BOOL "" FORCE) set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE) set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE) set(WITH_SDL OFF CACHE BOOL "" FORCE) +set(WITH_TBB OFF CACHE BOOL "" FORCE) set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE) set(WITH_X11_XF86VMODE OFF CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index cb338f40a7b..cf849519c83 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -50,6 +50,7 @@ set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE) set(WITH_QUADRIFLOW ON CACHE BOOL "" FORCE) set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE) set(WITH_SDL ON CACHE BOOL "" FORCE) +set(WITH_TBB ON CACHE BOOL "" FORCE) set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE) set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index e159dd9e5ee..c3025be34ba 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -460,13 +460,16 @@ function(setup_liblinks target_link_libraries(${target} ${OSL_LIBRARIES}) endif() if(WITH_OPENVDB) - target_link_libraries(${target} ${OPENVDB_LIBRARIES} ${TBB_LIBRARIES} ${BLOSC_LIBRARIES}) + target_link_libraries(${target} ${OPENVDB_LIBRARIES} ${BLOSC_LIBRARIES}) endif() if(WITH_OPENIMAGEIO) target_link_libraries(${target} ${OPENIMAGEIO_LIBRARIES}) endif() if(WITH_OPENIMAGEDENOISE) - target_link_libraries(${target} ${OPENIMAGEDENOISE_LIBRARIES} ${TBB_LIBRARIES}) + target_link_libraries(${target} ${OPENIMAGEDENOISE_LIBRARIES}) + endif() + if(WITH_TBB) + target_link_libraries(${target} ${TBB_LIBRARIES}) endif() if(WITH_OPENCOLORIO) target_link_libraries(${target} ${OPENCOLORIO_LIBRARIES}) @@ -1209,7 +1212,9 @@ macro(openmp_delayload ) if(MSVC) if(WITH_OPENMP) - if(MSVC_VERSION EQUAL 1800) + if(MSVC_CLANG) + set(OPENMP_DLL_NAME "libomp") + elseif(MSVC_VERSION EQUAL 1800) set(OPENMP_DLL_NAME "vcomp120") else() set(OPENMP_DLL_NAME "vcomp140") diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 249546dd216..3ae3b2b66b5 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -157,7 +157,7 @@ if(WITH_CODEC_FFMPEG) avcodec avdevice avformat avutil mp3lame swscale x264 xvidcore theora theoradec theoraenc - vorbis vorbisenc vorbisfile ogg + vorbis vorbisenc vorbisfile ogg opus vpx swresample) set(FFMPEG_LIBPATH ${FFMPEG}/lib) endif() @@ -313,9 +313,7 @@ endif() if(WITH_OPENVDB) set(OPENVDB ${LIBDIR}/openvdb) set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include) - set(TBB_INCLUDE_DIRS ${LIBDIR}/tbb/include) - set(TBB_LIBRARIES ${LIBDIR}/tbb/lib/libtbb.a) - set(OPENVDB_LIBRARIES openvdb blosc ${TBB_LIBRARIES}) + set(OPENVDB_LIBRARIES openvdb blosc) set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib) set(OPENVDB_DEFINITIONS) endif() @@ -386,14 +384,25 @@ endif() if(WITH_OPENIMAGEDENOISE) find_package(OpenImageDenoise) - find_package(TBB) if(NOT OPENIMAGEDENOISE_FOUND) set(WITH_OPENIMAGEDENOISE OFF) message(STATUS "OpenImageDenoise not found") - elseif(NOT TBB_FOUND) + endif() +endif() + +if(WITH_TBB) + find_package(TBB) +endif() + +if(NOT WITH_TBB OR NOT TBB_FOUND) + if(WITH_OPENIMAGEDENOISE) + message(STATUS "TBB not found, disabling OpenImageDenoise") set(WITH_OPENIMAGEDENOISE OFF) - message(STATUS "TBB not found") + endif() + if(WITH_OPENVDB) + message(STATUS "TBB not found, disabling OpenVDB") + set(WITH_OPENVDB OFF) endif() endif() diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 1b3f9cf3fad..c48780ebd6a 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -22,14 +22,30 @@ # Detect precompiled library directory if(NOT DEFINED LIBDIR) + # Path to a locally compiled libraries. set(LIBDIR_NAME ${CMAKE_SYSTEM_NAME}_${CMAKE_SYSTEM_PROCESSOR}) string(TOLOWER ${LIBDIR_NAME} LIBDIR_NAME) - set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_NAME}) -else() - message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}") + set(LIBDIR_NATIVE_ABI ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_NAME}) + + # Path to precompiled libraries with known CentOS 7 ABI. + set(LIBDIR_CENTOS7_ABI ${CMAKE_SOURCE_DIR}/../lib/linux_centos7_x86_64) + + # Choose the best suitable libraries. + if(EXISTS ${LIBDIR_NATIVE_ABI}) + set(LIBDIR ${LIBDIR_NATIVE_ABI}) + elseif(EXISTS ${LIBDIR_CENTOS7_ABI}) + set(LIBDIR ${LIBDIR_CENTOS7_ABI}) + set(WITH_CXX11_ABI OFF) + endif() + + # Avoid namespace pollustion. + unset(LIBDIR_NATIVE_ABI) + unset(LIBDIR_CENTOS7_ABI) endif() if(EXISTS ${LIBDIR}) + message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}") + file(GLOB LIB_SUBDIRS ${LIBDIR}/*) # NOTE: Make sure "proper" compiled zlib comes first before the one # which is a part of OpenCollada. They have different ABI, and we @@ -244,13 +260,8 @@ endif() if(WITH_OPENVDB) find_package_wrapper(OpenVDB) - find_package_wrapper(TBB) find_package_wrapper(Blosc) - if(NOT TBB_FOUND) - set(WITH_OPENVDB OFF) - set(WITH_OPENVDB_BLOSC OFF) - message(STATUS "TBB not found, disabling OpenVDB") - elseif(NOT OPENVDB_FOUND) + if(NOT OPENVDB_FOUND) set(WITH_OPENVDB OFF) set(WITH_OPENVDB_BLOSC OFF) message(STATUS "OpenVDB not found, disabling it") @@ -416,6 +427,21 @@ if(WITH_OPENSUBDIV) endif() endif() +if(WITH_TBB) + find_package_wrapper(TBB) +endif() + +if(NOT WITH_TBB OR NOT TBB_FOUND) + if(WITH_OPENIMAGEDENOISE) + message(STATUS "TBB not found, disabling OpenImageDenoise") + set(WITH_OPENIMAGEDENOISE OFF) + endif() + if(WITH_OPENVDB) + message(STATUS "TBB not found, disabling OpenVDB") + set(WITH_OPENVDB OFF) + endif() +endif() + # OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed if(HAIKU) list(APPEND PLATFORM_LINKLIBS -lnetwork) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index b2277c440fe..ef7722b0aef 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -35,6 +35,22 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang") else() message("Unable to detect the Visual Studio redist directory, copying of the runtime dlls will not work, try running from the visual studio developer prompt.") endif() + # 1) CMake has issues detecting openmp support in clang-cl so we have to provide + # the right switches here. + # 2) While the /openmp switch *should* work, it currently doesn't as for clang 9.0.0 + if(WITH_OPENMP) + set(OPENMP_CUSTOM ON) + set(OPENMP_FOUND ON) + set(OpenMP_C_FLAGS "/clang:-fopenmp") + set(OpenMP_CXX_FLAGS "/clang:-fopenmp") + GET_FILENAME_COMPONENT(LLVMROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM;]" ABSOLUTE CACHE) + set(CLANG_OPENMP_DLL "${LLVMROOT}/bin/libomp.dll") + set(CLANG_OPENMP_LIB "${LLVMROOT}/lib/libomp.lib") + if(NOT EXISTS "${CLANG_OPENMP_DLL}") + message(FATAL_ERROR "Clang OpenMP library (${CLANG_OPENMP_DLL}) not found.") + endif() + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \"${CLANG_OPENMP_LIB}\"") + endif() endif() set_property(GLOBAL PROPERTY USE_FOLDERS ${WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS}) @@ -96,7 +112,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO") list(APPEND PLATFORM_LINKLIBS - ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 + ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp ) @@ -475,25 +491,20 @@ endif() if(WITH_OPENVDB) set(BLOSC_LIBRARIES optimized ${LIBDIR}/blosc/lib/libblosc.lib debug ${LIBDIR}/blosc/lib/libblosc_d.lib) - set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib) - set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include) set(OPENVDB ${LIBDIR}/openVDB) set(OPENVDB_LIBPATH ${OPENVDB}/lib) - set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include ${TBB_INCLUDE_DIR}) - set(OPENVDB_LIBRARIES optimized ${OPENVDB_LIBPATH}/openvdb.lib debug ${OPENVDB_LIBPATH}/openvdb_d.lib ${TBB_LIBRARIES} ${BLOSC_LIBRARIES}) + set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include) + set(OPENVDB_LIBRARIES optimized ${OPENVDB_LIBPATH}/openvdb.lib debug ${OPENVDB_LIBPATH}/openvdb_d.lib ${BLOSC_LIBRARIES}) set(OPENVDB_DEFINITIONS -DNOMINMAX) endif() if(WITH_OPENIMAGEDENOISE) - set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib) - set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include) set(OPENIMAGEDENOISE ${LIBDIR}/OpenImageDenoise) set(OPENIMAGEDENOISE_LIBPATH ${LIBDIR}/OpenImageDenoise/lib) - set(OPENIMAGEDENOISE_INCLUDE_DIRS ${OPENIMAGEDENOISE}/include ${TBB_INCLUDE_DIR}) + set(OPENIMAGEDENOISE_INCLUDE_DIRS ${OPENIMAGEDENOISE}/include) set(OPENIMAGEDENOISE_LIBRARIES optimized ${OPENIMAGEDENOISE_LIBPATH}/OpenImageDenoise.lib ${OPENIMAGEDENOISE_LIBPATH}/common.lib ${OPENIMAGEDENOISE_LIBPATH}/mkldnn.lib - debug ${OPENIMAGEDENOISE_LIBPATH}/OpenImageDenoise_d.lib ${OPENIMAGEDENOISE_LIBPATH}/common_d.lib ${OPENIMAGEDENOISE_LIBPATH}/mkldnn_d.lib - ${TBB_LIBRARIES}) + debug ${OPENIMAGEDENOISE_LIBPATH}/OpenImageDenoise_d.lib ${OPENIMAGEDENOISE_LIBPATH}/common_d.lib ${OPENIMAGEDENOISE_LIBPATH}/mkldnn_d.lib) set(OPENIMAGEDENOISE_DEFINITIONS) endif() @@ -558,6 +569,21 @@ if(WITH_SYSTEM_AUDASPACE) set(AUDASPACE_PY_LIBRARIES ${LIBDIR}/audaspace/lib/audaspace-py.lib) endif() +if(WITH_TBB) + set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib) + set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include) + set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR}) +else() + if(WITH_OPENIMAGEDENOISE) + message(STATUS "TBB disabled, also disabling OpenImageDenoise") + set(WITH_OPENIMAGEDENOISE OFF) + endif() + if(WITH_OPENVDB) + message(STATUS "TBB disabled, also disabling OpenVDB") + set(WITH_OPENVDB OFF) + endif() +endif() + # used in many places so include globally, like OpenGL blender_include_dirs_sys("${PTHREADS_INCLUDE_DIRS}") diff --git a/build_files/utils/make_test.py b/build_files/utils/make_test.py index a8a6afc43cc..309ab36ecdd 100755 --- a/build_files/utils/make_test.py +++ b/build_files/utils/make_test.py @@ -39,7 +39,8 @@ if make_utils.command_missing(git_command): sys.exit(1) # Test if we are building a specific release version. -release_version = make_utils.git_branch_release_version(git_command) +branch = make_utils.git_branch(git_command) +release_version = make_utils.git_branch_release_version(branch) lib_tests_dirpath = os.path.join('..', 'lib', "tests") if not os.path.exists(lib_tests_dirpath): diff --git a/build_files/utils/make_update.py b/build_files/utils/make_update.py index 3ecfa218432..ec72514fdfc 100755 --- a/build_files/utils/make_update.py +++ b/build_files/utils/make_update.py @@ -28,13 +28,17 @@ def parse_arguments(): parser.add_argument("--use-tests", action="store_true") parser.add_argument("--svn-command", default="svn") parser.add_argument("--git-command", default="git") + parser.add_argument("--use-centos-libraries", action="store_true") return parser.parse_args() +def get_blender_git_root(): + return check_output([args.git_command, "rev-parse", "--show-toplevel"]) + # Setup for precompiled libraries and tests from svn. def svn_update(args, release_version): svn_non_interactive = [args.svn_command, '--non-interactive'] - lib_dirpath = os.path.join('..', 'lib') + lib_dirpath = os.path.join(get_blender_git_root(), '..', 'lib') svn_url = make_utils.svn_libraries_base_url(release_version) # Checkout precompiled libraries @@ -45,6 +49,8 @@ def svn_update(args, release_version): # this script is bundled as part of the precompiled libraries. However it # is used by the buildbot. lib_platform = "win64_vc14" + elif args.use_centos_libraries: + lib_platform = "linux_centos7_x86_64" else: # No precompiled libraries for Linux. lib_platform = None @@ -81,10 +87,14 @@ def svn_update(args, release_version): if os.path.isdir(lib_dirpath): for dirname in os.listdir(lib_dirpath): + dirpath = os.path.join(lib_dirpath, dirname) + if dirname == ".svn": + # Cleanup must be run from svn root directory if it exists. + if not make_utils.command_missing(args.svn_command): + call(svn_non_interactive + ["cleanup", lib_dirpath]) continue - dirpath = os.path.join(lib_dirpath, dirname) svn_dirpath = os.path.join(dirpath, ".svn") svn_root_dirpath = os.path.join(lib_dirpath, ".svn") @@ -94,21 +104,23 @@ def svn_update(args, release_version): sys.stderr.write("svn not found, can't update libraries\n") sys.exit(1) - call(svn_non_interactive + ["cleanup", dirpath]) + # Cleanup to continue with interrupted downloads. + if os.path.exists(svn_dirpath): + call(svn_non_interactive + ["cleanup", dirpath]) + # Switch to appropriate branch and update. call(svn_non_interactive + ["switch", svn_url + dirname, dirpath]) call(svn_non_interactive + ["update", dirpath]) - -# Update blender repository. -def blender_update_skip(args): +# Test if git repo can be updated. +def git_update_skip(args, check_remote_exists=True): if make_utils.command_missing(args.git_command): sys.stderr.write("git not found, can't update code\n") sys.exit(1) # Abort if a rebase is still progress. - rebase_merge = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-merge']) - rebase_apply = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-apply']) - merge_head = check_output([args.git_command, 'rev-parse', '--git-path', 'MERGE_HEAD']) + rebase_merge = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-merge'], exit_on_error=False) + rebase_apply = check_output([args.git_command, 'rev-parse', '--git-path', 'rebase-apply'], exit_on_error=False) + merge_head = check_output([args.git_command, 'rev-parse', '--git-path', 'MERGE_HEAD'], exit_on_error=False) if os.path.exists(rebase_merge) or \ os.path.exists(rebase_apply) or \ os.path.exists(merge_head): @@ -120,49 +132,92 @@ def blender_update_skip(args): return "you have unstaged changes" # Test if there is an upstream branch configured - branch = check_output([args.git_command, "rev-parse", "--abbrev-ref", "HEAD"]) - remote = check_output([args.git_command, "config", "branch." + branch + ".remote"], exit_on_error=False) - if len(remote) == 0: - return "no remote branch to pull from" + if check_remote_exists: + branch = check_output([args.git_command, "rev-parse", "--abbrev-ref", "HEAD"]) + remote = check_output([args.git_command, "config", "branch." + branch + ".remote"], exit_on_error=False) + if len(remote) == 0: + return "no remote branch to pull from" - return None + return "" +# Update blender repository. def blender_update(args): print_stage("Updating Blender Git Repository") call([args.git_command, "pull", "--rebase"]) # Update submodules. -def submodules_update(args, release_version): +def submodules_update(args, release_version, branch): print_stage("Updating Submodules") if make_utils.command_missing(args.git_command): sys.stderr.write("git not found, can't update code\n") sys.exit(1) - call([args.git_command, "submodule", "update", "--init", "--recursive"]) + # Update submodules to latest master or appropriate release branch. if not release_version: - # Update submodules to latest master if not building a specific release. - # In that case submodules are set to a specific revision, which is checked - # out by running "git submodule update". - call([args.git_command, "submodule", "foreach", "git", "checkout", "master"]) - call([args.git_command, "submodule", "foreach", "git", "pull", "--rebase", "origin", "master"]) + branch = "master" + + submodules = [ + ("release/scripts/addons", branch), + ("release/scripts/addons_contrib", branch), + ("release/datafiles/locale", branch), + ("source/tools", branch), + ] + + # Initialize submodules only if needed. + for submodule_path, submodule_branch in submodules: + if not os.path.exists(os.path.join(submodule_path, ".git")): + call([args.git_command, "submodule", "update", "--init", "--recursive"]) + break + + # Checkout appropriate branch and pull changes. + skip_msg = "" + for submodule_path, submodule_branch in submodules: + cwd = os.getcwd() + try: + os.chdir(submodule_path) + msg = git_update_skip(args, check_remote_exists=False) + if msg: + skip_msg += submodule_path + " skipped: " + msg + "\n" + else: + if make_utils.git_branch(args.git_command) != submodule_branch: + call([args.git_command, "fetch", "origin"]) + call([args.git_command, "checkout", submodule_branch]) + call([args.git_command, "pull", "--rebase", "origin", submodule_branch]) + finally: + os.chdir(cwd) + + return skip_msg if __name__ == "__main__": args = parse_arguments() - blender_skipped = None + blender_skip_msg = "" + submodules_skip_msg = "" # Test if we are building a specific release version. - release_version = make_utils.git_branch_release_version(args.git_command) + branch = make_utils.git_branch(args.git_command) + release_version = make_utils.git_branch_release_version(branch) if not args.no_libraries: svn_update(args, release_version) if not args.no_blender: - blender_skipped = blender_update_skip(args) - if not blender_skipped: + blender_skip_msg = git_update_skip(args) + if blender_skip_msg: + blender_skip_msg = "Blender repository skipped: " + blender_skip_msg + "\n" + else: blender_update(args) if not args.no_submodules: - submodules_update(args, release_version) - - if blender_skipped: - print_stage("Blender repository skipped: " + blender_skipped) + submodules_skip_msg = submodules_update(args, release_version, branch) + + # Report any skipped repositories at the end, so it's not as easy to miss. + skip_msg = blender_skip_msg + submodules_skip_msg + if skip_msg: + print_stage(skip_msg.strip()) + + # For failed submodule update we throw an error, since not having correct + # submodules can make Blender throw errors. + # For Blender itself we don't and consider "make update" to be a command + # you can use while working on uncommitted code. + if submodules_skip_msg: + sys.exit(1) diff --git a/build_files/utils/make_utils.py b/build_files/utils/make_utils.py index 5fedd792149..7b21bc607a4 100755 --- a/build_files/utils/make_utils.py +++ b/build_files/utils/make_utils.py @@ -35,7 +35,7 @@ def check_output(cmd, exit_on_error=True): return output.strip() -def git_branch_release_version(git_command): +def git_branch(git_command): # Test if we are building a specific release version. try: branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"]) @@ -43,7 +43,9 @@ def git_branch_release_version(git_command): sys.stderr.write("Failed to get Blender git branch\n") sys.exit(1) - branch = branch.strip().decode('utf8') + return branch.strip().decode('utf8') + +def git_branch_release_version(branch): release_version = re.search("^blender-v(.*)-release$", branch) if release_version: release_version = release_version.group(1) diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 366d0b1b507..4380b94890a 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = Blender # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "V2.81" +PROJECT_NUMBER = "V2.82" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py index 995991c4afd..78bfd3c85b8 100755 --- a/doc/python_api/sphinx_doc_update.py +++ b/doc/python_api/sphinx_doc_update.py @@ -94,10 +94,10 @@ def main(): rsync_base = "rsync://%s@%s:%s" % (args.user, args.rsync_server, args.rsync_root) - blenver = blenver_zip = "" + blenver = api_blenver = api_blenver_zip = "" api_name = "" branch = "" - is_release = False + is_release = is_beta = False # I) Update local mirror using rsync. rsync_mirror_cmd = ("rsync", "--delete-after", "-avzz", rsync_base, args.mirror_dir) @@ -118,11 +118,14 @@ def main(): "import sys, bpy\n" "with open(sys.argv[-1], 'w') as f:\n" " is_release = bpy.app.version_cycle in {'rc', 'release'}\n" + " is_beta = bpy.app.version_cycle in {'beta'}\n" " branch = bpy.app.build_branch.split()[0].decode()\n" " 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" - " if is_release else '%s\\n' % branch)\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" ) @@ -130,8 +133,9 @@ def main(): "--python-expr", getver_script, "--", getver_file) subprocess.run(get_ver_cmd) with open(getver_file) as f: - is_release, branch, blenver, blenver_zip = f.read().split("\n") + is_release, is_beta, branch, blenver, api_blenver, api_blenver_zip = f.read().split("\n") is_release = bool(int(is_release)) + is_beta = bool(int(is_beta)) os.remove(getver_file) # IV) Build doc. @@ -143,14 +147,17 @@ def main(): os.chdir(curr_dir) # V) Cleanup existing matching dir in server mirror (if any), and copy new doc. - api_name = blenver + api_name = api_blenver api_dir = os.path.join(args.mirror_dir, api_name) if os.path.exists(api_dir): - shutil.rmtree(api_dir) + if os.path.islink(api_dir): + os.remove(api_dir) + else: + shutil.rmtree(api_dir) os.rename(os.path.join(tmp_dir, "sphinx-out"), api_dir) # VI) Create zip archive. - zip_name = "blender_python_reference_%s" % blenver_zip # We can't use 'release' postfix here... + zip_name = "blender_python_reference_%s" % api_blenver_zip # We can't use 'release' postfix here... zip_path = os.path.join(args.mirror_dir, zip_name) with zipfile.ZipFile(zip_path, 'w') as zf: for dirname, _, filenames in os.walk(api_dir): @@ -163,12 +170,27 @@ def main(): # VII) Create symlinks and html redirects. if is_release: symlink = os.path.join(args.mirror_dir, "current") - os.remove(symlink) + if os.path.exists(symlink): + if os.path.islink(symlink): + os.remove(symlink) + else: + shutil.rmtree(symlink) os.symlink("./%s" % api_name, symlink) with open(os.path.join(args.mirror_dir, "250PythonDoc/index.html"), 'w') as f: f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\"" "content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name) + elif is_beta: + # We do not have any particular symlink for that stage. + pass elif branch == "master": + # Also create a symlink from version number to actual master api doc. + symlink = os.path.join(args.mirror_dir, blenver) + if os.path.exists(symlink): + if os.path.islink(symlink): + os.remove(symlink) + else: + shutil.rmtree(symlink) + os.symlink("./%s" % api_name, symlink) with open(os.path.join(args.mirror_dir, "blender_python_api/index.html"), 'w') as f: f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\"" "content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name) diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp index c944b9ed12d..8c16c75e8e3 100644 --- a/extern/audaspace/src/devices/SoftwareDevice.cpp +++ b/extern/audaspace/src/devices/SoftwareDevice.cpp @@ -78,7 +78,7 @@ bool SoftwareDevice::SoftwareHandle::pause(bool keep) } SoftwareDevice::SoftwareHandle::SoftwareHandle(SoftwareDevice* device, std::shared_ptr<IReader> reader, std::shared_ptr<PitchReader> pitch, std::shared_ptr<ResampleReader> resampler, std::shared_ptr<ChannelMapperReader> mapper, bool keep) : - m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_old_volume(0), m_loopcount(0), + m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(0.0f), m_old_volume(0.0f), m_loopcount(0), m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()), m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0), m_flags(RENDER_CONE), m_stop(nullptr), m_stop_data(nullptr), m_status(STATUS_PLAYING), m_device(device) diff --git a/extern/cuew/src/cuew.c b/extern/cuew/src/cuew.c index 1f386c4e5d3..a0146741494 100644 --- a/extern/cuew/src/cuew.c +++ b/extern/cuew/src/cuew.c @@ -859,6 +859,23 @@ int cuewNvrtcVersion(void) { return 0; } +static size_t safe_strnlen(const char *s, size_t maxlen) { + size_t length; + for (length = 0; length < maxlen; s++, length++) { + if (*s == '\0') { + break; + } + } + return length; +} + +static char *safe_strncpy(char *dest, const char *src, size_t n) { + const size_t src_len = safe_strnlen(src, n - 1); + memcpy(dest, src, src_len); + dest[src_len] = '\0'; + return dest; +} + int cuewCompilerVersion(void) { const char *path = cuewCompilerPath(); const char *marker = "Cuda compilation tools, release "; @@ -874,7 +891,7 @@ int cuewCompilerVersion(void) { } /* get --version output */ - strncpy(command, path, sizeof(command)); + safe_strncpy(command, path, sizeof(command)); strncat(command, " --version", sizeof(command) - strlen(path)); pipe = popen(command, "r"); if (!pipe) { diff --git a/extern/quadriflow/CMakeLists.txt b/extern/quadriflow/CMakeLists.txt index 3891079073e..2e13bf17b17 100644 --- a/extern/quadriflow/CMakeLists.txt +++ b/extern/quadriflow/CMakeLists.txt @@ -23,6 +23,9 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") add_c_flag( "-Wno-unused-result" ) + remove_cc_flag( + "-Wmissing-declarations" + ) endif() set(CMAKE_CXX_STANDARD 14) diff --git a/extern/quadriflow/patches/blender.patch b/extern/quadriflow/patches/blender.patch index d131abc52e2..55fdd123e3b 100644 --- a/extern/quadriflow/patches/blender.patch +++ b/extern/quadriflow/patches/blender.patch @@ -1,3 +1,19 @@ +diff --git a/extern/quadriflow/src/config.hpp b/extern/quadriflow/src/config.hpp +index 842b885..bf597ad 100644 +--- a/extern/quadriflow/src/config.hpp ++++ b/extern/quadriflow/src/config.hpp +@@ -1,6 +1,11 @@ + #ifndef CONFIG_H_ + #define CONFIG_H_ + ++/* Workaround a bug in boost 1.68, until we upgrade to a newer version. */ ++#if defined(__clang__) && defined(WIN32) ++ #include <boost/type_traits/is_assignable.hpp> ++ using namespace boost; ++#endif + // Move settings to cmake to make CMake happy :) + + // #define WITH_SCALE diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc b/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc index 35a73d9..0eeba8a 100644 --- a/extern/quadriflow/3rd/lemon-1.3.1/lemon/arg_parser.cc diff --git a/extern/quadriflow/src/config.hpp b/extern/quadriflow/src/config.hpp index 842b885a209..bf597ad0f39 100644 --- a/extern/quadriflow/src/config.hpp +++ b/extern/quadriflow/src/config.hpp @@ -1,6 +1,11 @@ #ifndef CONFIG_H_ #define CONFIG_H_ +/* Workaround a bug in boost 1.68, until we upgrade to a newer version. */ +#if defined(__clang__) && defined(WIN32) + #include <boost/type_traits/is_assignable.hpp> + using namespace boost; +#endif // Move settings to cmake to make CMake happy :) // #define WITH_SCALE diff --git a/intern/clog/clog.c b/intern/clog/clog.c index da94acd97b1..9074e0f85e1 100644 --- a/intern/clog/clog.c +++ b/intern/clog/clog.c @@ -174,6 +174,7 @@ static void clg_str_append(CLogStringBuf *cstr, const char *str) clg_str_append_with_len(cstr, str, strlen(str)); } +ATTR_PRINTF_FORMAT(2, 0) static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args) { /* Use limit because windows may use '-1' for a formatting error. */ diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 59509d20fb2..5520cfd5ecf 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -541,7 +541,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights; BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); - const bool has_local_view = b_v3d && b_v3d.local_view(); BL::Depsgraph::object_instances_iterator b_instance_iter; for (b_depsgraph.object_instances.begin(b_instance_iter); @@ -555,10 +554,10 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, /* test if object needs to be hidden */ const bool show_self = b_instance.show_self(); - const bool show_local_view = !has_local_view || b_ob.local_view_get(b_v3d); const bool show_particles = b_instance.show_particles(); + const bool show_in_viewport = !b_v3d || b_ob.visible_in_viewport_get(b_v3d); - if (show_local_view && (show_self || show_particles)) { + if (show_in_viewport && (show_self || show_particles)) { /* object itself */ sync_object(b_depsgraph, b_view_layer, diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 362155f22ac..22dbc3fba79 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -1340,6 +1340,14 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, graph->connect(background->output("Background"), out->input("Surface")); } else if (!new_viewport_parameters.use_scene_world) { + float3 world_color; + if (b_world) { + world_color = get_float3(b_world.color()); + } + else { + world_color = make_float3(0.0f, 0.0f, 0.0f); + } + BackgroundNode *background = new BackgroundNode(); graph->add(background); @@ -1347,7 +1355,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, graph->add(light_path); MixNode *mix_scene_with_background = new MixNode(); - mix_scene_with_background->color2 = get_float3(b_world.color()); + mix_scene_with_background->color2 = world_color; graph->add(mix_scene_with_background); EnvironmentTextureNode *texture_environment = new EnvironmentTextureNode(); @@ -1369,7 +1377,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, MixNode *mix_background_with_environment = new MixNode(); mix_background_with_environment->fac = new_viewport_parameters.studiolight_background_alpha; - mix_background_with_environment->color1 = get_float3(b_world.color()); + mix_background_with_environment->color1 = world_color; graph->add(mix_background_with_environment); ShaderNode *out = graph->output(); diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 00dd37f089c..b5e10b0c2cb 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -454,6 +454,12 @@ class CUDADevice : public Device { VLOG(1) << "Using precompiled kernel."; return cubin; } + const string ptx = path_get(string_printf("lib/%s_compute_%d%d.ptx", name, major, minor)); + VLOG(1) << "Testing for pre-compiled kernel " << ptx << "."; + if (path_exists(ptx)) { + VLOG(1) << "Using precompiled kernel."; + return ptx; + } } const string common_cflags = compile_kernel_get_common_cflags( diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index b745235aed5..6f4734059da 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -169,6 +169,7 @@ class OptiXDevice : public Device { OptixModule optix_module = NULL; OptixPipeline pipelines[NUM_PIPELINES] = {}; + bool motion_blur = false; bool need_texture_info = false; device_vector<SbtRecord> sbt_data; device_vector<TextureInfo> texture_info; @@ -337,7 +338,12 @@ class OptiXDevice : public Device { # endif pipeline_options.pipelineLaunchParamsVariableName = "__params"; // See kernel_globals.h - if (requested_features.use_object_motion) { + // Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds + // This is necessary since objects may be reported to have motion if the Vector pass is + // active, but may still need to be rendered without motion blur if that isn't active as well + motion_blur = requested_features.use_object_motion; + + if (motion_blur) { pipeline_options.usesMotionBlur = true; // Motion blur can insert motion transforms into the traversal graph // It is no longer a two-level graph then, so need to set flags to allow any configuration @@ -872,7 +878,7 @@ class OptiXDevice : public Device { size_t num_motion_steps = 1; Attribute *motion_keys = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if (mesh->use_motion_blur && motion_keys) { + if (motion_blur && mesh->use_motion_blur && motion_keys) { num_motion_steps = mesh->motion_steps; } @@ -942,7 +948,7 @@ class OptiXDevice : public Device { size_t num_motion_steps = 1; Attribute *motion_keys = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if (mesh->use_motion_blur && motion_keys) { + if (motion_blur && mesh->use_motion_blur && motion_keys) { num_motion_steps = mesh->motion_steps; } @@ -1041,7 +1047,7 @@ class OptiXDevice : public Device { instance.visibilityMask = (ob->mesh->has_volume ? 3 : 1); // Insert motion traversable if object has motion - if (ob->use_motion()) { + if (motion_blur && ob->use_motion()) { blas.emplace_back(this, "motion_transform"); device_only_memory<uint8_t> &motion_transform_gpu = blas.back(); motion_transform_gpu.alloc_to_device(sizeof(OptixSRTMotionTransform) + diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index ea8aa197b6f..78da584e132 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -389,11 +389,20 @@ if(WITH_CYCLES_CUDA_BINARIES) set(cuda_cubins) macro(CYCLES_CUDA_KERNEL_ADD arch prev_arch name flags sources experimental) - set(cuda_cubin ${name}_${arch}.cubin) + if(${arch} MATCHES "compute_.*") + set(format "ptx") + else() + set(format "cubin") + endif() + set(cuda_file ${name}_${arch}.${format}) set(kernel_sources ${sources}) if(NOT ${prev_arch} STREQUAL "none") - set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.cubin) + if(${prev_arch} MATCHES "compute_.*") + set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.ptx) + else() + set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.cubin) + endif() endif() set(cuda_kernel_src "/kernels/cuda/${name}.cu") @@ -406,7 +415,7 @@ if(WITH_CYCLES_CUDA_BINARIES) -I ${CMAKE_CURRENT_SOURCE_DIR}/.. -I ${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda --use_fast_math - -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin}) + -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_file}) if(${experimental}) set(cuda_flags ${cuda_flags} -D __KERNEL_EXPERIMENTAL__) @@ -440,20 +449,21 @@ if(WITH_CYCLES_CUDA_BINARIES) -v -cuda-toolkit-dir "${CUDA_TOOLKIT_ROOT_DIR}" DEPENDS ${kernel_sources} cycles_cubin_cc) + set(cuda_file ${cuda_cubin}) else() add_custom_command( - OUTPUT ${cuda_cubin} + OUTPUT ${cuda_file} COMMAND ${CUDA_NVCC_EXECUTABLE} -arch=${arch} ${CUDA_NVCC_FLAGS} - --cubin + --${format} ${CMAKE_CURRENT_SOURCE_DIR}${cuda_kernel_src} --ptxas-options="-v" ${cuda_flags} DEPENDS ${kernel_sources}) endif() - delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cuda_cubin}" ${CYCLES_INSTALL_PATH}/lib) - list(APPEND cuda_cubins ${cuda_cubin}) + delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cuda_file}" ${CYCLES_INSTALL_PATH}/lib) + list(APPEND cuda_cubins ${cuda_file}) unset(cuda_debug_flags) endmacro() diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index d45ffe9c7df..55abe39c465 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -459,7 +459,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, throughput /= probability; } +# ifdef __DENOISING_FEATURES__ kernel_update_denoising_features(kg, sd, state, L); +# endif # ifdef __AO__ /* ambient occlusion */ diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl index 8caea6803ed..9fbd3391ade 100644 --- a/intern/cycles/kernel/shaders/node_mix.osl +++ b/intern/cycles/kernel/shaders/node_mix.osl @@ -91,12 +91,12 @@ color node_mix_diff(float t, color col1, color col2) color node_mix_dark(float t, color col1, color col2) { - return min(col1, col2) * t + col1 * (1.0 - t); + return mix(col1, min(col1, col2), t); } color node_mix_light(float t, color col1, color col2) { - return max(col1, col2 * t); + return mix(col1, max(col1, col2), t); } color node_mix_dodge(float t, color col1, color col2) diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h index 0f571eb7253..1a0fa03305e 100644 --- a/intern/cycles/kernel/svm/svm_color_util.h +++ b/intern/cycles/kernel/svm/svm_color_util.h @@ -92,12 +92,12 @@ ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2) ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2) { - return min(col1, col2) * t + col1 * (1.0f - t); + return interp(col1, min(col1, col2), t); } ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2) { - return max(col1, col2 * t); + return interp(col1, max(col1, col2), t); } ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2) diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 71f1863ea49..b58e10a7b52 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -5567,11 +5567,21 @@ void MapRangeNode::expand(ShaderGraph *graph) ShaderOutput *result_out = output("Result"); if (!result_out->links.empty()) { ClampNode *clamp_node = new ClampNode(); - clamp_node->min = to_min; - clamp_node->max = to_max; graph->add(clamp_node); graph->relink(result_out, clamp_node->output("Result")); graph->connect(result_out, clamp_node->input("Value")); + if (input("To Min")->link) { + graph->connect(input("To Min")->link, clamp_node->input("Min")); + } + else { + clamp_node->min = to_min; + } + if (input("To Max")->link) { + graph->connect(input("To Max")->link, clamp_node->input("Max")); + } + else { + clamp_node->max = to_max; + } } } } diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h index 2778cffba3a..b29d4163133 100644 --- a/intern/cycles/util/util_defines.h +++ b/intern/cycles/util/util_defines.h @@ -16,127 +16,127 @@ */ #ifndef __UTIL_DEFINES_H__ -# define __UTIL_DEFINES_H__ +#define __UTIL_DEFINES_H__ /* Bitness */ -# if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || \ - defined(_M_X64) -# define __KERNEL_64_BIT__ -# endif +#if defined(__ppc64__) || defined(__PPC64__) || defined(__x86_64__) || defined(__ia64__) || \ + defined(_M_X64) +# define __KERNEL_64_BIT__ +#endif /* Qualifiers for kernel code shared by CPU and GPU */ -# ifndef __KERNEL_GPU__ -# define ccl_device static inline -# define ccl_device_noinline static -# define ccl_device_noinline_cpu ccl_device_noinline -# define ccl_global -# define ccl_static_constant static const -# define ccl_constant const -# define ccl_local -# define ccl_local_param -# define ccl_private -# define ccl_restrict __restrict -# define ccl_ref & -# define ccl_optional_struct_init -# define __KERNEL_WITH_SSE_ALIGN__ - -# if defined(_WIN32) && !defined(FREE_WINDOWS) -# define ccl_device_inline static __forceinline -# define ccl_device_forceinline static __forceinline -# define ccl_align(...) __declspec(align(__VA_ARGS__)) -# ifdef __KERNEL_64_BIT__ -# define ccl_try_align(...) __declspec(align(__VA_ARGS__)) -# else /* __KERNEL_64_BIT__ */ -# undef __KERNEL_WITH_SSE_ALIGN__ +#ifndef __KERNEL_GPU__ +# define ccl_device static inline +# define ccl_device_noinline static +# define ccl_device_noinline_cpu ccl_device_noinline +# define ccl_global +# define ccl_static_constant static const +# define ccl_constant const +# define ccl_local +# define ccl_local_param +# define ccl_private +# define ccl_restrict __restrict +# define ccl_ref & +# define ccl_optional_struct_init +# define __KERNEL_WITH_SSE_ALIGN__ + +# if defined(_WIN32) && !defined(FREE_WINDOWS) +# define ccl_device_inline static __forceinline +# define ccl_device_forceinline static __forceinline +# define ccl_align(...) __declspec(align(__VA_ARGS__)) +# ifdef __KERNEL_64_BIT__ +# define ccl_try_align(...) __declspec(align(__VA_ARGS__)) +# else /* __KERNEL_64_BIT__ */ +# undef __KERNEL_WITH_SSE_ALIGN__ /* No support for function arguments (error C2719). */ -# define ccl_try_align(...) -# endif /* __KERNEL_64_BIT__ */ -# define ccl_may_alias -# define ccl_always_inline __forceinline -# define ccl_never_inline __declspec(noinline) -# define ccl_maybe_unused -# else /* _WIN32 && !FREE_WINDOWS */ -# define ccl_device_inline static inline __attribute__((always_inline)) -# define ccl_device_forceinline static inline __attribute__((always_inline)) -# define ccl_align(...) __attribute__((aligned(__VA_ARGS__))) -# ifndef FREE_WINDOWS64 -# define __forceinline inline __attribute__((always_inline)) -# endif -# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__))) -# define ccl_may_alias __attribute__((__may_alias__)) -# define ccl_always_inline __attribute__((always_inline)) -# define ccl_never_inline __attribute__((noinline)) -# define ccl_maybe_unused __attribute__((used)) -# endif /* _WIN32 && !FREE_WINDOWS */ +# define ccl_try_align(...) +# endif /* __KERNEL_64_BIT__ */ +# define ccl_may_alias +# define ccl_always_inline __forceinline +# define ccl_never_inline __declspec(noinline) +# define ccl_maybe_unused +# else /* _WIN32 && !FREE_WINDOWS */ +# define ccl_device_inline static inline __attribute__((always_inline)) +# define ccl_device_forceinline static inline __attribute__((always_inline)) +# define ccl_align(...) __attribute__((aligned(__VA_ARGS__))) +# ifndef FREE_WINDOWS64 +# define __forceinline inline __attribute__((always_inline)) +# endif +# define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__))) +# define ccl_may_alias __attribute__((__may_alias__)) +# define ccl_always_inline __attribute__((always_inline)) +# define ccl_never_inline __attribute__((noinline)) +# define ccl_maybe_unused __attribute__((used)) +# endif /* _WIN32 && !FREE_WINDOWS */ /* Use to suppress '-Wimplicit-fallthrough' (in place of 'break'). */ -# ifndef ATTR_FALLTHROUGH -# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */ -# define ATTR_FALLTHROUGH __attribute__((fallthrough)) -# else -# define ATTR_FALLTHROUGH ((void)0) -# endif +# ifndef ATTR_FALLTHROUGH +# if defined(__GNUC__) && (__GNUC__ >= 7) /* gcc7.0+ only */ +# define ATTR_FALLTHROUGH __attribute__((fallthrough)) +# else +# define ATTR_FALLTHROUGH ((void)0) # endif -# endif /* __KERNEL_GPU__ */ +# endif +#endif /* __KERNEL_GPU__ */ /* macros */ /* hints for branch prediction, only use in code that runs a _lot_ */ -# if defined(__GNUC__) && defined(__KERNEL_CPU__) -# define LIKELY(x) __builtin_expect(!!(x), 1) -# define UNLIKELY(x) __builtin_expect(!!(x), 0) -# else -# define LIKELY(x) (x) -# define UNLIKELY(x) (x) -# endif - -# if defined(__GNUC__) || defined(__clang__) -# if defined(__cplusplus) +#if defined(__GNUC__) && defined(__KERNEL_CPU__) +# define LIKELY(x) __builtin_expect(!!(x), 1) +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +# define LIKELY(x) (x) +# define UNLIKELY(x) (x) +#endif + +#if defined(__GNUC__) || defined(__clang__) +# if defined(__cplusplus) /* Some magic to be sure we don't have reference in the type. */ template<typename T> static inline T decltype_helper(T x) { return x; } -# define TYPEOF(x) decltype(decltype_helper(x)) -# else -# define TYPEOF(x) typeof(x) -# endif +# define TYPEOF(x) decltype(decltype_helper(x)) +# else +# define TYPEOF(x) typeof(x) # endif +#endif /* Causes warning: * incompatible types when assigning to type 'Foo' from type 'Bar' * ... the compiler optimizes away the temp var */ -# ifdef __GNUC__ -# define CHECK_TYPE(var, type) \ - { \ - TYPEOF(var) * __tmp; \ - __tmp = (type *)NULL; \ - (void)__tmp; \ - } \ - (void)0 - -# define CHECK_TYPE_PAIR(var_a, var_b) \ - { \ - TYPEOF(var_a) * __tmp; \ - __tmp = (typeof(var_b) *)NULL; \ - (void)__tmp; \ - } \ - (void)0 -# else -# define CHECK_TYPE(var, type) -# define CHECK_TYPE_PAIR(var_a, var_b) -# endif +#ifdef __GNUC__ +# define CHECK_TYPE(var, type) \ + { \ + TYPEOF(var) * __tmp; \ + __tmp = (type *)NULL; \ + (void)__tmp; \ + } \ + (void)0 + +# define CHECK_TYPE_PAIR(var_a, var_b) \ + { \ + TYPEOF(var_a) * __tmp; \ + __tmp = (typeof(var_b) *)NULL; \ + (void)__tmp; \ + } \ + (void)0 +#else +# define CHECK_TYPE(var, type) +# define CHECK_TYPE_PAIR(var_a, var_b) +#endif /* can be used in simple macros */ -# define CHECK_TYPE_INLINE(val, type) ((void)(((type)0) != (val))) - -# ifndef __KERNEL_GPU__ -# include <cassert> -# define util_assert(statement) assert(statement) -# else -# define util_assert(statement) -# endif +#define CHECK_TYPE_INLINE(val, type) ((void)(((type)0) != (val))) + +#ifndef __KERNEL_GPU__ +# include <cassert> +# define util_assert(statement) assert(statement) +#else +# define util_assert(statement) +#endif #endif /* __UTIL_DEFINES_H__ */ diff --git a/intern/cycles/util/util_static_assert.h b/intern/cycles/util/util_static_assert.h index b4b972a4036..ceb52830319 100644 --- a/intern/cycles/util/util_static_assert.h +++ b/intern/cycles/util/util_static_assert.h @@ -15,18 +15,18 @@ */ #ifndef __UTIL_STATIC_ASSERT_H__ -# define __UTIL_STATIC_ASSERT_H__ +#define __UTIL_STATIC_ASSERT_H__ CCL_NAMESPACE_BEGIN /* TODO(sergey): In theory CUDA might work with own static assert * implementation since it's just pure C++. */ -# ifdef __KERNEL_GPU__ -# ifndef static_assert -# define static_assert(statement, message) -# endif -# endif /* __KERNEL_GPU__ */ +#ifdef __KERNEL_GPU__ +# ifndef static_assert +# define static_assert(statement, message) +# endif +#endif /* __KERNEL_GPU__ */ /* TODO(sergey): For until C++11 is a bare minimum for us, * we do a bit of a trickery to show meaningful message so @@ -42,8 +42,8 @@ CCL_NAMESPACE_BEGIN * After C++11 bump it should be possible to glue structure * name to the error message, */ -# define static_assert_align(st, align) \ - static_assert((sizeof(st) % (align) == 0), "Structure must be strictly aligned") // NOLINT +#define static_assert_align(st, align) \ + static_assert((sizeof(st) % (align) == 0), "Structure must be strictly aligned") // NOLINT CCL_NAMESPACE_END diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 20bb144a924..720929ce945 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -66,6 +66,25 @@ extern GHOST_SystemHandle GHOST_CreateSystem(void); extern GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle); /** + * Show a system message box to the user + * \param systemhandle The handle to the system + * \param title Title of the message box + * \param message Message of the message box + * \param help_label Text to show on the help button that opens a link + * \param continue_label Text to show on the ok button that continues + * \param link Optional (hyper)link to a webpage to show when pressing help + * \param dialog_options Options to configure the message box. + * \return void. + */ +extern void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle, + const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options); + +/** * Creates an event consumer object * \param eventCallback The event callback routine. * \param userdata Pointer to user data returned to the callback routine. @@ -176,10 +195,22 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, GHOST_TDrawingContextType type, GHOST_GLSettings glSettings); +extern GHOST_WindowHandle GHOST_CreateDialogWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle parent_windowhandle, + const char *title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + GHOST_GLSettings glSettings); + /** * Create a new offscreen context. * Never explicitly delete the context, use disposeContext() instead. * \param systemhandle The handle to the system + * \param platform_support_callback An optional callback to check platform support * \return A handle to the new context ( == NULL if creation failed). */ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle); @@ -207,6 +238,8 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl */ extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata); +extern int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle); + /** * Dispose a window. * \param systemhandle The handle to the system diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 27be80a2f20..b781de266bc 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -235,7 +235,8 @@ class GHOST_ISystem { * \param state: The state of the window when opened. * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. - * \param exclusive: Use to show the window on top and ignore others (used fullscreen). + * \param exclusive: Use to show the window on top and ignore others (used full-screen). + * \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized. * \param parentWindow: Parent (embedder) window * \return The new window (or 0 if creation failed). */ @@ -248,7 +249,8 @@ class GHOST_ISystem { GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, - const GHOST_TEmbedderWindowID parentWindow = 0) = 0; + const bool is_dialog = false, + const GHOST_IWindow *parentWindow = NULL) = 0; /** * Dispose a window. @@ -435,6 +437,27 @@ class GHOST_ISystem { */ virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0; + /*************************************************************************************** + * System Message Box. + ***************************************************************************************/ + + /** + * Show a system message box + * + * \param title The title of the message box + * \param message The message to display + * \param help_label Help button label + * \param continue_label Continue button label + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + virtual GHOST_TSuccess showMessageBox(const char * /*title*/, + const char * /*message*/, + const char * /*help_label*/, + const char * /*continue_label*/, + const char * /*link*/, + GHOST_DialogOptions /*dialog_options*/) const = 0; + protected: /** * Initialize the system. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 03a0db9abbe..c19d4bdf6bd 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -241,6 +241,8 @@ class GHOST_IWindow { */ virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; + virtual bool isDialog() const = 0; + /** * Returns the tablet data (pressure etc). * \return The tablet data (pressure etc). diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 891f9d982b9..32472373b17 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -58,6 +58,11 @@ typedef enum { GHOST_glAlphaBackground = (1 << 2), } GHOST_GLFlags; +typedef enum GHOST_DialogOptions { + GHOST_DialogWarning = (1 << 0), + GHOST_DialogError = (1 << 1), +} GHOST_DialogOptions; + #ifdef _MSC_VER typedef __int64 GHOST_TInt64; typedef unsigned __int64 GHOST_TUns64; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index a1a209af77a..eeb23ea7471 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -47,6 +47,18 @@ GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle) return system->disposeSystem(); } +void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle, + const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options) +{ + GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; + system->showMessageBox(title, message, help_label, continue_label, link, dialog_options); +} + GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata) { @@ -140,7 +152,33 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; return (GHOST_WindowHandle)system->createWindow( - title, left, top, width, height, state, type, glSettings, false); + title, left, top, width, height, state, type, glSettings, false, false); +} + +GHOST_WindowHandle GHOST_CreateDialogWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle parent_windowhandle, + const char *title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + GHOST_GLSettings glSettings) +{ + GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; + + return (GHOST_WindowHandle)system->createWindow(title, + left, + top, + width, + height, + state, + type, + glSettings, + false, + true, + (GHOST_IWindow *)parent_windowhandle); } GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle) @@ -156,6 +194,13 @@ void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr window->setUserData(userdata); } +int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; + + return (int)window->isDialog(); +} + GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle) { @@ -618,8 +663,13 @@ GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandl GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle) { GHOST_IContext *context = (GHOST_IContext *)contexthandle; - - return context->activateDrawingContext(); + if (context) { + return context->activateDrawingContext(); + } + else { + GHOST_PRINT("GHOST_ActivateOpenGLContext: Context not valid"); + return GHOST_kFailure; + } } GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle) diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index fbf8af01e59..893592e3cf5 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -105,14 +105,6 @@ class GHOST_System : public GHOST_ISystem { ***************************************************************************************/ /** - * Inherited from GHOST_ISystem but left pure virtual - * - * virtual GHOST_TUns8 getNumDisplays() const = 0; - * virtual void getMainDisplayDimensions(...) const = 0; - * virtual GHOST_IWindow* createWindow(..) - */ - - /** * Dispose a window. * \param window Pointer to the window to be disposed. * \return Indication of success. @@ -317,6 +309,25 @@ class GHOST_System : public GHOST_ISystem { */ virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const = 0; + /** + * Show a system message box + * \param title The title of the message box + * \param message The message to display + * \param help_label Help button label + * \param continue_label Continue button label + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + virtual GHOST_TSuccess showMessageBox(const char * /*title*/, + const char * /*message*/, + const char * /*help_label */, + const char * /*continue_label */, + const char * /*link*/, + GHOST_DialogOptions /*dialog_options*/) const + { + return GHOST_kFailure; + }; + protected: /** * Initialize the system. diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 109dd6c180d..1e44c3e31d4 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -109,7 +109,8 @@ class GHOST_SystemCocoa : public GHOST_System { GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, - const GHOST_TEmbedderWindowID parentWindow = 0); + const bool is_dialog = false, + const GHOST_IWindow *parentWindow = NULL); /** * Create a new offscreen context. @@ -232,6 +233,11 @@ class GHOST_SystemCocoa : public GHOST_System { GHOST_TSuccess handleApplicationBecomeActiveEvent(); /** + * \return True if any dialog window is open. + */ + bool hasDialogWindow(); + + /** * External objects should call this when they send an event outside processEvents. */ void notifyExternalEventProcessed(); diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 2026c1b7b4f..68bac7d153b 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -707,7 +707,8 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title, GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, - const GHOST_TEmbedderWindowID parentWindow) + const bool is_dialog, + const GHOST_IWindow *parentWindow) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; GHOST_IWindow *window = NULL; @@ -735,7 +736,9 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title, state, type, glSettings.flags & GHOST_glStereoVisual, - glSettings.flags & GHOST_glDebugContext); + glSettings.flags & GHOST_glDebugContext, + is_dialog, + (GHOST_WindowCocoa *)parentWindow); if (window->getValid()) { // Store the pointer to the window @@ -972,6 +975,13 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) // Note: called from NSApplication delegate GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent() { + for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) { + GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow; + if (window->isDialog()) { + [window->getCocoaWindow() makeKeyAndOrderFront:nil]; + } + } + // Update the modifiers key mask, as its status may have changed when the application // was not active (that is when update events are sent to another application). unsigned int modifiers; @@ -1021,6 +1031,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent() return GHOST_kSuccess; } +bool GHOST_SystemCocoa::hasDialogWindow() +{ + for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) { + GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow; + if (window->isDialog()) { + return true; + } + } + return false; +} + void GHOST_SystemCocoa::notifyExternalEventProcessed() { m_outsideLoopEventProcessed = true; diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h index 93aea87e9a6..10138bfc6eb 100644 --- a/intern/ghost/intern/GHOST_SystemNULL.h +++ b/intern/ghost/intern/GHOST_SystemNULL.h @@ -114,8 +114,9 @@ class GHOST_SystemNULL : public GHOST_System { GHOST_TWindowState state, GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, - bool exclusive, - const GHOST_TEmbedderWindowID parentWindow) + const bool exclusive, + const bool is_dialog, + const GHOST_IWindow *parentWindow) { return new GHOST_WindowNULL(this, title, diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index 520c62719f8..e3f6f4b6bb1 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -58,6 +58,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const STR_String &title, GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, + const bool /* is_dialog */, const GHOST_TEmbedderWindowID parentWindow) { GHOST_WindowSDL *window = NULL; diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h index 7dbdc3ccec8..942b6297c22 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.h +++ b/intern/ghost/intern/GHOST_SystemSDL.h @@ -89,6 +89,7 @@ class GHOST_SystemSDL : public GHOST_System { GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, + const bool is_dialog = false, const GHOST_TEmbedderWindowID parentWindow = 0); /* SDL specific */ diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 9073ed9944b..c86accf4ede 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -28,12 +28,21 @@ # define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */ #endif +/* clang-format off */ +#pragma comment(linker,"\"/manifestdependency:type='win32' \ +name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ +processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +/* clang-format on */ + +#include <commctrl.h> #include <shlobj.h> #include <tlhelp32.h> #include <psapi.h> +#include <shellapi.h> #include <windowsx.h> #include "utfconv.h" +#include "utf_winfunc.h" #include "GHOST_DisplayManagerWin32.h" #include "GHOST_EventButton.h" @@ -266,7 +275,8 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const STR_String &title, GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, - const GHOST_TEmbedderWindowID parentWindow) + const bool is_dialog, + const GHOST_IWindow *parentWindow) { GHOST_WindowWin32 *window = new GHOST_WindowWin32( this, @@ -279,8 +289,9 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const STR_String &title, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), ((glSettings.flags & GHOST_glAlphaBackground) != 0), - parentWindow, - ((glSettings.flags & GHOST_glDebugContext) != 0)); + (GHOST_WindowWin32 *)parentWindow, + ((glSettings.flags & GHOST_glDebugContext) != 0), + is_dialog); if (window->getValid()) { // Store the pointer to the window @@ -356,14 +367,8 @@ GHOST_IContext *GHOST_SystemWin32::createOffscreenContext() goto finished; } else { - MessageBox(NULL, - "A graphics card and driver with support for OpenGL 3.3 or higher is required.\n" - "Installing the latest driver for your graphics card may resolve the issue.\n\n" - "The program will now close.", - "Blender - Unsupported Graphics Card or Driver", - MB_OK | MB_ICONERROR); delete context; - exit(); + return NULL; } #elif defined(WITH_GL_PROFILE_COMPAT) @@ -514,6 +519,7 @@ GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons &buttons) const GHOST_TSuccess GHOST_SystemWin32::init() { GHOST_TSuccess success = GHOST_System::init(); + InitCommonControls(); /* Disable scaling on high DPI displays on Vista */ HMODULE @@ -1774,6 +1780,57 @@ void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const } } +/** \name Message Box + * \{ */ +GHOST_TSuccess GHOST_SystemWin32::showMessageBox(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options) const +{ + const wchar_t *title_16 = alloc_utf16_from_8(title, 0); + const wchar_t *message_16 = alloc_utf16_from_8(message, 0); + const wchar_t *help_label_16 = alloc_utf16_from_8(help_label, 0); + const wchar_t *continue_label_16 = alloc_utf16_from_8(continue_label, 0); + + int nButtonPressed = 0; + TASKDIALOGCONFIG config = {0}; + const TASKDIALOG_BUTTON buttons[] = {{IDOK, help_label_16}, {IDCONTINUE, continue_label_16}}; + + config.cbSize = sizeof(config); + config.hInstance = 0; + config.dwCommonButtons = 0; + config.pszMainIcon = (dialog_options & GHOST_DialogError ? + TD_ERROR_ICON : + dialog_options & GHOST_DialogWarning ? TD_WARNING_ICON : + TD_INFORMATION_ICON); + config.pszWindowTitle = L"Blender"; + config.pszMainInstruction = title_16; + config.pszContent = message_16; + config.pButtons = (link) ? buttons : buttons + 1; + config.cButtons = (link) ? 2 : 1; + + TaskDialogIndirect(&config, &nButtonPressed, NULL, NULL); + switch (nButtonPressed) { + case IDOK: + ShellExecute(NULL, "open", link, NULL, NULL, SW_SHOWNORMAL); + break; + case IDCONTINUE: + break; + default: + break; // should never happen + } + + free((void *)title_16); + free((void *)message_16); + free((void *)help_label_16); + free((void *)continue_label_16); + + return GHOST_kSuccess; +} +/* \} */ + static DWORD GetParentProcessID(void) { HANDLE snapshot; diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 7ac6a3e3e20..b069e6cf3b6 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -29,10 +29,6 @@ # error WIN32 only! #endif // WIN32 -/* require Windows XP or newer */ -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x501 - #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <ole2.h> // for drag-n-drop @@ -112,7 +108,7 @@ class GHOST_SystemWin32 : public GHOST_System { * \param type The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. * \param exclusive: Use to show the window ontop and ignore others (used fullscreen). - * \param parentWindow Parent (embedder) window + * \param parentWindow Parent window * \return The new window (or 0 if creation failed). */ GHOST_IWindow *createWindow(const STR_String &title, @@ -124,7 +120,8 @@ class GHOST_SystemWin32 : public GHOST_System { GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, - const GHOST_TEmbedderWindowID parentWindow = 0); + const bool is_dialog = false, + const GHOST_IWindow *parentWindow = 0); /** * Create a new offscreen context. @@ -204,6 +201,22 @@ class GHOST_SystemWin32 : public GHOST_System { void putClipboard(GHOST_TInt8 *buffer, bool selection) const; /** + * Show a system message box + * \param title The title of the message box + * \param message The message to display + * \param help_label Help button label + * \param continue_label Continue button label + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + GHOST_TSuccess showMessageBox(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options) const; + + /** * Creates a drag'n'drop event and pushes it immediately onto the event queue. * Called by GHOST_DropTargetWin32 class. * \param eventType: The type of drag'n'drop event diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index e46edeeac9a..1ca412fbccc 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -324,7 +324,7 @@ void GHOST_SystemX11::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 * \param type The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. * \param exclusive: Use to show the window ontop and ignore others (used fullscreen). - * \param parentWindow Parent (embedder) window + * \param parentWindow Parent window * \return The new window (or 0 if creation failed). */ GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title, @@ -336,7 +336,8 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title, GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, - const GHOST_TEmbedderWindowID parentWindow) + const bool is_dialog, + const GHOST_IWindow *parentWindow) { GHOST_WindowX11 *window = NULL; @@ -351,8 +352,9 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title, width, height, state, - parentWindow, + (GHOST_WindowX11 *)parentWindow, type, + is_dialog, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, ((glSettings.flags & GHOST_glAlphaBackground) != 0), @@ -2143,6 +2145,222 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const } } +/** \name Message Box + * \{ */ +class DialogData { + public: + /* Width of the dialog */ + uint width; + /* Heigth of the dialog */ + uint height; + /* Default padding (x direction) between controls and edge of dialog */ + uint padding_x; + /* Default padding (y direction) between controls and edge of dialog */ + uint padding_y; + /* Width of a single button */ + uint button_width; + /* Height of a single button */ + uint button_height; + /* Inset of a button to its text */ + uint button_inset_x; + /* Size of the border of the button */ + uint button_border_size; + /* Height of a line of text */ + uint line_height; + /* offset of the text inside the button */ + uint button_text_offset_y; + + /* Construct a new DialogData with the default settings */ + DialogData() + : width(640), + height(175), + padding_x(10), + padding_y(5), + button_width(130), + button_height(24), + button_inset_x(10), + button_border_size(1), + line_height(16) + { + button_text_offset_y = button_height - line_height; + } + + void drawButton(Display *display, + Window &window, + GC &borderGC, + GC &buttonGC, + uint button_num, + const char *label) + { + XFillRectangle(display, + window, + borderGC, + width - (padding_x + button_width) * button_num, + height - padding_y - button_height, + button_width, + button_height); + + XFillRectangle(display, + window, + buttonGC, + width - (padding_x + button_width) * button_num + button_border_size, + height - padding_y - button_height + button_border_size, + button_width - button_border_size * 2, + button_height - button_border_size * 2); + + XDrawString(display, + window, + borderGC, + width - (padding_x + button_width) * button_num + button_inset_x, + height - padding_y - button_text_offset_y, + label, + strlen(label)); + } + + /* Is the mouse inside the given button */ + bool isInsideButton(XEvent &e, uint button_num) + { + return ((e.xmotion.y > height - padding_y - button_height) && + (e.xmotion.y < height - padding_y) && + (e.xmotion.x > width - (padding_x + button_width) * button_num) && + (e.xmotion.x < width - padding_x - (padding_x + button_width) * (button_num - 1))); + } +}; + +static void split(const char *text, const char *seps, char ***str, int *count) +{ + char *tok, *data; + int i; + *count = 0; + + data = strdup(text); + for (tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps)) + (*count)++; + free(data); + + data = strdup(text); + *str = (char **)malloc((size_t)(*count) * sizeof(char *)); + for (i = 0, tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps), i++) + (*str)[i] = strdup(tok); + free(data); +} + +GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions) const +{ + char **text_splitted = NULL; + int textLines = 0; + split(message, "\n", &text_splitted, &textLines); + + DialogData dialog_data; + XSizeHints hints; + + Window window; + XEvent e; + int screen = DefaultScreen(m_display); + window = XCreateSimpleWindow(m_display, + RootWindow(m_display, screen), + 0, + 0, + dialog_data.width, + dialog_data.height, + 1, + BlackPixel(m_display, screen), + WhitePixel(m_display, screen)); + + /* Window Should not be resizable */ + { + hints.flags = PSize | PMinSize | PMaxSize; + hints.min_width = hints.max_width = hints.base_width = dialog_data.width; + hints.min_height = hints.max_height = hints.base_height = dialog_data.height; + XSetWMNormalHints(m_display, window, &hints); + } + + /* Set title */ + { + Atom wm_Name = XInternAtom(m_display, "_NET_WM_NAME", False); + Atom utf8Str = XInternAtom(m_display, "UTF8_STRING", False); + + Atom winType = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False); + Atom typeDialog = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + + XChangeProperty(m_display, + window, + wm_Name, + utf8Str, + 8, + PropModeReplace, + (const unsigned char *)title, + (int)strlen(title)); + + XChangeProperty( + m_display, window, winType, XA_ATOM, 32, PropModeReplace, (unsigned char *)&typeDialog, 1); + } + + /* Create buttons GC */ + XGCValues buttonBorderGCValues; + buttonBorderGCValues.foreground = BlackPixel(m_display, screen); + buttonBorderGCValues.background = WhitePixel(m_display, screen); + XGCValues buttonGCValues; + buttonGCValues.foreground = WhitePixel(m_display, screen); + buttonGCValues.background = BlackPixel(m_display, screen); + + GC buttonBorderGC = XCreateGC(m_display, window, GCForeground, &buttonBorderGCValues); + GC buttonGC = XCreateGC(m_display, window, GCForeground, &buttonGCValues); + + XSelectInput(m_display, window, ExposureMask | ButtonPressMask | ButtonReleaseMask); + XMapWindow(m_display, window); + + while (1) { + XNextEvent(m_display, &e); + if (e.type == Expose) { + for (int i = 0; i < textLines; i++) { + XDrawString(m_display, + window, + DefaultGC(m_display, screen), + dialog_data.padding_x, + dialog_data.padding_x + (i + 1) * dialog_data.line_height, + text_splitted[i], + (int)strlen(text_splitted[i])); + } + dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 1, continue_label); + if (strlen(link)) { + dialog_data.drawButton(m_display, window, buttonBorderGC, buttonGC, 2, help_label); + } + } + else if (e.type == ButtonRelease) { + if (dialog_data.isInsideButton(e, 1)) { + break; + } + else if (dialog_data.isInsideButton(e, 2)) { + if (strlen(link)) { + string cmd = "xdg-open \"" + string(link) + "\""; + if (system(cmd.c_str()) != 0) { + GHOST_PRINTF("GHOST_SystemX11::showMessageBox: Unable to run system command [%s]", + cmd); + } + } + break; + } + } + } + + for (int i = 0; i < textLines; i++) { + free(text_splitted[i]); + } + free(text_splitted); + + XDestroyWindow(m_display, window); + XFreeGC(m_display, buttonBorderGC); + XFreeGC(m_display, buttonGC); + return GHOST_kSuccess; +} +/* \} */ + #ifdef WITH_XDND GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, @@ -2303,26 +2521,30 @@ void GHOST_SystemX11::refreshXInputDevices() /* Find how many pressure levels tablet has */ XAnyClassPtr ici = device_info[i].inputclassinfo; - for (int j = 0; j < xtablet.Device->num_classes; ++j) { - if (ici->c_class == ValuatorClass) { - XValuatorInfo *xvi = (XValuatorInfo *)ici; - xtablet.PressureLevels = xvi->axes[2].max_value; - - if (xvi->num_axes > 3) { - /* this is assuming that the tablet has the same tilt resolution in both - * positive and negative directions. It would be rather weird if it didn't.. */ - xtablet.XtiltLevels = xvi->axes[3].max_value; - xtablet.YtiltLevels = xvi->axes[4].max_value; - } - else { - xtablet.XtiltLevels = 0; - xtablet.YtiltLevels = 0; + if (ici != NULL) { + for (int j = 0; j < xtablet.Device->num_classes; ++j) { + if (ici->c_class == ValuatorClass) { + XValuatorInfo *xvi = (XValuatorInfo *)ici; + if (xvi->axes != NULL) { + xtablet.PressureLevels = xvi->axes[2].max_value; + + if (xvi->num_axes > 3) { + /* this is assuming that the tablet has the same tilt resolution in both + * positive and negative directions. It would be rather weird if it didn't.. */ + xtablet.XtiltLevels = xvi->axes[3].max_value; + xtablet.YtiltLevels = xvi->axes[4].max_value; + } + else { + xtablet.XtiltLevels = 0; + xtablet.YtiltLevels = 0; + } + + break; + } } - break; + ici = (XAnyClassPtr)(((char *)ici) + ici->length); } - - ici = (XAnyClassPtr)(((char *)ici) + ici->length); } m_xtablets.push_back(xtablet); diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 1fe94b40f17..67dd0789ac3 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -146,7 +146,8 @@ class GHOST_SystemX11 : public GHOST_System { GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, - const GHOST_TEmbedderWindowID parentWindow = 0); + const bool is_dialog = false, + const GHOST_IWindow *parentWindow = 0); /** * Create a new offscreen context. @@ -232,6 +233,21 @@ class GHOST_SystemX11 : public GHOST_System { */ void putClipboard(GHOST_TInt8 *buffer, bool selection) const; + /** + * Show a system message box + * \param title The title of the message box + * \param message The message to display + * \param help_label Help button label + * \param continue_label Continue button label + * \param link An optional hyperlink + * \param dialog_options Options how to display the message + */ + GHOST_TSuccess showMessageBox(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options) const; #ifdef WITH_XDND /** * Creates a drag'n'drop event and pushes it immediately onto the event queue. diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 5f9e8ffdd5e..553a7d89df4 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -109,6 +109,11 @@ class GHOST_Window : public GHOST_IWindow { */ inline GHOST_TStandardCursor getCursorShape() const; + inline bool isDialog() const + { + return false; + } + /** * Set the shape of the cursor. * \param cursorShape: The new cursor shape type id. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 66de8bcf7cc..d260d0eacbc 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -66,7 +66,9 @@ class GHOST_WindowCocoa : public GHOST_Window { GHOST_TWindowState state, GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, const bool stereoVisual = false, - bool is_debug = false); + bool is_debug = false, + bool dialog = false, + GHOST_WindowCocoa *parentWindow = 0); /** * Destructor. @@ -218,6 +220,8 @@ class GHOST_WindowCocoa : public GHOST_Window { NSCursor *getStandardCursor(GHOST_TStandardCursor cursor) const; void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; + bool isDialog() const; + const GHOST_TabletData *GetTabletData() { return &m_tablet; @@ -328,6 +332,7 @@ class GHOST_WindowCocoa : public GHOST_Window { bool m_immediateDraw; bool m_debug_context; // for debug messages during context setup + bool m_is_dialog; }; #endif // __GHOST_WINDOWCOCOA_H__ diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 6087df978fa..1d89da90a32 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -166,7 +166,8 @@ - (BOOL)canBecomeKeyWindow { - return YES; + /* Don't make other windows active when a dialog window is open. */ + return (associatedWindow->isDialog() || !systemCocoa->hasDialogWindow()); } //The drag'n'drop dragging destination methods @@ -290,7 +291,9 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, GHOST_TWindowState state, GHOST_TDrawingContextType type, const bool stereoVisual, - bool is_debug) + bool is_debug, + bool is_dialog, + GHOST_WindowCocoa *parentWindow) : GHOST_Window(width, height, state, stereoVisual, false), m_openGLView(nil), m_metalView(nil), @@ -298,7 +301,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, m_systemCocoa(systemCocoa), m_customCursor(0), m_immediateDraw(false), - m_debug_context(is_debug) + m_debug_context(is_debug), + m_is_dialog(is_dialog) { m_fullScreen = false; @@ -313,12 +317,16 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, rect.size.width = width; rect.size.height = height; - m_window = [[CocoaWindow alloc] - initWithContentRect:rect - styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable - backing:NSBackingStoreBuffered - defer:NO]; + NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskResizable; + if (!is_dialog) { + styleMask |= NSWindowStyleMaskMiniaturizable; + } + + m_window = [[CocoaWindow alloc] initWithContentRect:rect + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; if (m_window == nil) { [pool drain]; @@ -402,6 +410,10 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, if (state == GHOST_kWindowStateFullScreen) setState(GHOST_kWindowStateFullScreen); + if (is_dialog && parentWindow) { + [parentWindow->getCocoaWindow() addChildWindow:m_window ordered:NSWindowAbove]; + } + setNativePixelSize(); [pool drain]; @@ -548,10 +560,8 @@ void GHOST_WindowCocoa::getClientBounds(GHOST_Rect &bounds) const NSRect screenSize = [[m_window screen] visibleFrame]; // Max window contents as screen size (excluding title bar...) - NSRect contentRect = [CocoaWindow - contentRectForFrameRect:screenSize - styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable)]; + NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize + styleMask:[m_window styleMask]]; rect = [m_window contentRectForFrameRect:[m_window frame]]; @@ -1045,6 +1055,11 @@ void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor shape) co [cursor set]; } +bool GHOST_WindowCocoa::isDialog() const +{ + return m_is_dialog; +} + GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h index 1d332a7dc3e..29f3eee7cce 100644 --- a/intern/ghost/intern/GHOST_WindowNULL.h +++ b/intern/ghost/intern/GHOST_WindowNULL.h @@ -36,6 +36,11 @@ class GHOST_WindowNULL : public GHOST_Window { return NULL; } + GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor) + { + return GHOST_kSuccess; + } + GHOST_WindowNULL(GHOST_SystemNULL *system, const STR_String &title, GHOST_TInt32 left, @@ -43,7 +48,7 @@ class GHOST_WindowNULL : public GHOST_Window { GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, - const GHOST_TEmbedderWindowID parentWindow, + const GHOST_IWindow *parentWindow, GHOST_TDrawingContextType type, const bool stereoVisual) : GHOST_Window(width, height, state, stereoVisual, false), m_system(system) diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index d283e9e3aff..e1c6aa1109c 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -23,6 +23,7 @@ #define _USE_MATH_DEFINES +#include "GHOST_WindowManager.h" #include "GHOST_WindowWin32.h" #include "GHOST_SystemWin32.h" #include "GHOST_DropTargetWin32.h" @@ -66,8 +67,9 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, GHOST_TDrawingContextType type, bool wantStereoVisual, bool alphaBackground, - GHOST_TEmbedderWindowID parentwindowhwnd, - bool is_debug) + GHOST_WindowWin32 *parentwindow, + bool is_debug, + bool dialog) : GHOST_Window(width, height, state, wantStereoVisual, false), m_inLiveResize(false), m_system(system), @@ -82,7 +84,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_fpGetPointerInfo(NULL), m_fpGetPointerPenInfo(NULL), m_fpGetPointerTouchInfo(NULL), - m_parentWindowHwnd(parentwindowhwnd), + m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : NULL), m_debug_context(is_debug) { // Initialize tablet variables @@ -146,9 +148,9 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, top = monitor.rcWork.top; int wintype = WS_OVERLAPPEDWINDOW; - if (m_parentWindowHwnd != 0) { + if ((m_parentWindowHwnd != 0) && !dialog) { wintype = WS_CHILD; - GetWindowRect((HWND)m_parentWindowHwnd, &rect); + GetWindowRect(m_parentWindowHwnd, &rect); left = 0; top = 0; width = rect.right - rect.left; @@ -156,14 +158,14 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0); - m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name - title_16, // pointer to window name - wintype, // window style - left, // horizontal position of window - top, // vertical position of window - width, // window width - height, // window height - (HWND)m_parentWindowHwnd, // handle to parent or owner window + m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name + title_16, // pointer to window name + wintype, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + dialog ? 0 : m_parentWindowHwnd, // handle to parent or owner window 0, // handle to menu or child-window identifier ::GetModuleHandle(0), // handle to application instance 0); // pointer to window-creation data @@ -267,7 +269,16 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } } - if (parentwindowhwnd != 0) { + if (dialog && parentwindow) { + ::SetWindowLongPtr(m_hWnd, + GWL_STYLE, + WS_VISIBLE | WS_CHILD | WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX | + WS_SIZEBOX); + ::SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, (LONG_PTR)m_parentWindowHwnd); + ::SetWindowPos( + m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + } + else if (parentwindow) { RAWINPUTDEVICE device = {0}; device.usUsagePage = 0x01; /* usUsagePage & usUsage for keyboard*/ device.usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */ @@ -386,6 +397,16 @@ GHOST_WindowWin32::~GHOST_WindowWin32() } if (m_hWnd) { + /* If this window is referenced by others as parent, clear that relation or windows will free + * the handle while we still reference it. */ + for (GHOST_IWindow *iter_win : m_system->getWindowManager()->getWindows()) { + GHOST_WindowWin32 *iter_winwin = (GHOST_WindowWin32 *)iter_win; + if (iter_winwin->m_parentWindowHwnd == m_hWnd) { + ::SetWindowLongPtr(iter_winwin->m_hWnd, GWLP_HWNDPARENT, NULL); + iter_winwin->m_parentWindowHwnd = 0; + } + } + if (m_dropTarget) { // Disable DragDrop RevokeDragDrop(m_hWnd); @@ -528,7 +549,7 @@ GHOST_TWindowState GHOST_WindowWin32::getState() const // we need to find a way to combine parented windows + resizing if we simply set the // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else. // It's also strange that in Windows is the only platform we need to make this separation. - if (m_parentWindowHwnd != 0) { + if ((m_parentWindowHwnd != 0) && !isDialog()) { state = GHOST_kWindowStateEmbedded; return state; } @@ -574,6 +595,7 @@ void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) { GHOST_TWindowState curstate = getState(); + LONG_PTR newstyle = -1; WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT); ::GetWindowPlacement(m_hWnd, &wp); @@ -587,7 +609,7 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) break; case GHOST_kWindowStateMaximized: wp.showCmd = SW_SHOWMAXIMIZED; - ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + newstyle = WS_OVERLAPPEDWINDOW; break; case GHOST_kWindowStateFullScreen: if (curstate != state && curstate != GHOST_kWindowStateMinimized) @@ -595,17 +617,21 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) wp.showCmd = SW_SHOWMAXIMIZED; wp.ptMaxPosition.x = 0; wp.ptMaxPosition.y = 0; - ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_MAXIMIZE); + newstyle = WS_MAXIMIZE; break; case GHOST_kWindowStateEmbedded: - ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD); + newstyle = WS_CHILD; break; case GHOST_kWindowStateNormal: default: wp.showCmd = SW_SHOWNORMAL; - ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + newstyle = WS_OVERLAPPEDWINDOW; break; } + if ((newstyle >= 0) && !isDialog()) { + ::SetWindowLongPtr(m_hWnd, GWL_STYLE, newstyle); + } + /* Clears window cache for SetWindowLongPtr */ ::SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); @@ -737,6 +763,14 @@ void GHOST_WindowWin32::lostMouseCapture() } } +bool GHOST_WindowWin32::isDialog() const +{ + HWND parent = (HWND)::GetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT); + long int style = (long int)::GetWindowLongPtr(m_hWnd, GWL_STYLE); + + return (parent != 0) && (style & WS_POPUPWINDOW); +} + void GHOST_WindowWin32::registerMouseClickEvent(int press) { diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 8dac142d6f4..f72f03855fd 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -235,8 +235,9 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, bool wantStereoVisual = false, bool alphaBackground = false, - GHOST_TEmbedderWindowID parentWindowHwnd = 0, - bool is_debug = false); + GHOST_WindowWin32 *parentWindow = 0, + bool is_debug = false, + bool dialog = false); /** * Destructor. @@ -381,6 +382,8 @@ class GHOST_WindowWin32 : public GHOST_Window { */ void lostMouseCapture(); + bool isDialog() const; + /** * Loads the windows equivalent of a standard GHOST cursor. * \param visible Flag for cursor visibility. @@ -528,8 +531,7 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_WIN32_GetPointerPenInfo m_fpGetPointerPenInfo; GHOST_WIN32_GetPointerTouchInfo m_fpGetPointerTouchInfo; - /** Hwnd to parent window */ - GHOST_TEmbedderWindowID m_parentWindowHwnd; + HWND m_parentWindowHwnd; #ifdef WITH_INPUT_IME /** Handle input method editors event */ diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 8aa4a4e284a..ae8d705fe4a 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -72,7 +72,18 @@ typedef struct { long input_mode; } MotifWmHints; -#define MWM_HINTS_DECORATIONS (1L << 1) +enum { + MWM_HINTS_FUNCTIONS = (1L << 0), + MWM_HINTS_DECORATIONS = (1L << 1), +}; +enum { + MWM_FUNCTION_ALL = (1L << 0), + MWM_FUNCTION_RESIZE = (1L << 1), + MWM_FUNCTION_MOVE = (1L << 2), + MWM_FUNCTION_MINIMIZE = (1L << 3), + MWM_FUNCTION_MAXIMIZE = (1L << 4), + MWM_FUNCTION_CLOSE = (1L << 5), +}; #ifndef HOST_NAME_MAX # define HOST_NAME_MAX 64 @@ -191,8 +202,9 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, - const GHOST_TEmbedderWindowID parentWindow, + GHOST_WindowX11 *parentWindow, GHOST_TDrawingContextType type, + const bool is_dialog, const bool stereoVisual, const bool exclusive, const bool alphaBackground, @@ -259,7 +271,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, m_display, RootWindow(m_display, m_visualInfo->screen), m_visualInfo->visual, AllocNone); /* create the window! */ - if (parentWindow == 0) { + if ((parentWindow == 0) || is_dialog) { m_window = XCreateWindow(m_display, RootWindow(m_display, m_visualInfo->screen), left, @@ -279,7 +291,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, unsigned int w_return, h_return, border_w_return, depth_return; XGetGeometry(m_display, - parentWindow, + parentWindow->m_window, &root_return, &x_return, &y_return, @@ -294,7 +306,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, height = h_return; m_window = XCreateWindow(m_display, - parentWindow, /* reparent against embedder */ + parentWindow->m_window, /* reparent against embedder */ left, top, width, @@ -306,7 +318,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, xattributes_valuemask, &xattributes); - XSelectInput(m_display, parentWindow, SubstructureNotifyMask); + XSelectInput(m_display, parentWindow->m_window, SubstructureNotifyMask); } #ifdef WITH_XDND @@ -356,6 +368,10 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, m_post_state = GHOST_kWindowStateNormal; } + if (is_dialog && parentWindow) { + setDialogHints(parentWindow); + } + /* Create some hints for the window manager on how * we want this window treated. */ { @@ -701,6 +717,42 @@ void GHOST_WindowX11::clientToScreen(GHOST_TInt32 inX, outY = ay; } +GHOST_TSuccess GHOST_WindowX11::setDialogHints(GHOST_WindowX11 *parentWindow) +{ + + Atom atom_window_type = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False); + Atom atom_dialog = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + MotifWmHints hints = {0}; + + XChangeProperty(m_display, + m_window, + atom_window_type, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char *)&atom_dialog, + 1); + XSetTransientForHint(m_display, m_window, parentWindow->m_window); + + /* Disable minimizing of the window for now. + * Actually, most window managers disable minimizing and maximizing for dialogs, ignoring this. + * Leaving it here anyway in the hope it brings back maximizing on some window managers at least, + * we'd preferably have it even for dialog windows (e.g. file browser). */ + hints.flags = MWM_HINTS_FUNCTIONS; + hints.functions = MWM_FUNCTION_RESIZE | MWM_FUNCTION_MOVE | MWM_FUNCTION_MAXIMIZE | + MWM_FUNCTION_CLOSE; + XChangeProperty(m_display, + m_window, + m_system->m_atom._MOTIF_WM_HINTS, + m_system->m_atom._MOTIF_WM_HINTS, + 32, + PropModeReplace, + (unsigned char *)&hints, + 4); + + return GHOST_kSuccess; +} + void GHOST_WindowX11::icccmSetState(int state) { XEvent xev; @@ -1112,6 +1164,44 @@ GHOST_TSuccess GHOST_WindowX11::setOrder(GHOST_TWindowOrder order) return GHOST_kSuccess; } +bool GHOST_WindowX11::isDialog() const +{ + Atom atom_window_type = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False); + Atom atom_dialog = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + + Atom *prop_ret; + unsigned long bytes_after, num_ret; + Atom type_ret; + bool st; + int format_ret, ret; + + prop_ret = NULL; + st = False; + ret = XGetWindowProperty(m_display, + m_window, + atom_window_type, + 0, + INT_MAX, + False, + XA_ATOM, + &type_ret, + &format_ret, + &num_ret, + &bytes_after, + (unsigned char **)&prop_ret); + if ((ret == Success) && (prop_ret) && (format_ret == 32)) { + if (prop_ret[0] == atom_dialog) { + st = True; + } + } + + if (prop_ret) { + XFree(prop_ret); + } + + return st; +} + GHOST_TSuccess GHOST_WindowX11::invalidate() { /* So the idea of this function is to generate an expose event diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 0b8fe3a3a41..faf3acba234 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -75,8 +75,9 @@ class GHOST_WindowX11 : public GHOST_Window { GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, - const GHOST_TEmbedderWindowID parentWindow, + GHOST_WindowX11 *parentWindow, GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool is_dialog = false, const bool stereoVisual = false, const bool exclusive = false, const bool alphaBackground = false, @@ -92,6 +93,8 @@ class GHOST_WindowX11 : public GHOST_Window { void getClientBounds(GHOST_Rect &bounds) const; + bool isDialog() const; + GHOST_TSuccess setClientWidth(GHOST_TUns32 width); GHOST_TSuccess setClientHeight(GHOST_TUns32 height); @@ -185,6 +188,8 @@ class GHOST_WindowX11 : public GHOST_Window { GHOST_TSuccess endFullScreen() const; + GHOST_TSuccess setDialogHints(GHOST_WindowX11 *parentWindow); + GHOST_TUns16 getDPIHint(); protected: diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c index ab58c8f48e4..4f120b7d83c 100644 --- a/intern/mikktspace/mikktspace.c +++ b/intern/mikktspace/mikktspace.c @@ -460,11 +460,6 @@ tbool genTangSpace(const SMikkTSpaceContext *pContext, const float fAngularThres /////////////////////////////////////////////////////////////////////////////////////////////////// -typedef struct { - float vert[3]; - int index; -} STmpVert; - static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext *pContext, const int iNrTrianglesIn); diff --git a/intern/numaapi/README.blender b/intern/numaapi/README.blender index 6f71d5f8807..0151be80e10 100644 --- a/intern/numaapi/README.blender +++ b/intern/numaapi/README.blender @@ -1,5 +1,5 @@ Project: LibNumaAPI URL: https://github.com/Nazg-Gul/libNumaAPI License: MIT -Upstream version: 4e7206befce +Upstream version: 1afdd28a08d Local modifications: None diff --git a/intern/numaapi/source/build_config.h b/intern/numaapi/source/build_config.h index 444adcc0c71..b8af51a5dd7 100644 --- a/intern/numaapi/source/build_config.h +++ b/intern/numaapi/source/build_config.h @@ -307,6 +307,27 @@ # define ARCH_CPU_32_BITS 1 # define ARCH_CPU_BIG_ENDIAN 1 # endif +#elif defined(__powerpc64__) +# define ARCH_CPU_PPC_FAMILY 1 +# define ARCH_CPU_PPC 1 +# define ARCH_CPU_64_BITS 1 +# if defined(__BIG_ENDIAN__) +# define ARCH_CPU_BIG_ENDIAN 1 +# elif defined(__LITTLE_ENDIAN) +# define ARCH_CPU_LITTLE_ENDIAN 1 +# else +# error Please define your endianness +# endif +#elif defined(__s390x__) +# define ARCH_CPU_S390_FAMILY 1 +# define ARCH_CPU_S390X 1 +# define ARCH_CPU_64_BITS 1 +# define ARCH_CPU_BIG_ENDIAN 1 +#elif defined(__s390__) +# define ARCH_CPU_S390_FAMILY 1 +# define ARCH_CPU_S390 1 +# define ARCH_CPU_31_BITS 1 +# define ARCH_CPU_BIG_ENDIAN 1 #else # error Please add support for your architecture in build_config.h #endif @@ -337,6 +358,12 @@ #if !defined(ARCH_CPU_MIPS64_FAMILY) # define ARCH_CPU_MIPS64_FAMILY 0 #endif +#if !defined(ARCH_CPU_PPC_FAMILY) +# define ARCH_CPU_PPC_FAMILY 0 +#endif +#if !defined(ARCH_CPU_S390_FAMILY) +# define ARCH_CPU_S390_FAMILY 0 +#endif //////////////////////////////////////////////////////////////////////////////// // Sizes of platform-dependent types. diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc index f4a1a82ca52..ac27cbdefdc 100644 --- a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc +++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc @@ -123,6 +123,21 @@ void getEdgeVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, 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); @@ -201,6 +216,8 @@ void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner) 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; @@ -389,7 +406,7 @@ bool compareCyclicBackward(const CyclicArray &array_a, // vertices. bool checkVerticesOfFacesMatch(const CyclicArray &indices_a, const CyclicArray &indices_b) { - if (indices_a.size() != indices_a.size()) { + if (indices_a.size() != indices_b.size()) { return false; } // "Align" the arrays so we know first matched element. diff --git a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h index cf7f59adf2f..38d722ab572 100644 --- a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h +++ b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h @@ -58,11 +58,13 @@ typedef struct OpenSubdiv_TopologyRefiner { int (*getNumVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner); int (*getNumEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner); int (*getNumFaces)(const struct OpenSubdiv_TopologyRefiner *topology_refiner); + int (*getNumFaceVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index); void (*getFaceVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index, int *face_vertices_indices); + int (*getNumFaceEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index); void (*getFaceEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner, @@ -72,6 +74,12 @@ typedef struct OpenSubdiv_TopologyRefiner { const int edge_index, int edge_vertices_indices[2]); + int (*getNumVertexEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner, + const int vertex_index); + void (*getVertexEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner, + const int vertex_index, + int *vertex_edges_indices); + ////////////////////////////////////////////////////////////////////////////// // PTex face geometry queries. diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject 1f6ec7f7a145c36808231090c8666febb49db22 +Subproject 88497d7507e76281fbdd0cc1f8451f81ae7e378 diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index 7785c9d2962..dc35187ab7e 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -22,6 +22,7 @@ #include "DNA_userdef_types.h" #include "DNA_curve_types.h" #include "DNA_space_types.h" +#include "DNA_anim_types.h" #include "BLI_math_rotation.h" @@ -138,6 +139,7 @@ const UserDef U_default = { .glreslimit = 0, .curssize = 0, .color_picker_type = USER_CP_CIRCLE_HSV, + .auto_smoothing_new = FCURVE_SMOOTH_CONT_ACCEL, .ipo_new = BEZT_IPO_BEZ, .keyhandles_new = HD_AUTO_ANIM, .view_frame_type = ZOOM_FRAME_MODE_KEEP_RANGE, diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c index 80bed03debf..0b9e8beccc1 100644 --- a/release/datafiles/userdef/userdef_default_theme.c +++ b/release/datafiles/userdef/userdef_default_theme.c @@ -585,6 +585,7 @@ const bTheme U_theme_default = { .anim_preview_range = RGBA(0xa14d0066), .nla_tweaking = RGBA(0x4df31a4d), .nla_tweakdupli = RGBA(0xd90000ff), + .nla_track = RGBA(0x424242ff), .nla_transition = RGBA(0x1c2630ff), .nla_transition_sel = RGBA(0x2e75dbff), .nla_meta = RGBA(0x332642ff), @@ -746,12 +747,12 @@ const bTheme U_theme_default = { .back = RGBA(0x333333b3), .sub_back = RGBA(0x0000003e), }, + .active = RGBA(0x3b5689ff), .vertex_size = 3, .outline_width = 1, .facedot_size = 4, .match = RGBA(0x337f334c), .selected_highlight = RGBA(0x223a5bff), - .active = RGBA(0x3b5689ff), .selected_object = RGBA(0xe96a00ff), .active_object = RGBA(0xffaf29ff), .edited_object = RGBA(0x00806266), diff --git a/release/freedesktop/org.blender.Blender.appdata.xml b/release/freedesktop/org.blender.Blender.appdata.xml index 1287c9eea5d..984b5b3b15e 100644 --- a/release/freedesktop/org.blender.Blender.appdata.xml +++ b/release/freedesktop/org.blender.Blender.appdata.xml @@ -40,6 +40,27 @@ </screenshot> </screenshots> <releases> + <release version="2.81" date="2019-11-14"> + <description> + <p>New features:</p> + <ul> + <li>Many sculpt tools and poly build tool for retopology</li> + <li>Voxel remesh and quad remesh</li> + <li>Transform origins, new snapping, mirroring and auto merge options</li> + <li>Revamped shaders for texturing</li> + <li>Cycles denoising with OpenImageDenoise and NVIDIA RTX support</li> + <li>Library overrides to make local overrides to linked characters and other data</li> + <li> + </ul> + <ul> + <p>Enhancements:</p> + <li>Eevee shadows, transparency and bump mapping redesigned</li> + <li>Viewport options for look development with Cycles and Eevee</li> + <li>Finer control over rotations and scale in bones, constraints and drivers</li> + <li>Outliner improvements, new file browser and batch rename</li> + </ul> + </description> + </release> <release version="2.80" date="2019-07-30"> <description> <p>New features:</p> diff --git a/release/scripts/addons b/release/scripts/addons -Subproject eb9bab0e7153fda8de113af9e3c54eca74c986e +Subproject 0ec4a4fd2ac1a9a0aaf550ced7e4b445a340ca4 diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject d9ed9d4d064c74c86e2767cd4be32d602a0ee31 +Subproject 69bcc72f1ec4df73265ce35851658ef184b9d0f diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py index a6c7940f5c8..c81558db587 100644 --- a/release/scripts/modules/bl_i18n_utils/settings.py +++ b/release/scripts/modules/bl_i18n_utils/settings.py @@ -94,6 +94,7 @@ LANGUAGES = ( (44, "Kazakh (қазақша)", "kk_KZ"), (45, "Abkhaz (Аԥсуа бызшәа)", "ab"), (46, "Thai (ภาษาไทย)", "th_TH"), + (47, "Slovak (Slovenčina)", "sk_SK"), ) # Default context, in py! diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py index 1576947b8b4..f70f1eacead 100644 --- a/release/scripts/modules/bpy_extras/mesh_utils.py +++ b/release/scripts/modules/bpy_extras/mesh_utils.py @@ -265,7 +265,7 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True): return [] def mlen(co): - # manhatten length of a vector, faster then length + # Manhatten length of a vector, faster then length. return abs(co[0]) + abs(co[1]) + abs(co[2]) def vert_treplet(v, i): @@ -278,9 +278,8 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True): return v1[1], v2[1] if not fix_loops: - """ - Normal single concave loop filling - """ + # Normal single concave loop filling. + if type(from_data) in {tuple, list}: verts = [Vector(from_data[i]) for ii, i in enumerate(indices)] else: @@ -294,17 +293,19 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True): fill = tessellate_polygon([verts]) else: - """ - Separate this loop into multiple loops be finding edges that are - used twice. This is used by lightwave LWO files a lot - """ + # Separate this loop into multiple loops be finding edges that are + # used twice. This is used by Light-Wave LWO files a lot. if type(from_data) in {tuple, list}: - verts = [vert_treplet(Vector(from_data[i]), ii) - for ii, i in enumerate(indices)] + verts = [ + vert_treplet(Vector(from_data[i]), ii) + for ii, i in enumerate(indices) + ] else: - verts = [vert_treplet(from_data.vertices[i].co, ii) - for ii, i in enumerate(indices)] + verts = [ + vert_treplet(from_data.vertices[i].co, ii) + for ii, i in enumerate(indices) + ] edges = [(i, i - 1) for i in range(len(verts))] if edges: @@ -354,7 +355,7 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True): else: return False - # If were stuill here s1 and s2 are 2 segments in the same polyline + # If were still here s1 and s2 are 2 segments in the same poly-line. s1.pop() # remove the last vert from s1 s1.extend(s2) # add segment 2 to segment 1 @@ -402,14 +403,14 @@ def ngon_tessellate(from_data, indices, fix_loops=True, debug_print=True): # draw_loops(loop_list) #raise Exception("done loop") # map to original indices - fill = [[vert_map[i] for i in reversed(f)] for f in fill] + fill = [[vert_map[i] for i in f] for f in fill] if not fill: if debug_print: print('Warning Cannot scanfill, fallback on a triangle fan.') fill = [[0, i - 1, i] for i in range(2, len(indices))] else: - # Use real scanfill. + # Use real scan-fill. # See if its flipped the wrong way. flip = None for fi in fill: diff --git a/release/scripts/modules/bpy_extras/node_shader_utils.py b/release/scripts/modules/bpy_extras/node_shader_utils.py index 4ca3e675c37..720d1d8af5a 100644 --- a/release/scripts/modules/bpy_extras/node_shader_utils.py +++ b/release/scripts/modules/bpy_extras/node_shader_utils.py @@ -487,6 +487,35 @@ class PrincipledBSDFWrapper(ShaderWrapper): alpha_texture = property(alpha_texture_get) + # -------------------------------------------------------------------- + # Emission color. + + def emission_color_get(self): + if not self.use_nodes or self.node_principled_bsdf is None: + return Color((0.0, 0.0, 0.0)) + return rgba_to_rgb(self.node_principled_bsdf.inputs["Emission"].default_value) + + @_set_check + def emission_color_set(self, color): + if self.use_nodes and self.node_principled_bsdf is not None: + color = values_clamp(color, 0.0, 1.0) + color = rgb_to_rgba(color) + self.node_principled_bsdf.inputs["Emission"].default_value = color + + emission_color = property(emission_color_get, emission_color_set) + + + def emission_color_texture_get(self): + if not self.use_nodes or self.node_principled_bsdf is None: + return None + return ShaderImageTextureWrapper( + self, self.node_principled_bsdf, + self.node_principled_bsdf.inputs["Emission"], + grid_row_diff=1, + ) + + emission_color_texture = property(emission_color_texture_get) + # -------------------------------------------------------------------- # Normal map. @@ -771,7 +800,7 @@ class ShaderImageTextureWrapper(): def scale_get(self): if self.node_mapping is None: - return Vector((0.0, 0.0, 0.0)) + return Vector((1.0, 1.0, 1.0)) return self.node_mapping.inputs['Scale'].default_value @_set_check diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 29470895079..43ee785438b 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -184,6 +184,27 @@ class WindowManager(bpy_types.ID): self.piemenu_end__internal(pie) +class WorkSpace(bpy_types.ID): + __slots__ = () + + def status_text_set(self, text): + """ + Set the status text or None to clear, + When text is a function, this will be called with the (header, context) arguments. + """ + from bl_ui.space_statusbar import STATUSBAR_HT_header + draw_fn = getattr(STATUSBAR_HT_header, "_draw_orig", None) + if draw_fn is None: + draw_fn = STATUSBAR_HT_header._draw_orig = STATUSBAR_HT_header.draw + + if not (text is None or isinstance(text, str)): + draw_fn = text + text = None + + self.status_text_set_internal(text) + STATUSBAR_HT_header.draw = draw_fn + + class _GenericBone: """ functions for bones, common between Armature/Pose/Edit bones. @@ -418,6 +439,8 @@ class Mesh(bpy_types.ID): int pairs, each pair contains two indices to the *vertices* argument. eg: [(1, 2), ...] + When an empty iterable is passed in, the edges are inferred from the polygons. + :type edges: iterable object :arg faces: @@ -453,11 +476,15 @@ class Mesh(bpy_types.ID): self.polygons.foreach_set("loop_start", loop_starts) self.polygons.foreach_set("vertices", vertex_indices) - # if no edges - calculate them - if faces and (not edges): - self.update(calc_edges=True) - elif edges: - self.update(calc_edges_loose=True) + if edges or faces: + self.update( + # Needed to either: + # - Calculate edges that don't exist for polygons. + # - Assign edges to polygon loops. + calc_edges=bool(faces), + # Flag loose edges. + calc_edges_loose=bool(edges), + ) @property def edge_keys(self): @@ -612,17 +639,27 @@ class Gizmo(StructRNA): if select_id is not None: gpu.select.load_id(select_id) + use_blend = False else: if self.is_highlight: color = (*self.color_highlight, self.alpha_highlight) else: color = (*self.color, self.alpha) shader.uniform_float("color", color) + use_blend = color[3] < 1.0 + + if use_blend: + # TODO: wrap GPU_blend from GPU state. + from bgl import glEnable, glDisable, GL_BLEND + glEnable(GL_BLEND) with gpu.matrix.push_pop(): gpu.matrix.multiply_matrix(matrix) batch.draw() + if use_blend: + glDisable(GL_BLEND) + @staticmethod def new_custom_shape(type, verts): """ diff --git a/release/scripts/presets/keyconfig/blender.py b/release/scripts/presets/keyconfig/blender.py index 8a7689d6d60..596b17d734f 100644 --- a/release/scripts/presets/keyconfig/blender.py +++ b/release/scripts/presets/keyconfig/blender.py @@ -169,7 +169,10 @@ def load(): keyconfig_data = blender_default.generate_keymaps( blender_default.Params( select_mouse=kc_prefs.select_mouse, - use_mouse_emulate_3_button=prefs.inputs.use_mouse_emulate_3_button, + use_mouse_emulate_3_button=( + prefs.inputs.use_mouse_emulate_3_button and + prefs.inputs.mouse_emulate_3_button_modifier == 'ALT' + ), spacebar_action=kc_prefs.spacebar_action, v3d_tilde_action=kc_prefs.v3d_tilde_action, use_select_all_toggle=kc_prefs.use_select_all_toggle, diff --git a/release/scripts/presets/keyconfig/blender_27x.py b/release/scripts/presets/keyconfig/blender_27x.py index 4ce77f46213..8d50d449494 100644 --- a/release/scripts/presets/keyconfig/blender_27x.py +++ b/release/scripts/presets/keyconfig/blender_27x.py @@ -53,7 +53,10 @@ def load(): keyconfig_data = blender_default.generate_keymaps( blender_default.Params( select_mouse=kc_prefs.select_mouse, - use_mouse_emulate_3_button=prefs.inputs.use_mouse_emulate_3_button, + use_mouse_emulate_3_button=( + prefs.inputs.use_mouse_emulate_3_button and + prefs.inputs.mouse_emulate_3_button_modifier == 'ALT' + ), spacebar_action='SEARCH', use_select_all_toggle=True, use_gizmo_drag=False, diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index ddf7accc2b2..b7fd266596b 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -1448,7 +1448,6 @@ def km_graph_editor(params): ("graph.bake", {"type": 'C', "value": 'PRESS', "alt": True}, None), op_menu("GRAPH_MT_delete", {"type": 'X', "value": 'PRESS'}), op_menu("GRAPH_MT_delete", {"type": 'DEL', "value": 'PRESS'}), - op_menu("GRAPH_MT_context_menu", params.context_menu_event), ("graph.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), ("graph.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), ("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "ctrl": True}, @@ -1479,6 +1478,7 @@ def km_graph_editor(params): op_menu_pie("GRAPH_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}), ("marker.add", {"type": 'M', "value": 'PRESS'}, None), ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + op_menu("GRAPH_MT_context_menu", params.context_menu_event), ]) if params.select_mouse == 'LEFTMOUSE' and not params.legacy: @@ -1582,9 +1582,9 @@ def km_image(params): ) ), op_menu_pie("IMAGE_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}), - op_menu("IMAGE_MT_mask_context_menu", params.context_menu_event), ("image.render_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), ("image.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None), + op_menu("IMAGE_MT_mask_context_menu", params.context_menu_event), ]) if params.legacy: @@ -1671,7 +1671,6 @@ def km_node_editor(params): {"properties": [("factor", 1.2)]}), ("node.backimage_fit", {"type": 'HOME', "value": 'PRESS', "alt": True}, None), ("node.backimage_sample", {"type": params.action_mouse, "value": 'PRESS', "alt": True}, None), - op_menu("NODE_MT_context_menu", params.context_menu_event), ("node.link_make", {"type": 'F', "value": 'PRESS'}, {"properties": [("replace", False)]}), ("node.link_make", {"type": 'F', "value": 'PRESS', "shift": True}, @@ -1737,6 +1736,7 @@ def km_node_editor(params): {"properties": [("data_path", 'tool_settings.use_snap')]}), ("wm.context_menu_enum", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, {"properties": [("data_path", 'tool_settings.snap_node_element')]}), + op_menu("NODE_MT_context_menu", params.context_menu_event), ]) return keymap @@ -1793,6 +1793,9 @@ def km_file_browser(params): {"properties": [("data_path", 'space_data.params.show_hidden')]}), ("file.directory_new", {"type": 'I', "value": 'PRESS'}, {"properties": [("confirm", False)]}), + ("file.rename", {"type": 'F2', "value": 'PRESS'}, None), + ("file.delete", {"type": 'X', "value": 'PRESS'}, None), + ("file.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None), ("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), ("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, @@ -1831,7 +1834,7 @@ def km_file_browser_main(params): ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True}, {"properties": [("extend", True)]}), ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True}, - {"properties": [("extend", True), ("fill", True)]}), + {"properties": [("extend", True), ("fill", True), ("open", False)]}), ("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'UP')]}), ("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS', "shift": True}, @@ -1983,7 +1986,6 @@ def km_dopesheet(params): ("action.interpolation_type", {"type": 'T', "value": 'PRESS'}, None), ("action.extrapolation_type", {"type": 'E', "value": 'PRESS', "shift": True}, None), ("action.keyframe_type", {"type": 'R', "value": 'PRESS'}, None), - op_menu("DOPESHEET_MT_context_menu", params.context_menu_event), ("action.sample", {"type": 'O', "value": 'PRESS', "shift": True, "alt": True}, None), op_menu("DOPESHEET_MT_delete", {"type": 'X', "value": 'PRESS'}), op_menu("DOPESHEET_MT_delete", {"type": 'DEL', "value": 'PRESS'}), @@ -2015,6 +2017,7 @@ def km_dopesheet(params): op_menu_pie("VIEW3D_MT_proportional_editing_falloff_pie", {"type": 'O', "value": 'PRESS', "shift": True}), ("marker.add", {"type": 'M', "value": 'PRESS'}, None), ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + op_menu("DOPESHEET_MT_context_menu", params.context_menu_event), ]) return keymap @@ -2128,7 +2131,6 @@ def km_nla_editor(params): ("nla.apply_scale", {"type": 'A', "value": 'PRESS', "ctrl": True}, None), ("nla.clear_scale", {"type": 'S', "value": 'PRESS', "alt": True}, None), op_menu_pie("NLA_MT_snap_pie", {"type": 'S', "value": 'PRESS', "shift": True}), - op_menu("NLA_MT_context_menu", params.context_menu_event), ("nla.fmodifier_add", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None), ("transform.transform", {"type": 'G', "value": 'PRESS'}, {"properties": [("mode", 'TRANSLATION')]}), @@ -2140,6 +2142,7 @@ def km_nla_editor(params): {"properties": [("mode", 'TIME_SCALE')]}), ("marker.add", {"type": 'M', "value": 'PRESS'}, None), ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + op_menu("NLA_MT_context_menu", params.context_menu_event), ]) return keymap @@ -2299,9 +2302,9 @@ def km_text(params): {"properties": [("lines", 1)]}), ("text.line_break", {"type": 'RET', "value": 'PRESS'}, None), ("text.line_break", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None), - op_menu("TEXT_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}), ("text.autocomplete", {"type": 'SPACE', "value": 'PRESS', "ctrl": True}, None), ("text.line_number", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None), + op_menu("TEXT_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}), ("text.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None), ]) @@ -2429,7 +2432,6 @@ def km_sequencer(params): ("sequencer.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None), op_menu("SEQUENCER_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}), op_menu("SEQUENCER_MT_change", {"type": 'C', "value": 'PRESS'}), - op_menu("SEQUENCER_MT_context_menu", params.context_menu_event), ("sequencer.slip", {"type": 'S', "value": 'PRESS'}, None), ("wm.context_set_int", {"type": 'O', "value": 'PRESS'}, {"properties": [("data_path", 'scene.sequence_editor.overlay_frame'), ("value", 0)]}), @@ -2443,6 +2445,7 @@ def km_sequencer(params): {"properties": [("left_right", 'LEFT'), ("linked_time", True)]}), ("sequencer.select", {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, {"properties": [("left_right", 'RIGHT'), ("linked_time", True)]}), + op_menu("SEQUENCER_MT_context_menu", params.context_menu_event), ]) return keymap @@ -2539,8 +2542,8 @@ def km_console(params): {"properties": [("text", '\t')]}), ("console.indent", {"type": 'TAB', "value": 'PRESS'}, None), ("console.unindent", {"type": 'TAB', "value": 'PRESS', "shift": True}, None), + op_menu("CONSOLE_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}), ("console.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None), - op_menu("CONSOLE_MT_context_menu", params.context_menu_event), ]) return keymap @@ -2667,7 +2670,6 @@ def km_clip_editor(params): ("clip.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), ("clip.keyframe_delete", {"type": 'I', "value": 'PRESS', "alt": True}, None), ("clip.join_tracks", {"type": 'J', "value": 'PRESS', "ctrl": True}, None), - op_menu("CLIP_MT_tracking_context_menu", params.context_menu_event), ("clip.lock_selection_toggle", {"type": 'L', "value": 'PRESS'}, None), ("wm.context_toggle", {"type": 'D', "value": 'PRESS', "alt": True}, {"properties": [("data_path", 'space_data.show_disabled')]}), @@ -2689,6 +2691,7 @@ def km_clip_editor(params): op_menu_pie("CLIP_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}), ("clip.copy_tracks", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), ("clip.paste_tracks", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + op_menu("CLIP_MT_tracking_context_menu", params.context_menu_event), ]) if params.legacy: @@ -3049,8 +3052,6 @@ def km_grease_pencil_stroke_edit_mode(params): ("gpencil.blank_frame_add", {"type": 'I', "value": 'PRESS', "shift": True}, None), ("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None), ("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None), - # Context menu - op_menu("VIEW3D_MT_gpencil_edit_context_menu", params.context_menu_event), # Separate ("gpencil.stroke_separate", {"type": 'P', "value": 'PRESS'}, None), # Split and joint strokes @@ -3105,6 +3106,8 @@ def km_grease_pencil_stroke_edit_mode(params): {"properties": [("mode", 1)]}), ("gpencil.selectmode_toggle", {"type": 'THREE', "value": 'PRESS'}, {"properties": [("mode", 2)]}), + # Context menu + op_menu("VIEW3D_MT_gpencil_edit_context_menu", params.context_menu_event), ]) if params.legacy: @@ -3131,8 +3134,6 @@ def km_grease_pencil_stroke_paint_mode(params): # Brush size ("wm.radial_control", {"type": 'F', "value": 'PRESS'}, {"properties": [("data_path_primary", 'tool_settings.gpencil_paint.brush.size')]}), - # Draw context menu - op_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event), # Draw delete menu op_menu("GPENCIL_MT_gpencil_draw_delete", {"type": 'X', "value": 'PRESS'}), # Animation menu @@ -3148,6 +3149,8 @@ def km_grease_pencil_stroke_paint_mode(params): {"properties": [("unselected", False)]}), ("gpencil.hide", {"type": 'H', "value": 'PRESS', "shift": True}, {"properties": [("unselected", True)]}), + # Draw context menu + op_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event), ]) return keymap @@ -3170,9 +3173,6 @@ def km_grease_pencil_stroke_paint_draw_brush(params): # Draw - straight lines ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, {"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}), - # Draw - poly lines - ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, - {"properties": [("mode", 'DRAW_POLY'), ("wait_for_input", False)]}), # Erase ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, {"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}), @@ -3278,12 +3278,12 @@ def km_grease_pencil_stroke_sculpt_mode(params): # Brush size ("wm.radial_control", {"type": 'F', "value": 'PRESS'}, {"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.size')]}), - # Context menu - op_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event), # Copy ("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), # Display *_grease_pencil_display(), + # Context menu + op_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event), ]) return keymap @@ -3425,7 +3425,6 @@ def km_pose(params): ("pose.push", {"type": 'E', "value": 'PRESS', "ctrl": True}, None), ("pose.relax", {"type": 'E', "value": 'PRESS', "alt": True}, None), ("pose.breakdown", {"type": 'E', "value": 'PRESS', "shift": True}, None), - op_menu("VIEW3D_MT_pose_context_menu", params.context_menu_event), op_menu("VIEW3D_MT_pose_propagate", {"type": 'P', "value": 'PRESS', "alt": True}), *( (("object.hide_collection", @@ -3434,6 +3433,7 @@ def km_pose(params): for i in range(10) ) ), + op_menu("VIEW3D_MT_pose_context_menu", params.context_menu_event), ]) return keymap @@ -3496,7 +3496,6 @@ def km_object_mode(params): ("collection.objects_remove_all", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), ("collection.objects_add_active", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True}, None), ("collection.objects_remove_active", {"type": 'G', "value": 'PRESS', "shift": True, "alt": True}, None), - op_menu("VIEW3D_MT_object_context_menu", params.context_menu_event), *_template_items_object_subdivision_set(), ("object.move_to_collection", {"type": 'M', "value": 'PRESS'}, None), ("object.link_to_collection", {"type": 'M', "value": 'PRESS', "shift": True}, None), @@ -3513,6 +3512,7 @@ def km_object_mode(params): for i in range(10) ) ), + op_menu("VIEW3D_MT_object_context_menu", params.context_menu_event), ]) if params.legacy: @@ -3613,9 +3613,9 @@ def km_curve(params): {"properties": [("unselected", True)]}), ("curve.normals_make_consistent", {"type": 'N', "value": 'PRESS', "ctrl" if params.legacy else "shift": True}, None), ("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), - op_menu("VIEW3D_MT_edit_curve_context_menu", params.context_menu_event), op_menu("VIEW3D_MT_hook", {"type": 'H', "value": 'PRESS', "ctrl": True}), *_template_items_proportional_editing(connected=True), + op_menu("VIEW3D_MT_edit_curve_context_menu", params.context_menu_event), ]) return keymap @@ -3917,8 +3917,8 @@ def km_sculpt(params): ("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True}, {"properties": [("data_path", 'tool_settings.sculpt.brush.use_smooth_stroke')]}), op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}), + op_menu_pie("VIEW3D_MT_sculpt_mask_edit_pie", {"type" : 'A', "value": 'PRESS'}), op_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event), - op_menu_pie("VIEW3D_MT_sculpt_mask_edit_pie", {"type" : 'A', "value": 'PRESS'}) ]) if params.legacy: @@ -4022,7 +4022,6 @@ def km_mesh(params): {"properties": [("use_occlude_geometry", True), ("only_selected", False)]}), ("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), # Menus. - op_menu("VIEW3D_MT_edit_mesh_context_menu", params.context_menu_event), op_menu("VIEW3D_MT_edit_mesh_faces", {"type": 'F', "value": 'PRESS', "ctrl": True}), op_menu("VIEW3D_MT_edit_mesh_edges", {"type": 'E', "value": 'PRESS', "ctrl": True}), op_menu("VIEW3D_MT_edit_mesh_vertices", {"type": 'V', "value": 'PRESS', "ctrl": True}), @@ -4032,6 +4031,7 @@ def km_mesh(params): op_menu("VIEW3D_MT_edit_mesh_normals", {"type": 'N', "value": 'PRESS', "alt" : True}), ("object.vertex_group_remove_from", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None), *_template_items_proportional_editing(connected=True), + op_menu("VIEW3D_MT_edit_mesh_context_menu", params.context_menu_event), ]) if params.use_mouse_emulate_3_button and params.select_mouse == 'LEFTMOUSE': @@ -4188,8 +4188,8 @@ def km_lattice(params): ("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), ("lattice.flip", {"type": 'F', "value": 'PRESS', "alt": True}, None), op_menu("VIEW3D_MT_hook", {"type": 'H', "value": 'PRESS', "ctrl": True}), - op_menu("VIEW3D_MT_edit_lattice_context_menu", params.context_menu_event), *_template_items_proportional_editing(connected=False), + op_menu("VIEW3D_MT_edit_lattice_context_menu", params.context_menu_event), ]) return keymap @@ -4225,7 +4225,6 @@ def km_particle(params): {"properties": [("data_path_primary", 'tool_settings.particle_edit.brush.size')]}), ("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True}, {"properties": [("data_path_primary", 'tool_settings.particle_edit.brush.strength')]}), - op_menu("VIEW3D_MT_particle_context_menu", params.context_menu_event), ("particle.weight_set", {"type": 'K', "value": 'PRESS', "shift": True}, None), *( (("wm.context_set_enum", @@ -4235,6 +4234,7 @@ def km_particle(params): ) ), *_template_items_proportional_editing(connected=False), + op_menu("VIEW3D_MT_particle_context_menu", params.context_menu_event), ]) return keymap @@ -5870,6 +5870,18 @@ def km_3d_view_tool_paint_gpencil_cutter(params): ) +def km_3d_view_tool_paint_gpencil_eyedropper(params): + return ( + "3D View Tool: Paint Gpencil, Eyedropper", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": [ + ("ui.eyedropper_gpencil_color", {"type": params.tool_mouse, "value": 'PRESS'}, None), + ("ui.eyedropper_gpencil_color", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None), + ("ui.eyedropper_gpencil_color", {"type": params.tool_mouse, "value": 'PRESS', "shift": True, "ctrl": True}, None), + ]}, + ) + + def km_3d_view_tool_edit_gpencil_select(params): return ( "3D View Tool: Edit Gpencil, Tweak", @@ -6207,6 +6219,7 @@ def generate_keymaps(params=None): km_3d_view_tool_paint_gpencil_arc(params), km_3d_view_tool_paint_gpencil_curve(params), km_3d_view_tool_paint_gpencil_cutter(params), + km_3d_view_tool_paint_gpencil_eyedropper(params), km_3d_view_tool_edit_gpencil_select(params), km_3d_view_tool_edit_gpencil_select_box(params), km_3d_view_tool_edit_gpencil_select_circle(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 5ce79936836..49a394b478d 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -1177,10 +1177,14 @@ def km_file_browser(params): ("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None), ("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, None), ("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None), + ("file.previous", {"type": 'BACK_SPACE', "value": 'PRESS'}, None), + ("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None), ("wm.context_toggle", {"type": 'H', "value": 'PRESS'}, {"properties": [("data_path", 'space_data.params.show_hidden')]}), ("file.directory_new", {"type": 'I', "value": 'PRESS'}, {"properties": [("confirm", False)]}), + ("file.rename", {"type": 'F2', "value": 'PRESS'}, None), + ("file.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None), ("wm.context_toggle", {"type": 'T', "value": 'PRESS'}, {"properties": [("data_path", 'space_data.show_region_toolbar')]}), @@ -1221,7 +1225,7 @@ def km_file_browser_main(params): ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True}, {"properties": [("extend", True)]}), ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True,}, - {"properties": [("extend", True), ("fill", True)]}), + {"properties": [("extend", True), ("fill", True), ("open", False)]}), ("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "shift": True}, {"properties": [("extend", True), ("open", False)]}), ("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "alt": True}, diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py index b052f333d2a..0cd90610cdc 100644 --- a/release/scripts/startup/bl_operators/userpref.py +++ b/release/scripts/startup/bl_operators/userpref.py @@ -114,7 +114,8 @@ class PREFERENCES_OT_copy_prev(Operator): shutil.copytree(self._old_path(), self._new_path(), symlinks=True) - # reload recent-files.txt + # reload preferences and recent-files.txt + bpy.ops.wm.read_userpref() bpy.ops.wm.read_history() # don't loose users work if they open the splash later. diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 2b20754a995..2befb7c73e2 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -565,7 +565,12 @@ def unwrap(operator, context, **kwargs): bpy.ops.object.mode_set(mode='OBJECT', toggle=False) # define list of meshes - meshes = list({me for obj in context.selected_objects if obj.type == 'MESH' for me in (obj.data,) if me.polygons and me.library is None}) + meshes = list({ + me for obj in context.selected_objects + if obj.type == 'MESH' + for me in (obj.data,) + if me.polygons and me.library is None + }) if not meshes: operator.report({'ERROR'}, "No mesh object") diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index cb9af88f45f..5a6db45c329 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1107,7 +1107,7 @@ class WM_OT_doc_view(Operator): bl_label = "View Documentation" doc_id: doc_id - if bpy.app.version_cycle in {"release", "rc"}: + 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)) else: @@ -1999,7 +1999,6 @@ class WM_OT_batch_rename(Operator): descr, ) - return data @staticmethod @@ -2042,7 +2041,7 @@ class WM_OT_batch_rename(Operator): if action.use_replace_regex_dst: replace_dst = action.replace_dst else: - replace_dst = re.escape(action.replace_dst) + replace_dst = action.replace_dst.replace("\\", "\\\\") else: replace_src = re.escape(action.replace_src) replace_dst = re.escape(action.replace_dst) diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index b589f780c24..d1975919d7e 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -332,7 +332,8 @@ class DATA_PT_font(CurveButtonsPanelText, Panel): layout = self.layout text = context.curve - char = context.curve.edit_format + char = text.edit_format + mode = context.mode row = layout.split(factor=0.25) row.label(text="Regular") @@ -347,13 +348,14 @@ class DATA_PT_font(CurveButtonsPanelText, Panel): row.label(text="Bold & Italic") row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink") - layout.separator() + if mode == 'EDIT_TEXT': + layout.separator() - row = layout.row(align=True) - row.prop(char, "use_bold", toggle=True) - row.prop(char, "use_italic", toggle=True) - row.prop(char, "use_underline", toggle=True) - row.prop(char, "use_small_caps", toggle=True) + row = layout.row(align=True) + row.prop(char, "use_bold", toggle=True) + row.prop(char, "use_italic", toggle=True) + row.prop(char, "use_underline", toggle=True) + row.prop(char, "use_small_caps", toggle=True) class DATA_PT_font_transform(CurveButtonsPanelText, Panel): diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 51f24007271..72e9f710e9d 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -485,6 +485,7 @@ class DATA_PT_remesh(MeshButtonsPanel, Panel): else: col.operator("object.quadriflow_remesh", text="QuadriFlow Remesh") + class DATA_PT_customdata(MeshButtonsPanel, Panel): bl_label = "Geometry Data" bl_options = {'DEFAULT_CLOSED'} 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 ca9c518f443..e545ee971d8 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -950,6 +950,7 @@ class GPENCIL_UL_layer(UIList): icon_value=icon, ) + class GreasePencilSimplifyPanel: def draw_header(self, context): @@ -977,6 +978,7 @@ class GreasePencilSimplifyPanel: sub.active = rd.simplify_gpencil_view_fill sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines") + classes = ( GPENCIL_MT_pie_tool_palette, GPENCIL_MT_pie_settings_palette, diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 23b2556eddb..83f7cb710ff 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -367,7 +367,7 @@ def brush_basic_sculpt_settings(layout, context, brush, *, compact=False): layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {})) -def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True): +def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact=True, is_toolbar=False): gp_settings = brush.gpencil_settings # Brush details @@ -395,6 +395,23 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True) row = layout.row(align=True) row.prop(gp_settings, "fill_draw_mode", text="Boundary") row.prop(gp_settings, "show_fill_boundary", text="", icon='GRID') + # Fill options + if is_toolbar: + settings = _context.tool_settings.gpencil_sculpt + row = layout.row(align=True) + sub = row.row(align=True) + sub.popover( + panel="TOPBAR_PT_gpencil_fill", + text="Fill Options", + ) + else: + row = layout.row(align=True) + row.prop(gp_settings, "fill_factor", text="Resolution") + if gp_settings.fill_draw_mode != 'STROKE': + row = layout.row(align=True) + row.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes") + row = layout.row(align=True) + row.prop(gp_settings, "fill_threshold", text="Threshold") else: # brush.gpencil_tool == 'DRAW': row = layout.row(align=True) row.prop(brush, "size", text="Radius") @@ -403,6 +420,25 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True) row.prop(gp_settings, "pen_strength", slider=True) row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') + if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle"}: + settings = _context.tool_settings.gpencil_sculpt + if is_toolbar: + row = layout.row(align=True) + row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA') + sub = row.row(align=True) + sub.active = settings.use_thickness_curve + sub.popover( + panel="TOPBAR_PT_gpencil_primitive", + text="Thickness Profile", + ) + else: + row = layout.row(align=True) + row.prop(settings, "use_thickness_curve", text="Use Thickness Profile") + sub = row.row(align=True) + if settings.use_thickness_curve: + # Curve + layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True) + def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False): tool_settings = context.tool_settings diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index a322b96f9dd..181032e4d96 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -158,7 +158,8 @@ class FILEBROWSER_PT_filter(Panel): def panel_poll_is_upper_region(region): - # The upper region is left-aligned, the lower is split into it then. Note that after "Flip Regions" it's right-aligned. + # The upper region is left-aligned, the lower is split into it then. + # Note that after "Flip Regions" it's right-aligned. return region.alignment in {'LEFT', 'RIGHT'} @@ -469,7 +470,12 @@ class FILEBROWSER_MT_context_menu(Menu): layout.separator() layout.operator("file.rename", text="Rename") - # layout.operator("file.delete") + sub = layout.row() + sub.operator_context = 'EXEC_DEFAULT' + sub.operator("file.delete", text="Delete") + + layout.separator() + sub = layout.row() sub.operator_context = 'EXEC_DEFAULT' sub.operator("file.directory_new", text="New Folder") @@ -503,5 +509,6 @@ classes = ( if __name__ == "__main__": # only for live edit. from bpy.utils import register_class + for cls in classes: register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 0f926e596de..2ce81ba8359 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -373,6 +373,12 @@ class NODE_PT_material_slots(Panel): col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP' col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN' + if ob.mode == 'EDIT': + row = layout.row(align=True) + row.operator("object.material_slot_assign", text="Assign") + row.operator("object.material_slot_select", text="Select") + row.operator("object.material_slot_deselect", text="Deselect") + class NODE_PT_node_color_presets(PresetPanel, Panel): """Predefined node color""" @@ -412,6 +418,9 @@ class NODE_MT_context_menu(Menu): # If something is selected layout.operator_context = 'INVOKE_DEFAULT' layout.operator("node.duplicate_move") + props = layout.operator("wm.call_panel", text="Rename...") + props.name = "TOPBAR_PT_name" + props.keep_open = False layout.operator("node.delete") layout.operator("node.clipboard_copy", text="Copy") layout.operator("node.clipboard_paste", text="Paste") diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index a942b8769cf..cdac91b8014 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -741,6 +741,9 @@ class SEQUENCER_MT_context_menu(Menu): layout.operator("sequencer.copy", text="Copy", icon='COPYDOWN') layout.operator("sequencer.paste", text="Paste", icon='PASTEDOWN') layout.operator("sequencer.duplicate_move") + props = layout.operator("wm.call_panel", text="Rename...") + props.name = "TOPBAR_PT_name" + props.keep_open = False layout.operator("sequencer.delete", text="Delete...") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index aa5be13c01b..890250d3daf 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1320,7 +1320,7 @@ class _defs_gpencil_paint: icon_prefix="brush.gpencil_draw.", type=bpy.types.Brush, attr="gpencil_tool", - cursor='PAINT_CROSS', + cursor='DOT', tooldef_keywords=dict( operator="gpencil.draw", ), @@ -1392,6 +1392,17 @@ class _defs_gpencil_paint: keymap=(), ) + @ToolDef.from_fn + def eyedropper(): + return dict( + idname="builtin.eyedropper", + label="Eyedropper", + icon="ops.paint.weight_sample", + cursor='EYEDROPPER', + widget=None, + keymap=(), + ) + class _defs_gpencil_edit: @ToolDef.from_fn @@ -2044,6 +2055,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): _defs_gpencil_paint.generate_from_brushes, _defs_gpencil_paint.cutter, None, + _defs_gpencil_paint.eyedropper, + None, _defs_gpencil_paint.line, _defs_gpencil_paint.arc, _defs_gpencil_paint.curve, diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index be41fb52118..4c90f987c50 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -569,6 +569,7 @@ class USERPREF_PT_animation_fcurves(PreferencePanel, Panel): flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) flow.prop(edit, "fcurve_unselected_alpha", text="F-Curve Visibility") + flow.prop(edit, "fcurve_new_auto_smoothing", text="Default Smoothing Mode") flow.prop(edit, "keyframe_new_interpolation_type", text="Default Interpolation") flow.prop(edit, "keyframe_new_handle_type", text="Default Handles") flow.prop(edit, "use_insertkey_xyz_to_rgb", text="XYZ to RGB") @@ -1479,12 +1480,17 @@ class USERPREF_PT_input_mouse(PreferencePanel, Panel): return (prefs.active_section == 'INPUT') def draw_props(self, context, layout): + import sys 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, "use_mouse_emulate_3_button") + if sys.platform[:3] != "win": + rowsub = flow.row() + rowsub.active = inputs.use_mouse_emulate_3_button + rowsub.prop(inputs, "mouse_emulate_3_button_modifier") flow.prop(inputs, "use_mouse_continuous") flow.prop(inputs, "use_drag_immediately") flow.prop(inputs, "mouse_double_click_time", text="Double Click Speed") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index aca8ea701ce..93d480ba306 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -351,28 +351,7 @@ class _draw_tool_settings_context_mode: from bl_ui.properties_paint_common import ( brush_basic_gpencil_paint_settings, ) - brush_basic_gpencil_paint_settings(layout, context, brush, compact=True) - - # FIXME: tools must use their own UI drawing! - if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle"}: - settings = context.tool_settings.gpencil_sculpt - row = layout.row(align=True) - row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA') - sub = row.row(align=True) - sub.active = settings.use_thickness_curve - sub.popover( - panel="TOPBAR_PT_gpencil_primitive", - text="Thickness Profile", - ) - - if brush.gpencil_tool == 'FILL': - settings = context.tool_settings.gpencil_sculpt - row = layout.row(align=True) - sub = row.row(align=True) - sub.popover( - panel="TOPBAR_PT_gpencil_fill", - text="Fill Options", - ) + brush_basic_gpencil_paint_settings(layout, context, brush, tool, compact=True, is_toolbar=True) @staticmethod def SCULPT_GPENCIL(context, layout, tool): @@ -707,10 +686,18 @@ class VIEW3D_HT_header(Header): row = layout.row() row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'}) - if shading.type == 'WIREFRAME': - row.prop(shading, "show_xray_wireframe", text="", icon='XRAY') - else: - row.prop(shading, "show_xray", text="", icon='XRAY') + # While exposing 'shading.show_xray(_wireframe)' is correct. + # this hides the key shortcut from users: T70433. + row.operator( + "view3d.toggle_xray", + text="", + icon='XRAY', + depress=getattr( + shading, + "show_xray_wireframe" if shading.type == 'WIREFRAME' else + "show_xray" + ), + ) row = layout.row(align=True) row.prop(shading, "type", text="", expand=True) @@ -794,6 +781,8 @@ class VIEW3D_MT_editor_menus(Menu): elif obj: if mode_string != 'PAINT_TEXTURE': layout.menu("VIEW3D_MT_%s" % mode_string.lower()) + if mode_string == 'SCULPT': + layout.menu("VIEW3D_MT_mask") else: layout.menu("VIEW3D_MT_object") @@ -2822,20 +2811,29 @@ class VIEW3D_MT_sculpt(Menu): props.action = 'SHOW' props.area = 'ALL' - props = layout.operator("paint.hide_show", text="Hide Bounding Box") - props.action = 'HIDE' - props.area = 'INSIDE' - props = layout.operator("paint.hide_show", text="Show Bounding Box") props.action = 'SHOW' props.area = 'INSIDE' + props = layout.operator("paint.hide_show", text="Hide Bounding Box") + props.action = 'HIDE' + props.area = 'INSIDE' + props = layout.operator("paint.hide_show", text="Hide Masked") props.action = 'HIDE' props.area = 'MASKED' layout.separator() + layout.menu("VIEW3D_MT_sculpt_set_pivot", text="Set Pivot") + + +class VIEW3D_MT_mask(Menu): + bl_label = "Mask" + + def draw(self, _context): + layout = self.layout + props = layout.operator("paint.mask_flood_fill", text="Invert Mask") props.mode = 'INVERT' @@ -2898,9 +2896,6 @@ class VIEW3D_MT_sculpt(Menu): props = layout.operator("sculpt.dirty_mask", text='Dirty Mask') - layout.separator() - layout.menu("VIEW3D_MT_sculpt_set_pivot", text="Set Pivot") - class VIEW3D_MT_sculpt_set_pivot(Menu): bl_label = "Sculpt Set Pivot" @@ -5070,11 +5065,8 @@ class VIEW3D_PT_collections(Panel): if not use_local_collections: subrow.active = collection.is_visible # Parent collection runtime visibility subrow.prop(child, "hide_viewport", text="", emboss=False) - elif not child.is_visible: - subrow.active = False - subrow.label(text="", icon='REMOVE') else: - subrow.active = collection.visible_get() # Parent collection runtime visibility + subrow.active = collection.visible_get() # Parent collection runtime visibility icon = 'HIDE_OFF' if child.visible_get() else 'HIDE_ON' props = subrow.operator("object.hide_collection", text="", icon=icon, emboss=False) props.collection_index = index @@ -6808,6 +6800,7 @@ classes = ( VIEW3D_MT_paint_weight, VIEW3D_MT_sculpt, VIEW3D_MT_sculpt_set_pivot, + VIEW3D_MT_mask, VIEW3D_MT_particle, VIEW3D_MT_particle_context_menu, VIEW3D_MT_particle_showhide, diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 3aee14e0239..8da5ba67187 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1873,7 +1873,8 @@ class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel): from bl_ui.properties_paint_common import ( brush_basic_gpencil_paint_settings, ) - brush_basic_gpencil_paint_settings(layout, context, brush, compact=True) + tool = context.workspace.tools.from_space_view3d_mode(context.mode, create=False) + brush_basic_gpencil_paint_settings(layout, context, brush, tool, compact=True, is_toolbar=False) # Grease Pencil drawing brushes options diff --git a/release/scripts/templates_py/operator_mesh_add.py b/release/scripts/templates_py/operator_mesh_add.py index d3df64a5501..01a9ad6160e 100644 --- a/release/scripts/templates_py/operator_mesh_add.py +++ b/release/scripts/templates_py/operator_mesh_add.py @@ -2,6 +2,7 @@ import bpy import bmesh from bpy_extras.object_utils import AddObjectHelper + def add_box(width, height, depth): """ This function takes inputs and returns vertex and face arrays. @@ -77,16 +78,16 @@ class AddBox(bpy.types.Operator): # generic transform props align_items = ( - ('WORLD', "World", "Align the new object to the world"), - ('VIEW', "View", "Align the new object to the view"), - ('CURSOR', "3D Cursor", "Use the 3D cursor orientation for the new object") + ('WORLD', "World", "Align the new object to the world"), + ('VIEW', "View", "Align the new object to the view"), + ('CURSOR', "3D Cursor", "Use the 3D cursor orientation for the new object") ) align: EnumProperty( - name="Align", - items=align_items, - default='WORLD', - update=AddObjectHelper.align_update_callback, - ) + name="Align", + items=align_items, + default='WORLD', + update=AddObjectHelper.align_update_callback, + ) location: FloatVectorProperty( name="Location", subtype='TRANSLATION', diff --git a/release/scripts/templates_py/operator_modal_draw.py b/release/scripts/templates_py/operator_modal_draw.py index 5dc72c36a8f..1e185ecfe2b 100644 --- a/release/scripts/templates_py/operator_modal_draw.py +++ b/release/scripts/templates_py/operator_modal_draw.py @@ -4,6 +4,7 @@ import blf import gpu from gpu_extras.batch import batch_for_shader + def draw_callback_px(self, context): print("mouse points", len(self.mouse_path)) diff --git a/release/scripts/templates_py/ui_tool_simple.py b/release/scripts/templates_py/ui_tool_simple.py index afda5088e69..fc239093b9c 100644 --- a/release/scripts/templates_py/ui_tool_simple.py +++ b/release/scripts/templates_py/ui_tool_simple.py @@ -3,9 +3,10 @@ import bpy from bpy.types import WorkSpaceTool + class MyTool(WorkSpaceTool): - bl_space_type='VIEW_3D' - bl_context_mode='OBJECT' + bl_space_type = 'VIEW_3D' + bl_context_mode = 'OBJECT' # The prefix of the idname should be your add-on name. bl_idname = "my_template.my_circle_select" @@ -30,8 +31,8 @@ class MyTool(WorkSpaceTool): class MyOtherTool(WorkSpaceTool): - bl_space_type='VIEW_3D' - bl_context_mode='OBJECT' + bl_space_type = 'VIEW_3D' + bl_context_mode = 'OBJECT' bl_idname = "my_template.my_other_select" bl_label = "My Lasso Tool Select" @@ -56,9 +57,11 @@ def register(): bpy.utils.register_tool(MyTool, after={"builtin.scale_cage"}, separator=True, group=True) bpy.utils.register_tool(MyOtherTool, after={MyTool.bl_idname}) + def unregister(): bpy.utils.unregister_tool(MyTool) bpy.utils.unregister_tool(MyOtherTool) + if __name__ == "__main__": register() diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index 69a376d00b0..a69178281ff 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -53,6 +53,7 @@ extern "C" { #include "BKE_anim.h" #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_modifier.h" diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 868c5a69593..b7139d5bbf6 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -212,8 +212,8 @@ void what_does_obaction(struct Object *ob, float cframe); /* for proxy */ -void BKE_pose_copyesult_pchan_result(struct bPoseChannel *pchanto, - const struct bPoseChannel *pchanfrom); +void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto, + const struct bPoseChannel *pchanfrom); bool BKE_pose_copy_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void BKE_pose_rest(struct bPose *pose); diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index e55cb69a5c6..b35abb1ecef 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -91,5 +91,6 @@ enum { #define BLENDER_QUIT_FILE "quit.blend" #define BLENDER_BOOKMARK_FILE "bookmarks.txt" #define BLENDER_HISTORY_FILE "recent-files.txt" +#define BLENDER_PLATFORM_SUPPORT_FILE "platform_support.txt" #endif /* __BKE_APPDIR_H__ */ diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 21ef70b7bcd..9bd90f76b79 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -26,8 +26,8 @@ * * \note Use #STRINGIFY() rather than defining with quotes. */ -#define BLENDER_VERSION 281 -#define BLENDER_SUBVERSION 12 +#define BLENDER_VERSION 282 +#define BLENDER_SUBVERSION 0 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 891247f8127..70741831727 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -31,7 +31,6 @@ struct Main; struct Scene; struct ToolSettings; struct UnifiedPaintSettings; -struct bContext; // enum eCurveMappingPreset; diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h index e86408076cd..7c8a9452023 100644 --- a/source/blender/blenkernel/BKE_editmesh_bvh.h +++ b/source/blender/blenkernel/BKE_editmesh_bvh.h @@ -72,8 +72,8 @@ struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree, float *r_dist, float r_hitout[3], float r_cagehit[3], - BMBVHTree_FaceFilter filter, - void *filter_cb); + BMBVHTree_FaceFilter filter_cb, + void *filter_userdata); /* find a vert closest to co in a sphere of radius dist_max */ struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree, diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index 918f85d146c..9cbc7d05ac2 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -261,12 +261,6 @@ typedef struct GpencilModifierTypeInfo { struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); - - /** - * Get the number of times the strokes are duplicated in this modifier. - * This is used to calculate the size of the GPU VBOs - */ - int (*getDuplicationFactor)(struct GpencilModifierData *md); } GpencilModifierTypeInfo; /* Initialize modifier's global data (type info and some common global storages). */ diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 234b74eece3..82c831ae8e0 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -309,11 +309,11 @@ void BKE_image_get_aspect(struct Image *image, float *aspx, float *aspy); /* image_gen.c */ void BKE_image_buf_fill_color( unsigned char *rect, float *rect_float, int width, int height, const float color[4]); -void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int height, int width); +void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height); void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, - int height, - int width); + int width, + int height); /* Cycles hookup */ unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 535980840c1..19eb40debe6 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -114,11 +114,13 @@ void BKE_base_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, bool extend); -void BKE_layer_collection_isolate(struct Scene *scene, - struct ViewLayer *view_layer, - struct LayerCollection *lc, - bool extend); -void BKE_layer_collection_local_isolate(struct ViewLayer *view_layer, +bool BKE_base_is_visible(const struct View3D *v3d, const struct Base *base); +bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob); +void BKE_layer_collection_isolate_global(struct Scene *scene, + struct ViewLayer *view_layer, + struct LayerCollection *lc, + bool extend); +void BKE_layer_collection_isolate_local(struct ViewLayer *view_layer, struct View3D *v3d, struct LayerCollection *lc, bool extend); diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h index cc4a3a01892..86c094b8a6d 100644 --- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h +++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h @@ -43,7 +43,8 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh); struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size, - float adaptivity); + float adaptivity, + float isovalue); struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh, int target_faces, int seed, diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index b2bc30c107c..0977a406aa0 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -48,7 +48,9 @@ typedef enum { */ eModifierTypeType_OnlyDeform, + /* Modifier adds geometry. */ eModifierTypeType_Constructive, + /* Modifier can add and remove geometry. */ eModifierTypeType_Nonconstructive, /* both deformVerts & applyModifier are valid calls @@ -380,6 +382,7 @@ struct Object *modifiers_isDeformedByArmature(struct Object *ob); struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob); struct Object *modifiers_isDeformedByLattice(struct Object *ob); struct Object *modifiers_isDeformedByCurve(struct Object *ob); +bool modifiers_usesMultires(struct Object *ob); bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm); bool modifiers_usesSubsurfFacedots(struct Scene *scene, struct Object *ob); bool modifiers_isCorrectableDeformed(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 06fd7915476..a5b9b1e5148 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -594,7 +594,8 @@ void nodeChainIter(const bNodeTree *ntree, void nodeChainIterBackwards(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *), - void *userdata); + void *userdata, + int recursion_lvl); void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata); struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 8580aefcfbc..4413ad2a70f 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -220,7 +220,7 @@ typedef struct SculptSession { struct MPoly *mpoly; struct MLoop *mloop; int totvert, totpoly; - struct KeyBlock *kb; + struct KeyBlock *shapekey_active; float *vmask; /* Mesh connectivity */ @@ -243,10 +243,10 @@ typedef struct SculptSession { bool show_mask; /* Painting on deformed mesh */ - bool modifiers_active; /* object is deformed with some modifiers */ - float (*orig_cos)[3]; /* coords of undeformed mesh */ - float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */ - float (*deform_imats)[3][3]; /* crazyspace deformation matrices */ + bool deform_modifiers_active; /* object is deformed with some modifiers */ + float (*orig_cos)[3]; /* coords of undeformed mesh */ + float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */ + float (*deform_imats)[3][3]; /* crazyspace deformation matrices */ /* Used to cache the render of the active texture */ unsigned int texcache_side, *texcache, texcache_actual; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index dedf76ee839..13adb868c01 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -28,6 +28,10 @@ /* For embedding CCGKey in iterator. */ #include "BKE_ccg.h" +#ifdef __cplusplus +extern "C" { +#endif + struct BMLog; struct BMesh; struct CCGElem; @@ -36,6 +40,7 @@ struct CustomData; struct DMFlagMat; struct GPU_PBVH_Buffers; struct IsectRayPrecalc; +struct Mesh; struct MLoop; struct MLoopTri; struct MPoly; @@ -44,6 +49,7 @@ struct PBVH; struct PBVHNode; struct SubdivCCG; struct TaskParallelSettings; +struct TaskParallelTLS; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; @@ -89,6 +95,7 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float PBVH *BKE_pbvh_new(void); void BKE_pbvh_build_mesh(PBVH *bvh, + const struct Mesh *mesh, const struct MPoly *mpoly, const struct MLoop *mloop, struct MVert *verts, @@ -430,14 +437,39 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node); -void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, - bool use_threading, - int totnode); - // void BKE_pbvh_node_BB_reset(PBVHNode *node); // void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]); bool pbvh_has_mask(PBVH *bvh); void pbvh_show_mask_set(PBVH *bvh, bool show_mask); +/* Parallelization */ +typedef void (*PBVHParallelRangeFunc)(void *__restrict userdata, + const int iter, + const struct TaskParallelTLS *__restrict tls); +typedef void (*PBVHParallelReduceFunc)(const void *__restrict userdata, + void *__restrict chunk_join, + void *__restrict chunk); + +typedef struct PBVHParallelSettings { + bool use_threading; + void *userdata_chunk; + size_t userdata_chunk_size; + PBVHParallelReduceFunc func_reduce; +} PBVHParallelSettings; + +void BKE_pbvh_parallel_range_settings(struct PBVHParallelSettings *settings, + bool use_threading, + int totnode); + +void BKE_pbvh_parallel_range(const int start, + const int stop, + void *userdata, + PBVHParallelRangeFunc func, + const struct PBVHParallelSettings *settings); + +#ifdef __cplusplus +} +#endif + #endif /* __BKE_PBVH_H__ */ diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index 4c023f54e04..b4c440d54a6 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -103,8 +103,14 @@ bool BKE_rigidbody_add_object(struct Main *bmain, int type, struct ReportList *reports); void BKE_rigidbody_ensure_local_object(struct Main *bmain, struct Object *ob); -void BKE_rigidbody_remove_object(struct Main *bmain, struct Scene *scene, struct Object *ob); -void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob); +void BKE_rigidbody_remove_object(struct Main *bmain, + struct Scene *scene, + struct Object *ob, + const bool free_us); +void BKE_rigidbody_remove_constraint(struct Main *bmain, + struct Scene *scene, + struct Object *ob, + const bool free_us); /* -------------- */ /* Utility Macros */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 846b8d21f28..51abc7390b8 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -75,7 +75,10 @@ void BKE_scene_free(struct Scene *sce); void BKE_scene_init(struct Scene *sce); struct Scene *BKE_scene_add(struct Main *bmain, const char *name); -void BKE_scene_remove_rigidbody_object(struct Main *bmain, struct Scene *scene, struct Object *ob); +void BKE_scene_remove_rigidbody_object(struct Main *bmain, + struct Scene *scene, + struct Object *ob, + const bool free_us); bool BKE_scene_object_find(struct Scene *scene, struct Object *ob); struct Object *BKE_scene_object_find_by_name(struct Scene *scene, const char *name); @@ -122,7 +125,7 @@ struct Scene *BKE_scene_find_from_collection(const struct Main *bmain, #ifdef DURIAN_CAMERA_SWITCH struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH #endif -int BKE_scene_camera_switch_update(struct Scene *scene); +bool BKE_scene_camera_switch_update(struct Scene *scene); char *BKE_scene_find_marker_name(struct Scene *scene, int frame); char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 16f766ae8bb..a5b223a73f2 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -351,6 +351,7 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa void BKE_sequencer_prefetch_stop(struct Scene *scene); void BKE_sequencer_prefetch_free(struct Scene *scene); bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene); +bool BKE_sequencer_prefetch_job_is_running(struct Scene *scene); void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end); SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context); struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq, diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index e235193a486..409a0d1232b 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -92,6 +92,14 @@ typedef struct SubdivToCCGSettings { bool need_mask; } SubdivToCCGSettings; +typedef struct SubdivCCGCoord { + /* Index of the grid within SubdivCCG::grids array. */ + int grid_index; + + /* Coordinate within the grid. */ + short x, y; +} SubdivCCGCoord; + /* This is actually a coarse face, which consists of multiple CCG grids. */ typedef struct SubdivCCGFace { /* Total number of grids in this face. @@ -106,20 +114,16 @@ typedef struct SubdivCCGFace { /* Definition of an edge which is adjacent to at least one of the faces. */ typedef struct SubdivCCGAdjacentEdge { int num_adjacent_faces; - /* Indexed by adjacent face index. */ - SubdivCCGFace **faces; /* Indexed by adjacent face index, then by point index on the edge. - * points to a grid element. */ - struct CCGElem ***boundary_elements; + * points to a coordinate into the grids. */ + struct SubdivCCGCoord **boundary_coords; } SubdivCCGAdjacentEdge; /* Definition of a vertex which is adjacent to at least one of the faces. */ typedef struct SubdivCCGAdjacentVertex { int num_adjacent_faces; - /* Indexed by adjacent face index. */ - SubdivCCGFace **faces; - /* Indexed by adjacent face index, points to a grid element. */ - struct CCGElem **corner_elements; + /* Indexed by adjacent face index, points to a coordinate in the grids. */ + struct SubdivCCGCoord *corner_coords; } SubdivCCGAdjacentVertex; /* Representation of subdivision surface which uses CCG grids. */ @@ -135,6 +139,9 @@ typedef struct SubdivCCG { /* Resolution of grid. All grids have matching resolution, and resolution * is same as ptex created for non-quad polygons. */ int grid_size; + /* Size of a single element of a grid (including coordinate and all the other layers). + * Measured in bytes. */ + int grid_element_size; /* Grids represent limit surface, with displacement applied. Grids are * corresponding to face-corners of coarse mesh, each grid has * grid_size^2 elements. @@ -255,4 +262,40 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, int *r_num_faces, int *r_num_loops); +typedef struct SubdivCCGNeighbors { + SubdivCCGCoord *coords; + int size; + int num_duplicates; + + SubdivCCGCoord coords_fixed[256]; +} SubdivCCGNeighbors; + +void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord); +bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord); + +/* CCG element neighbors. + * + * Neighbors are considered: + * + * - For an inner elements of a grid other elements which are sharing same row or column (4 + * neighbor elements in total). + * + * - For the corner element a single neighboring element on every adjacent edge, single from + * every gird. + * + * - For the boundary element two neighbor elements on the boundary (from same grid) and one + * element inside of every neighboring grid. */ + +/* Get actual neighbors of the given coordinate. + * + * SubdivCCGNeighbors.neighbors must be freed if it is not equal to + * SubdivCCGNeighbors.fixed_neighbors. + * + * If include_duplicates is true, vertices in other grids that match + * the current vertex are added at the end of the coords array. */ +void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors); + #endif /* __BKE_SUBDIV_CCG_H__ */ diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 65aa43ced7c..98a94c5f689 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -78,6 +78,7 @@ void txt_delete_selected(struct Text *text); void txt_sel_all(struct Text *text); void txt_sel_clear(struct Text *text); void txt_sel_line(struct Text *text); +void txt_sel_set(struct Text *text, int startl, int startc, int endl, int endc); char *txt_sel_to_buf(struct Text *text, int *r_buf_strlen); void txt_insert_buf(struct Text *text, const char *in_buffer); void txt_split_curline(struct Text *text); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 47b44c3828a..ec4246f5dba 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -183,6 +183,7 @@ set(SRC intern/particle_system.c intern/pbvh.c intern/pbvh_bmesh.c + intern/pbvh_parallel.cc intern/pointcache.c intern/report.c intern/rigidbody.c @@ -637,6 +638,14 @@ if(WITH_QUADRIFLOW) add_definitions(-DWITH_QUADRIFLOW) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) +endif() + ## Warnings as errors, this is too strict! #if(MSVC) # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 4849d631493..2f61cfcbc15 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1952,7 +1952,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph, const CustomData_MeshMasks *dataMask) { /* This function isn't thread-safe and can't be used during evaluation. */ - BLI_assert(DEG_debug_is_evaluating(depsgraph) == false); + BLI_assert(DEG_is_evaluating(depsgraph) == false); /* Evaluated meshes aren't supposed to be created on original instances. If you do, * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */ @@ -1985,7 +1985,7 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, const CustomData_MeshMasks *dataMask) { /* This function isn't thread-safe and can't be used during evaluation. */ - BLI_assert(DEG_debug_is_evaluating(depsgraph) == false); + BLI_assert(DEG_is_evaluating(depsgraph) == false); /* Evaluated meshes aren't supposed to be created on original instances. If you do, * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index d072a0aa599..de1cbd236fb 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1472,7 +1472,7 @@ void BKE_pose_rest(bPose *pose) } } -void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom) +void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom) { copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat); copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat); @@ -1523,7 +1523,7 @@ bool BKE_pose_copy_result(bPose *to, bPose *from) for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) { pchanto = BKE_pose_channel_find_name(to, pchanfrom->name); if (pchanto != NULL) { - BKE_pose_copyesult_pchan_result(pchanto, pchanfrom); + BKE_pose_copy_pchan_result(pchanto, pchanfrom); } } return true; diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 00975976130..b6a2efb37b8 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -643,6 +643,10 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec } BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase)); + + if (object->proxy != NULL) { + object->proxy->proxy_from = object; + } } void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *object) @@ -905,7 +909,7 @@ void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, Object *object, pchan->name); return; } - BKE_pose_copyesult_pchan_result(pchan, pchan_from); + BKE_pose_copy_pchan_result(pchan, pchan_from); copy_dq_dq(&pchan->runtime.deform_dual_quat, &pchan_from->runtime.deform_dual_quat); BKE_pchan_bbone_segments_cache_copy(pchan, pchan_from); } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 4187dfa68ad..fe740f4898e 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -590,7 +590,10 @@ void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts) brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; /* Fill brush. */ - brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); + brush = BLI_findstring(&bmain->brushes, "Fill Area", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); + } brush->size = 20.0f; brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; @@ -618,7 +621,10 @@ void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts) brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; /* Soft Eraser brush. */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft"); + brush = BLI_findstring(&bmain->brushes, "Eraser Soft", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft"); + } brush->size = 30.0f; brush->gpencil_settings->draw_strength = 0.5f; brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); @@ -631,7 +637,10 @@ void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts) brush->gpencil_settings->era_thickness_f = 10.0f; /* Hard Eraser brush. */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard"); + brush = BLI_findstring(&bmain->brushes, "Eraser Hard", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard"); + } brush->size = 30.0f; brush->gpencil_settings->draw_strength = 1.0f; brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); @@ -643,7 +652,10 @@ void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts) brush->gpencil_tool = GPAINT_TOOL_ERASE; /* Point Eraser brush. */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point"); + brush = BLI_findstring(&bmain->brushes, "Eraser Point", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point"); + } brush->size = 30.0f; brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; @@ -652,7 +664,10 @@ void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts) brush->gpencil_tool = GPAINT_TOOL_ERASE; /* Stroke Eraser brush. */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke"); + brush = BLI_findstring(&bmain->brushes, "Eraser Stroke", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke"); + } brush->size = 30.0f; brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; @@ -909,6 +924,13 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_CLAY: br->flag |= BRUSH_FRONTFACE; break; + case SCULPT_TOOL_CLAY_STRIPS: + br->flag |= BRUSH_ACCUMULATE; + br->alpha = 0.7f; + br->normal_radius_factor = 1.7f; + br->curve_preset = BRUSH_CURVE_SPHERE; + br->spacing = 6; + break; case SCULPT_TOOL_CREASE: br->flag |= BRUSH_DIR_IN; br->alpha = 0.25; @@ -928,6 +950,7 @@ void BKE_brush_sculpt_reset(Brush *br) break; case SCULPT_TOOL_SNAKE_HOOK: br->alpha = 1.0f; + br->rake_factor = 1.0f; break; case SCULPT_TOOL_THUMB: br->size = 75; @@ -968,12 +991,12 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_INFLATE: case SCULPT_TOOL_BLOB: case SCULPT_TOOL_CREASE: - br->add_col[0] = 0.65f; - br->add_col[1] = 0.85f; - br->add_col[2] = 0.9f; - br->sub_col[0] = 0.65f; - br->sub_col[1] = 0.85f; - br->sub_col[2] = 0.9f; + br->add_col[0] = 0.5f; + br->add_col[1] = 0.7f; + br->add_col[2] = 0.875f; + br->sub_col[0] = 0.5f; + br->sub_col[1] = 0.7f; + br->sub_col[2] = 0.875f; break; case SCULPT_TOOL_SMOOTH: diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 63d58f7e32e..463cbd4f378 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -772,7 +772,7 @@ static int cloth_from_object( clmd->clothObject->old_solver_type = 255; clmd->clothObject->edgeset = NULL; } - else if (!clmd->clothObject) { + else { modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject"); return 0; } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index f2098cc2430..68a38c94ff7 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -773,7 +773,7 @@ static bool scene_collections_object_remove( bool removed = false; if (collection_skip == NULL) { - BKE_scene_remove_rigidbody_object(bmain, scene, ob); + BKE_scene_remove_rigidbody_object(bmain, scene, ob, free_us); } FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { @@ -1305,6 +1305,9 @@ bool BKE_collection_move(Main *bmain, BLI_ghash_free(view_layer_hash, NULL, NULL); + /* We need to sync it again to pass the correct flags to the collections objects. */ + BKE_main_collection_sync(bmain); + return true; } diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 6740fc985e9..fe834658689 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -355,7 +355,7 @@ static void crazyspace_init_verts_and_matrices(const Mesh *mesh, BLI_assert(num_verts == mesh->totvert); } -static bool crazyspace_modifier_supports_deform(ModifierData *md) +static bool crazyspace_modifier_supports_deform_matrices(ModifierData *md) { if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) { return true; @@ -364,6 +364,12 @@ static bool crazyspace_modifier_supports_deform(ModifierData *md) return (mti->type == eModifierTypeType_OnlyDeform); } +static bool crazyspace_modifier_supports_deform(ModifierData *md) +{ + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + return (mti->type == eModifierTypeType_OnlyDeform); +} + int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, Scene *scene, Object *object, @@ -391,13 +397,12 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData); for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { continue; } - if (mti->type == eModifierTypeType_OnlyDeform) { + if (crazyspace_modifier_supports_deform_matrices(md)) { + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (defmats == NULL) { /* NOTE: Evaluated object si re-set to its original undeformed * state. */ diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index cbd3c91acc7..46f6a604eaa 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -624,7 +624,7 @@ void BKE_displist_fill(ListBase *dispbase, static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase) { - const float z_up[3] = {0.0f, 0.0f, 1.0f}; + const float z_up[3] = {0.0f, 0.0f, -1.0f}; ListBase front, back; DispList *dl, *dlnew; float *fp, *fp1; @@ -703,7 +703,7 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis bevels_to_filledpoly(cu, dispbase); } else { - const float z_up[3] = {0.0f, 0.0f, 1.0f}; + const float z_up[3] = {0.0f, 0.0f, -1.0f}; BKE_displist_fill(dispbase, dispbase, z_up, false); } } @@ -1730,11 +1730,11 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, if (cu->bevobj && (cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) { if (a == 1) { fillBevelCap(nu, dlb, cur_data - 3 * dlb->nr, &bottom_capbase); - negate_v3_v3(bottom_no, bevp->dir); + copy_v3_v3(bottom_no, bevp->dir); } if (a == steps - 1) { fillBevelCap(nu, dlb, cur_data, &top_capbase); - copy_v3_v3(top_no, bevp->dir); + negate_v3_v3(top_no, bevp->dir); } } } diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 48c0258bf47..10499ae0b5c 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -821,7 +821,7 @@ static void fcm_noise_evaluate( FMod_Noise *data = (FMod_Noise *)fcm->data; float noise; - /* generate noise using good ol' Blender Noise + /* generate noise using good old Blender Noise * - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1 * with evaltime being an integer (which happens when evaluating on frame by frame basis) */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index b55635560be..250e6ff6a7b 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -397,6 +397,9 @@ static void build_underline(Curve *cu, copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f); copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f); + /* Used by curve extrusion. */ + bp[0].radius = bp[1].radius = bp[2].radius = bp[3].radius = 1.0f; + nu2->bp = bp; BLI_addtail(nubase, nu2); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f78833a0ebe..e885aa04881 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1397,6 +1397,7 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) bGPdata *gpd = ob->data; MDeformVert *dvert = NULL; const int def_nr = BLI_findindex(&ob->defbase, defgroup); + const int totgrp = BLI_listbase_count(&ob->defbase); /* Remove points data */ if (gpd) { @@ -1411,9 +1412,9 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) defvert_remove_group(dvert, dw); } else { - /* reorganize weights in other strokes */ - for (int g = 0; g < gps->dvert->totweight; g++) { - dw = &dvert->dw[g]; + /* Reorganize weights for other groups after deleted one. */ + for (int g = 0; g < totgrp; g++) { + dw = defvert_find_index(dvert, g); if ((dw != NULL) && (dw->def_nr > def_nr)) { dw->def_nr--; } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index bc682ffb8c8..332549c6b47 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -569,7 +569,7 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist char str[FILE_MAX], strtest[FILE_MAX]; STRNCPY(str, filepath); - BLI_path_abs(str, BKE_main_blendfile_path_from_global()); + BLI_path_abs(str, bmain->name); /* first search an identical filepath */ for (ima = bmain->images.first; ima; ima = ima->id.next) { @@ -5310,7 +5310,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) char str[FILE_MAX]; STRNCPY(str, iv->filepath); - BLI_path_abs(str, BKE_main_blendfile_path_from_global()); + BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); /* exists? */ file = BLI_open(str, O_BINARY | O_RDONLY, 0); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 9b18052ef1e..fd5b4b6e506 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -44,6 +44,7 @@ #include "DNA_object_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" +#include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" @@ -56,9 +57,10 @@ #include "MEM_guardedalloc.h" /* Set of flags which are dependent on a collection settings. */ -static const short g_base_collection_flags = (BASE_VISIBLE | BASE_SELECTABLE | - BASE_ENABLED_VIEWPORT | BASE_ENABLED_RENDER | - BASE_HOLDOUT | BASE_INDIRECT_ONLY); +static const short g_base_collection_flags = (BASE_VISIBLE_DEPSGRAPH | BASE_VISIBLE_VIEWLAYER | + BASE_SELECTABLE | BASE_ENABLED_VIEWPORT | + BASE_ENABLED_RENDER | BASE_HOLDOUT | + BASE_INDIRECT_ONLY); /* prototype */ static void object_bases_iterator_next(BLI_Iterator *iter, const int flag); @@ -735,9 +737,15 @@ static short layer_collection_sync(ViewLayer *view_layer, lc->runtime_flag = child_runtime_flag; } - if (((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) && + /* 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).*/ + if (child_restrict & COLLECTION_RESTRICT_VIEWPORT) { + lc->runtime_flag |= LAYER_COLLECTION_RESTRICT_VIEWPORT; + } + + if (((lc->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) == 0) && ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0)) { - lc->runtime_flag |= LAYER_COLLECTION_VISIBLE; + lc->runtime_flag |= LAYER_COLLECTION_VISIBLE_VIEW_LAYER; } /* Sync objects, except if collection was excluded. */ @@ -771,12 +779,12 @@ static short layer_collection_sync(ViewLayer *view_layer, } if ((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) { - base->flag_from_collection |= BASE_ENABLED_VIEWPORT; + base->flag_from_collection |= (BASE_ENABLED_VIEWPORT | BASE_VISIBLE_DEPSGRAPH); if ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0) { - base->flag_from_collection |= BASE_VISIBLE; - if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) { - base->flag_from_collection |= BASE_SELECTABLE; - } + base->flag_from_collection |= BASE_VISIBLE_VIEWLAYER; + } + if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) { + base->flag_from_collection |= BASE_SELECTABLE; } } @@ -974,7 +982,7 @@ bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerColle for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { Base *base = BKE_view_layer_base_find(view_layer, cob->ob); - if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE)) { + if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { return true; } } @@ -1026,6 +1034,60 @@ void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool BKE_layer_collection_sync(scene, view_layer); } +bool BKE_base_is_visible(const View3D *v3d, const Base *base) +{ + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { + return false; + } + + if (v3d == NULL) { + return base->flag & BASE_VISIBLE_VIEWLAYER; + } + + if ((v3d->localvd) && ((v3d->local_view_uuid & base->local_view_bits) == 0)) { + return false; + } + + if (((1 << (base->object->type)) & v3d->object_type_exclude_viewport) != 0) { + return false; + } + + if (v3d->flag & V3D_LOCAL_COLLECTIONS) { + return (v3d->local_collections_uuid & base->local_collections_bits) != 0; + } + + return base->flag & BASE_VISIBLE_VIEWLAYER; +} + +bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob) +{ + BLI_assert(v3d != NULL); + + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { + return false; + } + + if ((v3d->object_type_exclude_viewport & (1 << ob->type)) != 0) { + return false; + } + + if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + return false; + } + + if ((v3d->flag & V3D_LOCAL_COLLECTIONS) && + ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) { + return false; + } + + /* If not using local view or local collection the object may still be in a hidden collection. */ + if (((v3d->localvd) == NULL) && ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0)) { + return (ob->base_flag & BASE_VISIBLE_VIEWLAYER) != 0; + } + + return true; +} + static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag) { lc->flag |= flag; @@ -1050,13 +1112,13 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int * If the collection or any of its parents is disabled, make it enabled. * Don't change the children disable state though. */ -void BKE_layer_collection_isolate(Scene *scene, - ViewLayer *view_layer, - LayerCollection *lc, - bool extend) +void BKE_layer_collection_isolate_global(Scene *scene, + ViewLayer *view_layer, + LayerCollection *lc, + bool extend) { LayerCollection *lc_master = view_layer->layer_collections.first; - bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE); + bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER); if (!extend) { /* Hide all collections . */ @@ -1163,9 +1225,9 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d) /** * Isolate the collection locally * - * Same as BKE_layer_collection_local_isolate but for a viewport + * Same as BKE_layer_collection_isolate_local but for a viewport */ -void BKE_layer_collection_local_isolate(ViewLayer *view_layer, +void BKE_layer_collection_isolate_local(ViewLayer *view_layer, View3D *v3d, LayerCollection *lc, bool extend) @@ -1436,12 +1498,12 @@ static void objects_iterator_end(BLI_Iterator *iter) void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in) { - objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter) { - objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter) @@ -1478,7 +1540,7 @@ void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter) void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in) { - objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); if (iter->valid) { if (BKE_object_is_libdata((Object *)iter->current) == false) { // First object is valid (selectable and not libdata) -> all good. @@ -1495,7 +1557,7 @@ void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter) { // Search while there are objects and the one we have is not editable (editable = not libdata). do { - objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false); } @@ -1512,12 +1574,12 @@ void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter) void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in) { - objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter) { - object_bases_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED); + object_bases_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter) @@ -1617,7 +1679,8 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter)) /* Evaluation */ /* Applies object's restrict flags on top of flags coming from the collection - * and stores those in base->flag. BASE_VISIBLE is based on viewport visibility. */ + * and stores those in base->flag. BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility + * (i.e., restriction and local collection). */ void BKE_base_eval_flags(Base *base) { /* Apply collection flags. */ @@ -1640,7 +1703,7 @@ void BKE_base_eval_flags(Base *base) * can change these again, but for tools we always want the viewport * visibility to be in sync regardless if depsgraph was evaluated. */ if (!(base->flag & BASE_ENABLED_VIEWPORT) || (base->flag & BASE_HIDDEN)) { - base->flag &= ~(BASE_VISIBLE | BASE_SELECTABLE); + base->flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_VISIBLE_VIEWLAYER | BASE_SELECTABLE); } /* Deselect unselectable objects. */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 468d0e97ece..909db9c7b52 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1468,8 +1468,12 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori new_id->flag = (new_id->flag & ~copy_idflag_mask) | (id->flag & copy_idflag_mask); + /* We do not want any handling of usercount in code duplicating the data here, we do that all + * at once in id_copy_libmanagement_cb() at the end. */ + const int copy_data_flag = orig_flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + if (id->properties) { - new_id->properties = IDP_CopyProperty_ex(id->properties, flag); + new_id->properties = IDP_CopyProperty_ex(id->properties, copy_data_flag); } /* XXX Again... We need a way to control what we copy in a much more refined way. @@ -1488,10 +1492,9 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) { /* Note that even though horrors like root nodetrees are not in bmain, the actions they use * in their anim data *are* in bmain... super-mega-hooray. */ - int animdata_flag = orig_flag; - BLI_assert((animdata_flag & LIB_ID_COPY_ACTIONS) == 0 || - (animdata_flag & LIB_ID_CREATE_NO_MAIN) == 0); - iat->adt = BKE_animdata_copy(bmain, iat->adt, animdata_flag); + BLI_assert((copy_data_flag & LIB_ID_COPY_ACTIONS) == 0 || + (copy_data_flag & LIB_ID_CREATE_NO_MAIN) == 0); + iat->adt = BKE_animdata_copy(bmain, iat->adt, copy_data_flag); } else { iat->adt = NULL; diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index e03903c05e4..e6cfea6fb03 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -589,7 +589,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, (do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f, (do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f}; - const float zvec[3] = {0.0f, 0.0f, 1.0f}; + const float zvec[3] = {0.0f, 0.0f, -1.0f}; MaskLayer *masklay; unsigned int masklay_index; MemArena *sf_arena; diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c index 8419a72f97e..b93fe157f2a 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c @@ -295,7 +295,10 @@ Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh, return new_mesh; } -Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size, float adaptivity) +Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, + float voxel_size, + float adaptivity, + float isovalue) { Mesh *new_mesh = NULL; #ifdef WITH_OPENVDB @@ -304,7 +307,7 @@ Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size, float a OpenVDBTransform_create_linear_transform(xform, (double)voxel_size); level_set = BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(mesh, xform); new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain( - level_set, 0.0, (float)adaptivity, false); + level_set, (double)isovalue, (double)adaptivity, false); OpenVDBLevelSet_free(level_set); OpenVDBTransform_free(xform); #else @@ -444,6 +447,12 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh) } BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BMO_op_callf(bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "recalc_face_normals faces=%hf", + BM_ELEM_TAG); + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); Mesh *result = BKE_mesh_from_bmesh_nomain(bm, (&(struct BMeshToMeshParams){ diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index c8e75532075..fa03aec3e08 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -1619,6 +1619,12 @@ void BKE_mesh_calc_edges_loose(Mesh *mesh) for (int i = 0; i < mesh->totloop; i++, ml++) { mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE; } + med = mesh->medge; + for (int i = 0; i < mesh->totedge; i++, med++) { + if (med->flag & ME_LOOSEEDGE) { + med->flag |= ME_EDGEDRAW; + } + } } /** diff --git a/source/blender/blenkernel/intern/mirror.c b/source/blender/blenkernel/intern/mirror.c index c429b953015..02e0a2bb3b9 100644 --- a/source/blender/blenkernel/intern/mirror.c +++ b/source/blender/blenkernel/intern/mirror.c @@ -169,13 +169,13 @@ Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd, result = BKE_mesh_new_nomain_from_template( mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); - /*copy customdata to original geometry*/ + /* Copy custom-data to original geometry. */ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts); CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges); CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops); CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys); - /* Subsurf for eg won't have mesh data in the custom data arrays. + /* Subsurf for eg won't have mesh data in the custom-data arrays. * now add mvert/medge/mpoly layers. */ if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) { memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert); @@ -188,8 +188,8 @@ Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd, memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly); } - /* copy customdata to new geometry, - * copy from its self because this data may have been created in the checks above */ + /* Copy custom-data to new geometry, + * copy from its self because this data may have been created in the checks above. */ CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts); CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges); /* loops are copied later */ @@ -321,6 +321,12 @@ Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd, MLoopNorSpaceArray lnors_spacearr = {NULL}; float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__); + /* The transform matrix of a normal must be + * the transpose of inverse of transform matrix of the geometry... */ + float mtx_nor[4][4]; + invert_m4_m4(mtx_nor, mtx); + transpose_m4(mtx_nor); + /* calculate custom normals into loop_normals, then mirror first half into second half */ BKE_mesh_calc_normals_poly(result->mvert, @@ -361,7 +367,7 @@ Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd, mirrorj += mpmirror->totloop - (j - mp->loopstart); } copy_v3_v3(loop_normals[mirrorj], loop_normals[j]); - loop_normals[mirrorj][axis] = -loop_normals[j][axis]; + mul_m4_v3(mtx_nor, loop_normals[mirrorj]); BKE_lnor_space_custom_normal_to_data( lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]); } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 656ec50f31b..1c83bec17e5 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -761,6 +761,23 @@ Object *modifiers_isDeformedByCurve(Object *ob) return NULL; } +bool modifiers_usesMultires(Object *ob) +{ + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + MultiresModifierData *mmd = NULL; + + for (; md; md = md->next) { + if (md->type == eModifierType_Multires) { + mmd = (MultiresModifierData *)md; + if (mmd->totlvl != 0) { + return true; + } + } + } + return false; +} + bool modifiers_usesArmature(Object *ob, bArmature *arm) { VirtualModifierData virtualModifierData; diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index f67bc419210..9385a9ae24d 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -409,8 +409,8 @@ typedef struct MovieClipCache { /* cache for undistorted shot */ float principal[2]; - float polynomial_k1, polynomial_k2, polynomial_k3; - float division_k1, division_k2; + float polynomial_k1; + float division_k1; short distortion_model; bool undistortion_used; diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 2cc1083aba3..09581debd99 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1488,7 +1488,7 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) /* set default flags */ fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; /* store path - make copy, and store that */ fcu->rna_path = BLI_strdupn("influence", 9); @@ -1515,7 +1515,7 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) /* set default flags */ fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; /* store path - make copy, and store that */ fcu->rna_path = BLI_strdupn("strip_time", 10); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 0ef35bd3d06..779728cb037 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -950,7 +950,8 @@ void nodeChainIter(const bNodeTree *ntree, static void iter_backwards_ex(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *), - void *userdata) + void *userdata, + char recursion_mask) { LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) { bNodeLink *link = sock->link; @@ -961,18 +962,17 @@ static void iter_backwards_ex(const bNodeTree *ntree, /* Skip links marked as cyclic. */ continue; } - if (link->fromnode->iter_flag) { - /* Only iter on nodes once. */ + if (link->fromnode->iter_flag & recursion_mask) { continue; } else { - link->fromnode->iter_flag = 1; + link->fromnode->iter_flag |= recursion_mask; } if (!callback(link->fromnode, link->tonode, userdata)) { return; } - iter_backwards_ex(ntree, link->fromnode, callback, userdata); + iter_backwards_ex(ntree, link->fromnode, callback, userdata, recursion_mask); } } @@ -981,6 +981,8 @@ static void iter_backwards_ex(const bNodeTree *ntree, * \a callback for each node (which can return false to end iterator). * * Faster than nodeChainIter. Iter only once per node. + * Can be called recursively (using another nodeChainIterBackwards) by + * setting the recursion_lvl accordingly. * * \note Needs updated socket links (ntreeUpdateTree). * \note Recursive @@ -988,14 +990,23 @@ static void iter_backwards_ex(const bNodeTree *ntree, void nodeChainIterBackwards(const bNodeTree *ntree, const bNode *node_start, bool (*callback)(bNode *, bNode *, void *), - void *userdata) + void *userdata, + int recursion_lvl) { + if (!node_start) { + return; + } + + /* Limited by iter_flag type. */ + BLI_assert(recursion_lvl < 8); + char recursion_mask = (1 << recursion_lvl); + /* Reset flag. */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - node->iter_flag = 0; + node->iter_flag &= ~recursion_mask; } - iter_backwards_ex(ntree, node_start, callback, userdata); + iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask); } /** diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index f10930a2ba7..773e2d19b22 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -680,7 +680,7 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode) */ int BKE_object_visibility(const Object *ob, const int dag_eval_mode) { - if ((ob->base_flag & BASE_VISIBLE) == 0) { + if ((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return 0; } diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 01f3f2e309b..21ca5e6d6a6 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -439,10 +439,10 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph, * assumed viewport visibility. Select-ability does not matter here. */ if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) { if (base->flag & BASE_ENABLED_RENDER) { - base->flag |= BASE_VISIBLE; + base->flag |= BASE_VISIBLE_DEPSGRAPH; } else { - base->flag &= ~BASE_VISIBLE; + base->flag &= ~BASE_VISIBLE_DEPSGRAPH; } } diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index cc3b10b1207..5fa3352d497 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -267,11 +267,7 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose) } if (tot > 0) { - BKE_reportf(reports, - RPT_INFO, - tot == 1 ? "Packed %d file" : - "Packed %d files", - tot); + BKE_reportf(reports, RPT_INFO, "Packed %d file(s)", tot); } else if (verbose) { BKE_report(reports, RPT_INFO, "No new files have been packed"); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 983127372ca..cc9d1b98ba4 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -224,7 +224,6 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) return rna_enum_brush_image_tool_items; case PAINT_MODE_SCULPT_UV: return rna_enum_brush_uv_sculpt_tool_items; - return NULL; case PAINT_MODE_GPENCIL: return rna_enum_brush_gpencil_types_items; case PAINT_MODE_INVALID: @@ -1185,7 +1184,7 @@ static void sculpt_update_object( Mesh *me = BKE_object_get_original_mesh(ob); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); + ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0; ss->building_vp_handle = false; @@ -1206,7 +1205,7 @@ static void sculpt_update_object( /* tessfaces aren't used and will become invalid */ BKE_mesh_tessface_clear(me); - ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; + ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path, * so no extra checks is needed here. */ @@ -1241,14 +1240,15 @@ static void sculpt_update_object( pbvh_show_mask_set(ss->pbvh, ss->show_mask); - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { if (!ss->orig_cos) { int a; BKE_sculptsession_free_deformMats(ss); - ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : - BKE_mesh_vert_coords_alloc(me, NULL); + ss->orig_cos = (ss->shapekey_active) ? + BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active) : + BKE_mesh_vert_coords_alloc(me, NULL); BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos); BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert); @@ -1262,15 +1262,15 @@ static void sculpt_update_object( BKE_sculptsession_free_deformMats(ss); } - if (ss->kb != NULL && ss->deform_cos == NULL) { - ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->kb); + if (ss->shapekey_active != NULL && ss->deform_cos == NULL) { + ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); } /* if pbvh is deformed, key block is already applied to it */ - if (ss->kb) { + if (ss->shapekey_active) { bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh); if (!pbvh_deformed || ss->deform_cos == NULL) { - float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->kb); + float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); if (vertCos) { if (!pbvh_deformed) { @@ -1449,17 +1449,17 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush * stuff and show final evaluated mesh so user would see actual object shape. */ - deformed |= object->sculpt->modifiers_active; + deformed |= object->sculpt->deform_modifiers_active; if (for_construction) { - deformed |= object->sculpt->kb != NULL; + deformed |= object->sculpt->shapekey_active != NULL; } else { /* As in case with modifiers, we can't synchronize deformation made against * PBVH and non-locked keyblock, so also use PBVH only for brushes and * final DM to give final result to user. */ - deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0; + deformed |= object->sculpt->shapekey_active && (object->shapeflag & OB_SHAPE_LOCK) == 0; } return deformed; @@ -1489,6 +1489,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform) BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); BKE_pbvh_build_mesh(pbvh, + me, me->mpoly, me->mloop, me->mvert, @@ -1588,7 +1589,7 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d) if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { /* Regular mesh only draws from PBVH without modifiers and shape keys. */ const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID)); - return !(ss->kb || ss->modifiers_active || full_shading); + return !(ss->shapekey_active || ss->deform_modifiers_active || full_shading); } else { /* Multires and dyntopo always draw directly from the PBVH. */ diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 7ed986204d5..01612ded396 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -27,6 +27,7 @@ #include "BLI_ghash.h" #include "BLI_task.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BKE_pbvh.h" @@ -533,6 +534,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim) * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply(). */ void BKE_pbvh_build_mesh(PBVH *bvh, + const Mesh *mesh, const MPoly *mpoly, const MLoop *mloop, MVert *verts, @@ -545,6 +547,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh, BBC *prim_bbc = NULL; BB cb; + bvh->mesh = mesh; bvh->type = PBVH_FACES; bvh->mpoly = mpoly; bvh->mloop = mloop; @@ -1093,12 +1096,11 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode) .vnors = vnors, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); - - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); MEM_freeN(vnors); } @@ -1148,9 +1150,9 @@ static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, in .flag = flag, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); } static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata, @@ -1186,9 +1188,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) .flag = flag, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); } static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol) @@ -1222,7 +1224,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, bvh->looptri, bvh->verts, node->prim_indices, - node->totprim); + node->totprim, + bvh->mesh); break; case PBVH_BMESH: node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags & @@ -1295,9 +1298,9 @@ static void pbvh_update_draw_buffers( .show_vcol = show_vcol, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); } static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) @@ -1905,14 +1908,11 @@ static bool pbvh_faces_node_raycast(PBVH *bvh, const MVert *vert = bvh->verts; const MLoop *mloop = bvh->mloop; const int *faces = node->prim_indices; - int i, totface = node->totprim; + int totface = node->totprim; bool hit = false; - float min_depth = FLT_MAX; - float location[3] = {0.0f}; - float nearest_vertex_co[3]; - copy_v3_fl(nearest_vertex_co, 0.0f); + float nearest_vertex_co[3] = {0.0f}; - for (i = 0; i < totface; i++) { + for (int i = 0; i < totface; i++) { const MLoopTri *lt = &bvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; @@ -1920,35 +1920,33 @@ static bool pbvh_faces_node_raycast(PBVH *bvh, continue; } + const float *co[3]; if (origco) { /* intersect with backuped original coordinates */ - hit |= ray_face_intersection_tri(ray_start, - isect_precalc, - origco[face_verts[0]], - origco[face_verts[1]], - origco[face_verts[2]], - depth); + co[0] = origco[face_verts[0]]; + co[1] = origco[face_verts[1]]; + co[2] = origco[face_verts[2]]; } else { /* intersect with current coordinates */ - hit |= ray_face_intersection_tri(ray_start, - isect_precalc, - vert[mloop[lt->tri[0]].v].co, - vert[mloop[lt->tri[1]].v].co, - vert[mloop[lt->tri[2]].v].co, - depth); - - if (hit && *depth < min_depth) { - min_depth = *depth; - normal_tri_v3(r_face_normal, - vert[mloop[lt->tri[0]].v].co, - vert[mloop[lt->tri[1]].v].co, - vert[mloop[lt->tri[2]].v].co); + co[0] = vert[mloop[lt->tri[0]].v].co; + co[1] = vert[mloop[lt->tri[1]].v].co; + co[2] = vert[mloop[lt->tri[2]].v].co; + } + + if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) { + hit = true; + + if (r_face_normal) { + normal_tri_v3(r_face_normal, co[0], co[1], co[2]); + } + + if (r_active_vertex_index) { + float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { - if (len_squared_v3v3(location, vert[mloop[lt->tri[j]].v].co) < - len_squared_v3v3(location, nearest_vertex_co)) { - copy_v3_v3(nearest_vertex_co, vert[mloop[lt->tri[j]].v].co); + if (len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) { + copy_v3_v3(nearest_vertex_co, co[j]); *r_active_vertex_index = mloop[lt->tri[j]].v; } } @@ -1963,22 +1961,28 @@ static bool pbvh_grids_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], const float ray_start[3], + const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, - float *depth) + float *depth, + int *r_active_vertex_index, + float *r_face_normal) { const int totgrid = node->totprim; const int gridsize = bvh->gridkey.grid_size; bool hit = false; + float nearest_vertex_co[3] = {0.0}; + const CCGKey *gridkey = &bvh->gridkey; for (int i = 0; i < totgrid; i++) { - CCGElem *grid = bvh->grids[node->prim_indices[i]]; + const int grid_index = node->prim_indices[i]; + CCGElem *grid = bvh->grids[grid_index]; BLI_bitmap *gh; if (!grid) { continue; } - gh = bvh->grid_hidden[node->prim_indices[i]]; + gh = bvh->grid_hidden[grid_index]; for (int y = 0; y < gridsize - 1; y++) { for (int x = 0; x < gridsize - 1; x++) { @@ -1989,23 +1993,40 @@ static bool pbvh_grids_node_raycast(PBVH *bvh, } } + const float *co[4]; if (origco) { - hit |= ray_face_intersection_quad(ray_start, - isect_precalc, - origco[y * gridsize + x], - origco[y * gridsize + x + 1], - origco[(y + 1) * gridsize + x + 1], - origco[(y + 1) * gridsize + x], - depth); + co[0] = origco[y * gridsize + x]; + co[1] = origco[y * gridsize + x + 1]; + co[2] = origco[(y + 1) * gridsize + x + 1]; + co[3] = origco[(y + 1) * gridsize + x]; } else { - hit |= ray_face_intersection_quad(ray_start, - isect_precalc, - CCG_grid_elem_co(&bvh->gridkey, grid, x, y), - CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y), - CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1), - CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1), - depth); + co[0] = CCG_grid_elem_co(gridkey, grid, x, y); + co[1] = CCG_grid_elem_co(gridkey, grid, x + 1, y); + co[2] = CCG_grid_elem_co(gridkey, grid, x + 1, y + 1); + co[3] = CCG_grid_elem_co(gridkey, grid, x, y + 1); + } + + if (ray_face_intersection_quad( + ray_start, isect_precalc, co[0], co[1], co[2], co[3], depth)) { + hit = true; + + if (r_face_normal) { + normal_quad_v3(r_face_normal, co[0], co[1], co[2], co[3]); + } + + if (r_active_vertex_index) { + float location[3] = {0.0}; + madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); + for (int j = 0; j < 4; j++) { + if (len_squared_v3v3(location, co[j]) < + len_squared_v3v3(location, nearest_vertex_co)) { + copy_v3_v3(nearest_vertex_co, co[j]); + *r_active_vertex_index = gridkey->grid_area * grid_index + y * gridkey->grid_size + + x; + } + } + } } } } @@ -2048,7 +2069,15 @@ bool BKE_pbvh_node_raycast(PBVH *bvh, face_normal); break; case PBVH_GRIDS: - hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, isect_precalc, depth); + hit |= pbvh_grids_node_raycast(bvh, + node, + origco, + ray_start, + ray_normal, + isect_precalc, + depth, + active_vertex_index, + face_normal); break; case PBVH_BMESH: BM_mesh_elem_index_ensure(bvh->bm, BM_VERT); @@ -2712,13 +2741,10 @@ void pbvh_show_mask_set(PBVH *bvh, bool show_mask) bvh->show_mask = show_mask; } -void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings, +void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings, bool use_threading, int totnode) { - const int threaded_limit = 1; - BLI_parallel_range_settings_defaults(settings); - settings->use_threading = use_threading && (totnode > threaded_limit); - settings->min_iter_per_thread = 1; - settings->scheduling_mode = TASK_SCHEDULING_DYNAMIC; + memset(settings, 0, sizeof(*settings)); + settings->use_threading = use_threading && totnode > 1; } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index c04e172f116..6d38ae13994 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -1516,10 +1516,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, float *r_face_normal) { bool hit = false; - - float min_depth = FLT_MAX; float nearest_vertex_co[3] = {0.0f}; - float location[3] = {0.0f}; + if (use_original && node->bm_tot_ortri) { for (int i = 0; i < node->bm_tot_ortri; i++) { const int *t = node->bm_ortri[i]; @@ -1542,18 +1540,24 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, BMVert *v_tri[3]; BM_face_as_array_vert_tri(f, v_tri); - hit |= ray_face_intersection_tri( - ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth); - - if (hit && *depth < min_depth) { - min_depth = *depth; - normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); - madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); - for (int j = 0; j < 3; j++) { - if (len_squared_v3v3(location, v_tri[j]->co) < - len_squared_v3v3(location, nearest_vertex_co)) { - copy_v3_v3(nearest_vertex_co, v_tri[j]->co); - *r_active_vertex_index = BM_elem_index_get(v_tri[j]); + + if (ray_face_intersection_tri( + ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth)) { + hit = true; + + if (r_face_normal) { + normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); + } + + if (r_active_vertex_index) { + float location[3] = {0.0f}; + madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); + for (int j = 0; j < 3; j++) { + if (len_squared_v3v3(location, v_tri[j]->co) < + len_squared_v3v3(location, nearest_vertex_co)) { + copy_v3_v3(nearest_vertex_co, v_tri[j]->co); + *r_active_vertex_index = BM_elem_index_get(v_tri[j]); + } } } } @@ -1974,7 +1978,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, if (mode & PBVH_Collapse) { EdgeQueue q; - BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP); + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = { &q, queue_pool, @@ -1993,7 +1997,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, if (mode & PBVH_Subdivide) { EdgeQueue q; - BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP); + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = { &q, queue_pool, diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index bad103743eb..bdee05f1aab 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -127,6 +127,7 @@ struct PBVH { int leaf_limit; /* Mesh data */ + const struct Mesh *mesh; MVert *verts; const MPoly *mpoly; const MLoop *mloop; diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenkernel/intern/pbvh_parallel.cc new file mode 100644 index 00000000000..aa4c659c8bd --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_parallel.cc @@ -0,0 +1,145 @@ +/* + * 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 "MEM_guardedalloc.h" + +#include "BLI_task.h" +#include "BLI_threads.h" + +#include "BKE_pbvh.h" + +#include "atomic_ops.h" + +#ifdef WITH_TBB + +# include <tbb/tbb.h> + +/* Functor for running TBB parallel_for and parallel_reduce. */ +struct PBVHTask { + PBVHParallelRangeFunc func; + void *userdata; + const PBVHParallelSettings *settings; + + void *userdata_chunk; + + /* Root constructor. */ + PBVHTask(PBVHParallelRangeFunc func, void *userdata, const PBVHParallelSettings *settings) + : func(func), userdata(userdata), settings(settings) + { + init_chunk(settings->userdata_chunk); + } + + /* Copy constructor. */ + PBVHTask(const PBVHTask &other) + : func(other.func), userdata(other.userdata), settings(other.settings) + { + init_chunk(other.userdata_chunk); + } + + /* Splitting constructor for parallel reduce. */ + PBVHTask(PBVHTask &other, tbb::split) + : func(other.func), userdata(other.userdata), settings(other.settings) + { + init_chunk(settings->userdata_chunk); + } + + ~PBVHTask() + { + MEM_SAFE_FREE(userdata_chunk); + } + + void init_chunk(void *from_chunk) + { + if (from_chunk) { + userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask"); + memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size); + } + else { + userdata_chunk = NULL; + } + } + + void operator()(const tbb::blocked_range<int> &r) const + { + TaskParallelTLS tls; + tls.thread_id = get_thread_id(); + tls.userdata_chunk = userdata_chunk; + for (int i = r.begin(); i != r.end(); ++i) { + func(userdata, i, &tls); + } + } + + void join(const PBVHTask &other) + { + settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk); + } + + int get_thread_id() const + { + /* Get a unique thread ID for texture nodes. In the future we should get rid + * of the thread ID and change texture evaluation to not require per-thread + * storage that can't be efficiently allocated on the stack. */ + static tbb::enumerable_thread_specific<int> pbvh_thread_id(-1); + static int pbvh_thread_id_counter = 0; + + int &thread_id = pbvh_thread_id.local(); + if (thread_id == -1) { + thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1); + if (thread_id >= BLENDER_MAX_THREADS) { + BLI_assert(!"Maximum number of threads exceeded for sculpting"); + thread_id = thread_id % BLENDER_MAX_THREADS; + } + } + return thread_id; + } +}; + +#endif + +void BKE_pbvh_parallel_range(const int start, + const int stop, + void *userdata, + PBVHParallelRangeFunc func, + const struct PBVHParallelSettings *settings) +{ +#ifdef WITH_TBB + /* Multithreading. */ + if (settings->use_threading) { + PBVHTask task(func, userdata, settings); + + if (settings->func_reduce) { + parallel_reduce(tbb::blocked_range<int>(start, stop), task); + if (settings->userdata_chunk) { + memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size); + } + } + else { + parallel_for(tbb::blocked_range<int>(start, stop), task); + } + + return; + } +#endif + + /* Single threaded. Nothing to reduce as everything is accumulated into the + * main userdata chunk directly. */ + TaskParallelTLS tls; + tls.thread_id = 0; + tls.userdata_chunk = settings->userdata_chunk; + for (int i = start; i < stop; i++) { + func(userdata, i, &tls); + } +} diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 514f000d73d..c57808f3dee 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -51,6 +51,7 @@ #include "BKE_collection.h" #include "BKE_effect.h" +#include "BKE_global.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -61,7 +62,6 @@ #include "BKE_rigidbody.h" #include "BKE_scene.h" #ifdef WITH_BULLET -# include "BKE_global.h" # include "BKE_library.h" # include "BKE_library_query.h" #endif @@ -174,13 +174,22 @@ void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw) /* free physics references */ if (is_orig) { if (rbo->shared->physics_object) { - BLI_assert(rbw); - if (rbw) { + if (rbw != NULL) { /* We can only remove the body from the world if the world is known. * The world is generally only unknown if it's an evaluated copy of * an object that's being freed, in which case this code isn't run anyway. */ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); } + else { + /* We have no access to 'owner' RBW when deleting the object ID itself... No choice bu to + * loop over all scenes then. */ + for (Scene *scene = G_MAIN->scenes.first; scene != NULL; scene = scene->id.next) { + RigidBodyWorld *scene_rbw = scene->rigidbody_world; + if (scene_rbw != NULL) { + RB_dworld_remove_body(scene_rbw->shared->physics_world, rbo->shared->physics_object); + } + } + } RB_body_delete(rbo->shared->physics_object); rbo->shared->physics_object = NULL; @@ -1415,7 +1424,7 @@ bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, R return true; } -void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) +void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob, const bool free_us) { RigidBodyWorld *rbw = scene->rigidbody_world; RigidBodyCon *rbc; @@ -1438,8 +1447,13 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, obt) { if (obt && obt->rigidbody_constraint) { rbc = obt->rigidbody_constraint; - if (ELEM(ob, rbc->ob1, rbc->ob2)) { - BKE_rigidbody_remove_constraint(scene, obt); + if (rbc->ob1 == ob) { + rbc->ob1 = NULL; + DEG_id_tag_update(&obt->id, ID_RECALC_COPY_ON_WRITE); + } + if (rbc->ob2 == ob) { + rbc->ob2 = NULL; + DEG_id_tag_update(&obt->id, ID_RECALC_COPY_ON_WRITE); } } } @@ -1454,7 +1468,7 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) * when we remove them from RB simulation. */ BKE_collection_object_add(bmain, scene->master_collection, ob); } - BKE_collection_object_remove(bmain, rbw->group, ob, false); + BKE_collection_object_remove(bmain, rbw->group, ob, free_us); } /* remove object's settings */ @@ -1468,15 +1482,24 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } -void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) +void BKE_rigidbody_remove_constraint(Main *bmain, Scene *scene, Object *ob, const bool free_us) { RigidBodyWorld *rbw = scene->rigidbody_world; RigidBodyCon *rbc = ob->rigidbody_constraint; - /* remove from rigidbody world, free object won't do this */ - if (rbw && rbw->shared->physics_world && rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + if (rbw != NULL) { + /* Remove from RBW constraints collection. */ + if (rbw->constraints != NULL) { + BKE_collection_object_remove(bmain, rbw->constraints, ob, free_us); + DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE); + } + + /* remove from rigidbody world, free object won't do this */ + if (rbw->shared->physics_world && rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + } } + /* remove object's settings */ BKE_rigidbody_free_constraint(ob); @@ -1657,9 +1680,12 @@ static void rigidbody_update_simulation(Depsgraph *depsgraph, float ctime = DEG_get_ctime(depsgraph); /* update world */ - if (rebuild) { - BKE_rigidbody_validate_sim_world(scene, rbw, true); + /* Note physics_world can get NULL when undoing the deletion of the last object in it (see + * T70667). */ + if (rebuild || rbw->shared->physics_world == NULL) { + BKE_rigidbody_validate_sim_world(scene, rbw, rebuild); } + rigidbody_update_sim_world(scene, rbw); /* XXX TODO For rebuild: remove all constraints first. @@ -2086,10 +2112,10 @@ bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, R return false; } -void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) +void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob, const bool free_us) { } -void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) +void BKE_rigidbody_remove_constraint(Main *bmain, Scene *scene, Object *ob, const bool free_us) { } void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 4f855bd7d98..53e5f1fdfe5 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1008,19 +1008,19 @@ Object *BKE_scene_camera_switch_find(Scene *scene) } #endif -int BKE_scene_camera_switch_update(Scene *scene) +bool BKE_scene_camera_switch_update(Scene *scene) { #ifdef DURIAN_CAMERA_SWITCH Object *camera = BKE_scene_camera_switch_find(scene); - if (camera) { + if (camera && (camera != scene->camera)) { scene->camera = camera; DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - return 1; + return true; } #else (void)scene; #endif - return 0; + return false; } char *BKE_scene_find_marker_name(Scene *scene, int frame) @@ -1076,15 +1076,18 @@ int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, in return (delta_prev < delta_next) ? second_prev : second_next; } -void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob) +void BKE_scene_remove_rigidbody_object(struct Main *bmain, + Scene *scene, + Object *ob, + const bool free_us) { /* remove rigid body constraint from world before removing object */ if (ob->rigidbody_constraint) { - BKE_rigidbody_remove_constraint(scene, ob); + BKE_rigidbody_remove_constraint(bmain, scene, ob, free_us); } /* remove rigid body object from world before removing object */ if (ob->rigidbody_object) { - BKE_rigidbody_remove_object(bmain, scene, ob); + BKE_rigidbody_remove_object(bmain, scene, ob, free_us); } } diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index d12710690df..ccb1869ee21 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -244,7 +244,8 @@ static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCac * We could use temp cache as a shield and later make it a non-temporary entry, * but it is not worth of increasing system complexity. */ - if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) { + if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && + BKE_sequencer_prefetch_job_is_running(scene)) { int pfjob_start, pfjob_end; BKE_sequencer_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index dbdaaaa5fc3..236fb43e89c 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -3822,7 +3822,7 @@ void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user) char path[FILE_MAX]; STRNCPY(path, data->text_font->name); BLI_assert(BLI_thread_is_main()); - BLI_path_abs(path, BKE_main_blendfile_path_from_global()); + BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&data->text_font->id)); data->text_blf_id = BLF_load(path); } diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index a7543881dad..57b8c92de3e 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -34,6 +34,7 @@ #include "BLT_translation.h" +#include "DNA_mask_types.h" #include "DNA_sequence_types.h" #include "DNA_scene_types.h" @@ -1044,7 +1045,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, frame_offset = seq->start; } else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ { - frame_offset = 0; + frame_offset = ((Mask *)smd->mask_id)->sfra; } ImBuf *mask = modifier_mask_get(smd, context, cfra, frame_offset, ibuf->rect_float != NULL); diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c index c1109347e76..6dd1c47407f 100644 --- a/source/blender/blenkernel/intern/seqprefetch.c +++ b/source/blender/blenkernel/intern/seqprefetch.c @@ -31,6 +31,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_anim_types.h" #include "BLI_listbase.h" #include "BLI_threads.h" @@ -55,6 +56,7 @@ typedef struct PrefetchJob { struct PrefetchJob *next, *prev; struct Main *bmain; + struct Main *bmain_eval; struct Scene *scene; struct Scene *scene_eval; struct Depsgraph *depsgraph; @@ -109,7 +111,7 @@ static PrefetchJob *seq_prefetch_job_get(Scene *scene) return NULL; } -static bool seq_prefetch_job_is_running(Scene *scene) +bool BKE_sequencer_prefetch_job_is_running(Scene *scene) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); @@ -185,12 +187,12 @@ static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob) static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob) { DEG_evaluate_on_framechange( - pfjob->bmain, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched); + pfjob->bmain_eval, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched); } static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob) { - Main *bmain = pfjob->bmain; + Main *bmain = pfjob->bmain_eval; Scene *scene = pfjob->scene; ViewLayer *view_layer = BKE_view_layer_default_render(scene); @@ -198,7 +200,7 @@ static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob) DEG_debug_name_set(pfjob->depsgraph, "SEQUENCER PREFETCH"); /* Make sure there is a correct evaluated scene pointer. */ - DEG_graph_build_for_render_pipeline(pfjob->depsgraph, pfjob->bmain, scene, view_layer); + DEG_graph_build_for_render_pipeline(pfjob->depsgraph, bmain, scene, view_layer); /* Update immediately so we have proper evaluated scene. */ seq_prefetch_update_depsgraph(pfjob); @@ -229,7 +231,9 @@ static void seq_prefetch_update_area(PrefetchJob *pfjob) } } -/* Use also to update scene and context changes */ +/* Use also to update scene and context changes + * This function should almost always be called by cache invalidation, not directly. + */ void BKE_sequencer_prefetch_stop(Scene *scene) { PrefetchJob *pfjob; @@ -251,7 +255,7 @@ static void seq_prefetch_update_context(const SeqRenderData *context) PrefetchJob *pfjob; pfjob = seq_prefetch_job_get(context->scene); - BKE_sequencer_new_render_data(pfjob->bmain, + BKE_sequencer_new_render_data(pfjob->bmain_eval, pfjob->depsgraph, pfjob->scene_eval, context->rectx, @@ -314,6 +318,7 @@ void BKE_sequencer_prefetch_free(Scene *scene) BLI_mutex_end(&pfjob->prefetch_suspend_mutex); BLI_condition_end(&pfjob->prefetch_suspend_cond); seq_prefetch_free_depsgraph(pfjob); + BKE_main_free(pfjob->bmain_eval); MEM_freeN(pfjob); scene->ed->prefetch_job = NULL; } @@ -322,16 +327,26 @@ static void *seq_prefetch_frames(void *job) { PrefetchJob *pfjob = (PrefetchJob *)job; - /* set to NULL before return! */ - pfjob->scene_eval->ed->prefetch_job = pfjob; + while (pfjob->cfra + pfjob->num_frames_prefetched <= pfjob->scene->r.efra) { + pfjob->scene_eval->ed->prefetch_job = NULL; - while (pfjob->cfra + pfjob->num_frames_prefetched < pfjob->scene->r.efra) { - BKE_animsys_evaluate_all_animation(pfjob->context_cpy.bmain, - pfjob->context_cpy.depsgraph, - pfjob->context_cpy.scene, - pfjob->cfra + pfjob->num_frames_prefetched); + AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id); + BKE_animsys_evaluate_animdata(pfjob->context_cpy.scene, + &pfjob->context_cpy.scene->id, + adt, + pfjob->cfra + pfjob->num_frames_prefetched, + ADT_RECALC_ALL, + false); seq_prefetch_update_depsgraph(pfjob); + /* This is quite hacky solution: + * We need cross-reference original scene with copy for cache. + * However depsgraph must not have this data, because it will try to kill this job. + * Scene copy don't reference original scene. Perhaps, this could be done by depsgraph. + * Set to NULL before return! + */ + pfjob->scene_eval->ed->prefetch_job = pfjob; + ImBuf *ibuf = BKE_sequencer_give_ibuf( &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0); BKE_sequencer_cache_free_temp_cache( @@ -373,8 +388,7 @@ static void *seq_prefetch_frames(void *job) static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) { - PrefetchJob *pfjob; - pfjob = seq_prefetch_job_get(context->scene); + PrefetchJob *pfjob = seq_prefetch_job_get(context->scene); if (!pfjob) { if (context->scene->ed) { @@ -386,6 +400,7 @@ static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) BLI_condition_init(&pfjob->prefetch_suspend_cond); pfjob->bmain = context->bmain; + pfjob->bmain_eval = BKE_main_new(); pfjob->scene = context->scene; seq_prefetch_init_depsgraph(pfjob); @@ -419,7 +434,7 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa if (!context->is_prefetch_render && !context->is_proxy_render) { bool playing = seq_prefetch_is_playing(context->bmain); bool scrubbing = seq_prefetch_is_scrubbing(context->bmain); - bool running = seq_prefetch_job_is_running(scene); + bool running = BKE_sequencer_prefetch_job_is_running(scene); seq_prefetch_resume(scene); /* conditions to start: * prefetch enabled, prefetch not running, not scrubbing, @@ -437,7 +452,7 @@ bool BKE_sequencer_prefetch_need_redraw(Main *bmain, Scene *scene) { bool playing = seq_prefetch_is_playing(bmain); bool scrubbing = seq_prefetch_is_scrubbing(bmain); - bool running = seq_prefetch_job_is_running(scene); + bool running = BKE_sequencer_prefetch_job_is_running(scene); bool suspended = seq_prefetch_job_is_waiting(scene); /* force redraw, when prefetching and using cache view. */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 3e88db787ee..26dd9aab511 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3340,7 +3340,8 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr /* anim-data */ adt = BKE_animdata_from_id(&mask->id); - BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM, false); + BKE_animsys_evaluate_animdata( + context->scene, &mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false); maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__); diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 797ae0f0a8a..28f552cec2e 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -1516,6 +1516,7 @@ void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object ssmd.shrinkType = MOD_SHRINKWRAP_TARGET_PROJECT; ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE; ssmd.keepDist = 0.0f; + ssmd.projLimit = target_me->remesh_voxel_size; float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index e6c414b92da..3db51c95fcb 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -2527,17 +2527,13 @@ static void update_flowsfluids( } /* sample subframes */ else { -# if 0 int scene_frame = (int)DEG_get_ctime(depsgraph); -# endif // float scene_subframe = scene->r.subframe; // UNUSED int subframe; for (subframe = 0; subframe <= subframes; subframe++) { EmissionMap em_temp = {NULL}; float sample_size = 1.0f / (float)(subframes + 1); -# if 0 float prev_frame_pos = sample_size * (float)(subframe + 1); -# endif float sdt = dt * sample_size; int hires_multiplier = 1; @@ -2545,8 +2541,6 @@ static void update_flowsfluids( hires_multiplier = sds->amplify + 1; } - /* TODO: setting the scene frame no longer works with the new depsgraph. */ -# if 0 /* set scene frame to match previous frame + subframe * or use current frame for last sample */ if (subframe < subframes) { @@ -2557,7 +2551,6 @@ static void update_flowsfluids( scene->r.cfra = scene_frame; scene->r.subframe = 0.0f; } -# endif if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { /* emit_from_particles() updates timestep internally */ @@ -2569,8 +2562,13 @@ static void update_flowsfluids( else { /* MOD_SMOKE_FLOW_SOURCE_MESH */ /* update flow object frame */ BLI_mutex_lock(&object_update_lock); - BKE_object_modifier_update_subframe( - depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke); + BKE_object_modifier_update_subframe(depsgraph, + scene, + collob, + true, + 5, + BKE_scene_frame_get(scene), + eModifierType_Smoke); BLI_mutex_unlock(&object_update_lock); /* apply flow */ diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 471cca53900..8654c50a783 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -129,6 +129,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv) const int num_grids = topology_refiner_count_face_corners(topology_refiner); const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level); const int grid_area = grid_size * grid_size; + subdiv_ccg->grid_element_size = element_size; subdiv_ccg->num_grids = num_grids; subdiv_ccg->grids = MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids"); subdiv_ccg->grids_storage = MEM_calloc_arrayN( @@ -385,25 +386,33 @@ static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg, const int subdiv_ccg->num_adjacent_edges, sizeof(*subdiv_ccg->adjacent_edges), "ccg adjacent edges"); } +static SubdivCCGCoord subdiv_ccg_coord(int grid_index, int x, int y) +{ + SubdivCCGCoord coord = {.grid_index = grid_index, .x = x, .y = y}; + return coord; +} + +static CCGElem *subdiv_ccg_coord_to_elem(const CCGKey *key, + const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + return CCG_grid_elem(key, subdiv_ccg->grids[coord->grid_index], coord->x, coord->y); +} + /* Returns storage where boundary elements are to be stored. */ -static CCGElem **subdiv_ccg_adjacent_edge_add_face(SubdivCCG *subdiv_ccg, - SubdivCCGAdjacentEdge *adjacent_edge, - SubdivCCGFace *face) +static SubdivCCGCoord *subdiv_ccg_adjacent_edge_add_face(SubdivCCG *subdiv_ccg, + SubdivCCGAdjacentEdge *adjacent_edge) { const int grid_size = subdiv_ccg->grid_size * 2; const int adjacent_face_index = adjacent_edge->num_adjacent_faces; ++adjacent_edge->num_adjacent_faces; - /* Store new adjacent face. */ - adjacent_edge->faces = MEM_reallocN( - adjacent_edge->faces, adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces)); - adjacent_edge->faces[adjacent_face_index] = face; /* Allocate memory for the boundary elements. */ - adjacent_edge->boundary_elements = MEM_reallocN(adjacent_edge->boundary_elements, - adjacent_edge->num_adjacent_faces * - sizeof(*adjacent_edge->boundary_elements)); - adjacent_edge->boundary_elements[adjacent_face_index] = MEM_malloc_arrayN( - grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary"); - return adjacent_edge->boundary_elements[adjacent_face_index]; + adjacent_edge->boundary_coords = MEM_reallocN(adjacent_edge->boundary_coords, + adjacent_edge->num_adjacent_faces * + sizeof(*adjacent_edge->boundary_coords)); + adjacent_edge->boundary_coords[adjacent_face_index] = MEM_malloc_arrayN( + grid_size * 2, sizeof(SubdivCCGCoord), "ccg adjacent boundary"); + return adjacent_edge->boundary_coords[adjacent_face_index]; } static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg) @@ -423,9 +432,6 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg) StaticOrHeapIntStorage face_edges_storage; static_or_heap_storage_init(&face_vertices_storage); static_or_heap_storage_init(&face_edges_storage); - /* Key to access elements. */ - CCGKey key; - BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); /* Store adjacency for all faces. */ const int num_faces = subdiv_ccg->num_faces; for (int face_index = 0; face_index < num_faces; face_index++) { @@ -447,34 +453,32 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg) const bool is_edge_flipped = (edge_vertices[0] != vertex_index); /* Grid which is adjacent to the current corner. */ const int current_grid_index = face->start_grid_index + corner; - CCGElem *current_grid = subdiv_ccg->grids[current_grid_index]; /* Grid which is adjacent to the next corner. */ const int next_grid_index = face->start_grid_index + (corner + 1) % num_face_grids; - CCGElem *next_grid = subdiv_ccg->grids[next_grid_index]; /* Add new face to the adjacent edge. */ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index]; - CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face( - subdiv_ccg, adjacent_edge, face); + SubdivCCGCoord *boundary_coords = subdiv_ccg_adjacent_edge_add_face(subdiv_ccg, + adjacent_edge); /* Fill CCG elements along the edge. */ int boundary_element_index = 0; if (is_edge_flipped) { for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, next_grid, grid_size - i - 1, grid_size - 1); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + next_grid_index, grid_size - i - 1, grid_size - 1); } for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, current_grid, grid_size - 1, i); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + current_grid_index, grid_size - 1, i); } } else { for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, current_grid, grid_size - 1, grid_size - i - 1); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + current_grid_index, grid_size - 1, grid_size - i - 1); } for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, next_grid, i, grid_size - 1); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + next_grid_index, i, grid_size - 1); } } } @@ -494,21 +498,16 @@ static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg, const i /* Returns storage where corner elements are to be stored. This is a pointer * to the actual storage. */ -static CCGElem **subdiv_ccg_adjacent_vertex_add_face(SubdivCCGAdjacentVertex *adjacent_vertex, - SubdivCCGFace *face) +static SubdivCCGCoord *subdiv_ccg_adjacent_vertex_add_face( + SubdivCCGAdjacentVertex *adjacent_vertex) { const int adjacent_face_index = adjacent_vertex->num_adjacent_faces; ++adjacent_vertex->num_adjacent_faces; - /* Store new adjacent face. */ - adjacent_vertex->faces = MEM_reallocN(adjacent_vertex->faces, - adjacent_vertex->num_adjacent_faces * - sizeof(*adjacent_vertex->faces)); - adjacent_vertex->faces[adjacent_face_index] = face; /* Allocate memory for the boundary elements. */ - adjacent_vertex->corner_elements = MEM_reallocN(adjacent_vertex->corner_elements, - adjacent_vertex->num_adjacent_faces * - sizeof(*adjacent_vertex->corner_elements)); - return &adjacent_vertex->corner_elements[adjacent_face_index]; + adjacent_vertex->corner_coords = MEM_reallocN(adjacent_vertex->corner_coords, + adjacent_vertex->num_adjacent_faces * + sizeof(*adjacent_vertex->corner_coords)); + return &adjacent_vertex->corner_coords[adjacent_face_index]; } static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg) @@ -541,11 +540,10 @@ static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg) const int vertex_index = face_vertices[corner]; /* Grid which is adjacent to the current corner. */ const int grid_index = face->start_grid_index + corner; - CCGElem *grid = subdiv_ccg->grids[grid_index]; /* Add new face to the adjacent edge. */ SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[vertex_index]; - CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face(adjacent_vertex, face); - *corner_element = CCG_grid_elem(&key, grid, grid_size - 1, grid_size - 1); + SubdivCCGCoord *corner_coord = subdiv_ccg_adjacent_vertex_add_face(adjacent_vertex); + *corner_coord = subdiv_ccg_coord(grid_index, grid_size - 1, grid_size - 1); } } /* Free possibly heap-allocated storage. */ @@ -593,7 +591,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv, BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) { if (coarse_mesh->totpoly) { - return false; + return NULL; } } BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); @@ -638,17 +636,15 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg) for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) { SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i]; for (int face_index = 0; face_index < adjacent_edge->num_adjacent_faces; face_index++) { - MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]); + MEM_SAFE_FREE(adjacent_edge->boundary_coords[face_index]); } - MEM_SAFE_FREE(adjacent_edge->faces); - MEM_SAFE_FREE(adjacent_edge->boundary_elements); + MEM_SAFE_FREE(adjacent_edge->boundary_coords); } MEM_SAFE_FREE(subdiv_ccg->adjacent_edges); /* Free map of adjacent vertices. */ for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) { SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[i]; - MEM_SAFE_FREE(adjacent_vertex->faces); - MEM_SAFE_FREE(adjacent_vertex->corner_elements); + MEM_SAFE_FREE(adjacent_vertex->corner_coords); } MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices); MEM_freeN(subdiv_ccg); @@ -1051,7 +1047,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg, } for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { for (int i = 1; i < grid_size2 - 1; i++) { - CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_edge->boundary_coords[face_index][i]); element_accumulator_add(&tls->accumulators[i], subdiv_ccg, key, grid_element); } } @@ -1061,7 +1058,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg, /* Copy averaged value to all the other faces. */ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { for (int i = 1; i < grid_size2 - 1; i++) { - CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_edge->boundary_coords[face_index][i]); element_accumulator_copy(subdiv_ccg, key, grid_element, &tls->accumulators[i]); } } @@ -1103,13 +1101,15 @@ static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg, GridElementAccumulator accumulator; element_accumulator_init(&accumulator); for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { - CCGElem *grid_element = adjacent_vertex->corner_elements[face_index]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_vertex->corner_coords[face_index]); element_accumulator_add(&accumulator, subdiv_ccg, key, grid_element); } element_accumulator_mul_fl(&accumulator, 1.0f / (float)num_adjacent_faces); /* Copy averaged value to all the other faces. */ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { - CCGElem *grid_element = adjacent_vertex->corner_elements[face_index]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_vertex->corner_coords[face_index]); element_accumulator_copy(subdiv_ccg, key, grid_element, &accumulator); } } @@ -1243,3 +1243,540 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, *r_num_faces = num_grids * (grid_size - 1) * (grid_size - 1); *r_num_loops = *r_num_faces * 4; } + +/* ============================================================================= + * Neighbors. + */ + +void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord) +{ + printf("%s: grid index: %d, coord: (%d, %d)\n", message, coord->grid_index, coord->x, coord->y); +} + +bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + if (coord->grid_index < 0 || coord->grid_index >= subdiv_ccg->num_grids) { + return false; + } + const int grid_size = subdiv_ccg->grid_size; + if (coord->x < 0 || coord->x >= grid_size) { + return false; + } + if (coord->y < 0 || coord->y >= grid_size) { + return false; + } + return true; +} + +BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors *neighbors, + const int num_unique, + const int num_duplicates) +{ + const int size = num_unique + num_duplicates; + neighbors->size = size; + neighbors->num_duplicates = num_duplicates; + if (size < ARRAY_SIZE(neighbors->coords_fixed)) { + neighbors->coords = neighbors->coords_fixed; + } + else { + neighbors->coords = MEM_mallocN(sizeof(*neighbors->coords) * size, + "SubdivCCGNeighbors.coords"); + } +} + +/* Check whether given coordinate belongs to a grid corner. */ +BLI_INLINE bool is_corner_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + return (coord->x == 0 && coord->y == 0) || (coord->x == 0 && coord->y == grid_size_1) || + (coord->x == grid_size_1 && coord->y == grid_size_1) || + (coord->x == grid_size_1 && coord->y == 0); +} + +/* Check whether given coordinate belongs to a grid boundary. */ +BLI_INLINE bool is_boundary_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + return coord->x == 0 || coord->y == 0 || coord->x == grid_size_1 || coord->y == grid_size_1; +} + +/* Check whether coordinate is at the boundary between two grids of the same face. */ +BLI_INLINE bool is_inner_edge_grid_coordinate(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (coord->x == 0) { + return coord->y > 0 && coord->y < grid_size_1; + } + if (coord->y == 0) { + return coord->x > 0 && coord->x < grid_size_1; + } + return false; +} + +BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG *UNUSED(subdiv_ccg), + const SubdivCCGCoord *coord) +{ + BLI_assert(coord->y > 0); + SubdivCCGCoord result = *coord; + result.y -= 1; + return result; +} +BLI_INLINE SubdivCCGCoord coord_at_next_row(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + UNUSED_VARS_NDEBUG(subdiv_ccg); + BLI_assert(coord->y < subdiv_ccg->grid_size - 1); + SubdivCCGCoord result = *coord; + result.y += 1; + return result; +} + +BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG *UNUSED(subdiv_ccg), + const SubdivCCGCoord *coord) +{ + BLI_assert(coord->x > 0); + SubdivCCGCoord result = *coord; + result.x -= 1; + return result; +} +BLI_INLINE SubdivCCGCoord coord_at_next_col(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + UNUSED_VARS_NDEBUG(subdiv_ccg); + BLI_assert(coord->x < subdiv_ccg->grid_size - 1); + SubdivCCGCoord result = *coord; + result.x += 1; + return result; +} + +/* For the input coordinate which is at the boundary of the grid do one step inside. */ +static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) + +{ + SubdivCCGCoord result = *coord; + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (result.x == grid_size_1) { + --result.x; + } + else if (result.y == grid_size_1) { + --result.y; + } + else if (result.x == 0) { + ++result.x; + } + else if (result.y == 0) { + ++result.y; + } + else { + BLI_assert(!"non-boundary element given"); + } + return result; +} + +BLI_INLINE +int next_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_grid_index = coord->grid_index; + int next_face_grid_index = face_grid_index + 1 - face->start_grid_index; + if (next_face_grid_index == face->num_grids) { + next_face_grid_index = 0; + } + return face->start_grid_index + next_face_grid_index; +} +BLI_INLINE int prev_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_grid_index = coord->grid_index; + int prev_face_grid_index = face_grid_index - 1 - face->start_grid_index; + if (prev_face_grid_index < 0) { + prev_face_grid_index = face->num_grids - 1; + } + return face->start_grid_index + prev_face_grid_index; +} + +/* Simple case of getting neighbors of a corner coordinate: the corner is a face center, so + * can only iterate over grid of a single face, without looking into adjacency. */ +static void neighbor_coords_corner_center_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int num_adjacent_grids = face->num_grids; + + subdiv_ccg_neighbors_init( + r_neighbors, num_adjacent_grids, (include_duplicates) ? num_adjacent_grids - 1 : 0); + + int duplicate_face_grid_index = num_adjacent_grids; + for (int face_grid_index = 0; face_grid_index < num_adjacent_grids; ++face_grid_index) { + SubdivCCGCoord neighbor_coord; + neighbor_coord.grid_index = face->start_grid_index + face_grid_index; + neighbor_coord.x = 1; + neighbor_coord.y = 0; + r_neighbors->coords[face_grid_index] = neighbor_coord; + + if (include_duplicates && neighbor_coord.grid_index != coord->grid_index) { + neighbor_coord.x = 0; + r_neighbors->coords[duplicate_face_grid_index++] = neighbor_coord; + } + } +} + +/* Get index within adjacent_vertices array for the given CCG coordinate. */ +static int adjacent_vertex_index_from_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_index = face - subdiv_ccg->faces; + const int face_grid_index = coord->grid_index - face->start_grid_index; + const int num_face_grids = face->num_grids; + const int num_face_vertices = num_face_grids; + + StaticOrHeapIntStorage face_vertices_storage; + static_or_heap_storage_init(&face_vertices_storage); + + int *face_vertices = static_or_heap_storage_get(&face_vertices_storage, num_face_vertices); + topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices); + + const int adjacent_vertex_index = face_vertices[face_grid_index]; + static_or_heap_storage_free(&face_vertices_storage); + return adjacent_vertex_index; +} + +/* The corner is adjacent to a coarse vertex. */ +static void neighbor_coords_corner_vertex_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); + BLI_assert(adjacent_vertex_index >= 0); + BLI_assert(adjacent_vertex_index < subdiv_ccg->num_adjacent_vertices); + const int num_vertex_edges = topology_refiner->getNumVertexEdges(topology_refiner, + adjacent_vertex_index); + + SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[adjacent_vertex_index]; + const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces; + + subdiv_ccg_neighbors_init( + r_neighbors, num_vertex_edges, (include_duplicates) ? num_adjacent_faces - 1 : 0); + + StaticOrHeapIntStorage vertex_edges_storage; + static_or_heap_storage_init(&vertex_edges_storage); + + int *vertex_edges = static_or_heap_storage_get(&vertex_edges_storage, num_vertex_edges); + topology_refiner->getVertexEdges(topology_refiner, adjacent_vertex_index, vertex_edges); + + for (int i = 0; i < num_vertex_edges; ++i) { + const int edge_index = vertex_edges[i]; + + /* Use very first grid of every edge. */ + const int edge_face_index = 0; + + /* Depending edge orientation we use first (zero-based) or previous-to-last point. */ + int edge_vertices_indices[2]; + topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices_indices); + int edge_point_index, duplicate_edge_point_index; + if (edge_vertices_indices[0] == adjacent_vertex_index) { + duplicate_edge_point_index = 0; + edge_point_index = duplicate_edge_point_index + 1; + } + else { + /* Edge "consists" of 2 grids, which makes it 2 * grid_size elements per edge. + * The index of last edge element is 2 * grid_size - 1 (due to zero-based indices), + * and we are interested in previous to last element. */ + duplicate_edge_point_index = subdiv_ccg->grid_size * 2 - 1; + edge_point_index = duplicate_edge_point_index - 1; + } + + SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index]; + r_neighbors->coords[i] = adjacent_edge->boundary_coords[edge_face_index][edge_point_index]; + } + + if (include_duplicates) { + /* Add duplicates of the current grid vertex in adjacent faces if requested. */ + for (int i = 0, duplicate_i = num_vertex_edges; i < num_adjacent_faces; i++) { + SubdivCCGCoord neighbor_coord = adjacent_vertex->corner_coords[i]; + if (neighbor_coord.grid_index != coord->grid_index) { + r_neighbors->coords[duplicate_i++] = neighbor_coord; + } + } + } + + static_or_heap_storage_free(&vertex_edges_storage); +} + +static int adjacent_edge_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + + const int face_grid_index = coord->grid_index - face->start_grid_index; + const int face_index = face - subdiv_ccg->faces; + const int num_face_edges = topology_refiner->getNumFaceEdges(topology_refiner, face_index); + + StaticOrHeapIntStorage face_edges_storage; + static_or_heap_storage_init(&face_edges_storage); + int *face_edges_indices = static_or_heap_storage_get(&face_edges_storage, num_face_edges); + topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges_indices); + + const int grid_size_1 = subdiv_ccg->grid_size - 1; + int adjacent_edge_index = -1; + if (coord->x == grid_size_1) { + adjacent_edge_index = face_edges_indices[face_grid_index]; + } + else { + BLI_assert(coord->y == grid_size_1); + adjacent_edge_index = + face_edges_indices[face_grid_index == 0 ? face->num_grids - 1 : face_grid_index - 1]; + } + + static_or_heap_storage_free(&face_edges_storage); + + return adjacent_edge_index; +} + +static int adjacent_edge_point_index_from_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const int adjacent_edge_index) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); + int edge_vertices_indices[2]; + topology_refiner->getEdgeVertices(topology_refiner, adjacent_edge_index, edge_vertices_indices); + + /* Vertex index of an edge which is used to see whether edge points in the right direction. + * Tricky part here is that depending whether input coordinate is are maximum X or Y coordinate + * of the grid we need to use different edge direction. + * Basically, the edge adjacent to a previous loop needs to point opposite direction. */ + int directional_edge_vertex_index = -1; + + const int grid_size_1 = subdiv_ccg->grid_size - 1; + int adjacent_edge_point_index = -1; + if (coord->x == grid_size_1) { + adjacent_edge_point_index = subdiv_ccg->grid_size - coord->y - 1; + directional_edge_vertex_index = edge_vertices_indices[0]; + } + else { + BLI_assert(coord->y == grid_size_1); + adjacent_edge_point_index = subdiv_ccg->grid_size + coord->x; + directional_edge_vertex_index = edge_vertices_indices[1]; + } + + /* Flip the index if the edde points opposite direction. */ + if (adjacent_vertex_index != directional_edge_vertex_index) { + const int num_edge_points = subdiv_ccg->grid_size * 2; + adjacent_edge_point_index = num_edge_points - adjacent_edge_point_index - 1; + } + + return adjacent_edge_point_index; +} + +/* Adjacent edge has two points in the middle which corresponds to grid corners, but which are + * the same point in the final geometry. + * So need to use extra step when calculating next/previous points, so we don't go from a corner + * of one grid to a corner of adjacent grid. */ +static int next_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index) +{ + if (point_index == subdiv_ccg->grid_size - 1) { + return point_index + 2; + } + return point_index + 1; +} +static int prev_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index) +{ + if (point_index == subdiv_ccg->grid_size) { + return point_index - 2; + } + return point_index - 1; +} + +/* Common implementation of neighbor calculation when input coordinate is at the edge between two + * coarse faces, but is not at the coarse vertex. */ +static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) + +{ + const int adjacent_edge_index = adjacent_edge_index_from_coord(subdiv_ccg, coord); + BLI_assert(adjacent_edge_index >= 0); + BLI_assert(adjacent_edge_index < subdiv_ccg->num_adjacent_edges); + const SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[adjacent_edge_index]; + + /* 2 neighbor points along the edge, plus one inner point per every adjacent grid. */ + const int num_adjacent_faces = adjacent_edge->num_adjacent_faces; + subdiv_ccg_neighbors_init( + r_neighbors, num_adjacent_faces + 2, (include_duplicates) ? num_adjacent_faces - 1 : 0); + + const int point_index = adjacent_edge_point_index_from_coord( + subdiv_ccg, coord, adjacent_edge_index); + const int next_point_index = next_adjacent_edge_point_index(subdiv_ccg, point_index); + const int prev_point_index = prev_adjacent_edge_point_index(subdiv_ccg, point_index); + + for (int i = 0, duplicate_i = num_adjacent_faces; i < num_adjacent_faces; ++i) { + SubdivCCGCoord *boundary_coords = adjacent_edge->boundary_coords[i]; + /* One step into the grid from the edge for each adjacent face. */ + SubdivCCGCoord grid_coord = boundary_coords[point_index]; + r_neighbors->coords[i + 2] = coord_step_inside_from_boundary(subdiv_ccg, &grid_coord); + + if (grid_coord.grid_index == coord->grid_index) { + /* Prev and next along the edge for the current grid. */ + r_neighbors->coords[0] = boundary_coords[prev_point_index]; + r_neighbors->coords[1] = boundary_coords[next_point_index]; + } + else if (include_duplicates) { + /* Same coordinate on neighboring grids if requested. */ + r_neighbors->coords[duplicate_i + 2] = grid_coord; + duplicate_i++; + } + } +} + +/* The corner is at the middle of edge between faces. */ +static void neighbor_coords_corner_edge_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors); +} + +/* Input coordinate is at one of 4 corners of its grid corners. */ +static void neighbor_coords_corner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + if (coord->x == 0 && coord->y == 0) { + neighbor_coords_corner_center_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (coord->x == grid_size_1 && coord->y == grid_size_1) { + neighbor_coords_corner_vertex_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + neighbor_coords_corner_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + } +} + +/* Simple case of getting neighbors of a boundary coordinate: the input coordinate is at the + * boundary between two grids of the same face and there is no need to check adjacency with + * other faces. */ +static void neighbor_coords_boundary_inner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + subdiv_ccg_neighbors_init(r_neighbors, 4, (include_duplicates) ? 1 : 0); + + if (coord->x == 0) { + r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_next_col(subdiv_ccg, coord); + + r_neighbors->coords[3].grid_index = prev_grid_index_from_coord(subdiv_ccg, coord); + r_neighbors->coords[3].x = coord->y; + r_neighbors->coords[3].y = 1; + + if (include_duplicates) { + r_neighbors->coords[4] = r_neighbors->coords[3]; + r_neighbors->coords[4].y = 0; + } + } + else if (coord->y == 0) { + r_neighbors->coords[0] = coord_at_prev_col(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_col(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_next_row(subdiv_ccg, coord); + + r_neighbors->coords[3].grid_index = next_grid_index_from_coord(subdiv_ccg, coord); + r_neighbors->coords[3].x = 1; + r_neighbors->coords[3].y = coord->x; + + if (include_duplicates) { + r_neighbors->coords[4] = r_neighbors->coords[3]; + r_neighbors->coords[4].x = 0; + } + } +} + +/* Input coordinate is on an edge between two faces. Need to check adjacency. */ +static void neighbor_coords_boundary_outer_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors); +} + +/* Input coordinate is at one of 4 boundaries of its grid. + * It could either be an inner boundary (which connects face center to the face edge) or could be + * a part of coarse face edge. */ +static void neighbor_coords_boundary_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + if (is_inner_edge_grid_coordinate(subdiv_ccg, coord)) { + neighbor_coords_boundary_inner_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + neighbor_coords_boundary_outer_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } +} + +/* Input coordinate is inside of its grid, all the neighbors belong to the same grid. */ +static void neighbor_coords_inner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + subdiv_ccg_neighbors_init(r_neighbors, 4, 0); + + r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_prev_col(subdiv_ccg, coord); + r_neighbors->coords[3] = coord_at_next_col(subdiv_ccg, coord); +} + +void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + BLI_assert(coord->grid_index >= 0); + BLI_assert(coord->grid_index < subdiv_ccg->num_grids); + BLI_assert(coord->x >= 0); + BLI_assert(coord->x < subdiv_ccg->grid_size); + BLI_assert(coord->y >= 0); + BLI_assert(coord->y < subdiv_ccg->grid_size); + + if (is_corner_grid_coord(subdiv_ccg, coord)) { + neighbor_coords_corner_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else if (is_boundary_grid_coord(subdiv_ccg, coord)) { + neighbor_coords_boundary_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors); + } + +#ifndef NDEBUG + for (int i = 0; i < r_neighbors->size; i++) { + BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, &r_neighbors->coords[i])); + } +#endif +} diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 83be64e84c9..5c050dde990 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -312,7 +312,7 @@ bool BKE_text_reload(Text *text) } BLI_strncpy(filepath_abs, text->name, FILE_MAX); - BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global()); + BLI_path_abs(filepath_abs, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len); if (buffer == NULL) { @@ -352,7 +352,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len); if (buffer == NULL) { - return false; + return NULL; } ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0); @@ -477,7 +477,7 @@ int BKE_text_file_modified_check(Text *text) } BLI_strncpy(file, text->name, FILE_MAX); - BLI_path_abs(file, BKE_main_blendfile_path_from_global()); + BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); if (!BLI_exists(file)) { return 2; @@ -511,7 +511,7 @@ void BKE_text_file_modified_ignore(Text *text) } BLI_strncpy(file, text->name, FILE_MAX); - BLI_path_abs(file, BKE_main_blendfile_path_from_global()); + BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); if (!BLI_exists(file)) { return; @@ -1218,6 +1218,58 @@ void txt_sel_line(Text *text) text->selc = text->sell->len; } +void txt_sel_set(Text *text, int startl, int startc, int endl, int endc) +{ + TextLine *froml, *tol; + int fromllen, tollen; + + /* Support negative indices. */ + if (startl < 0 || endl < 0) { + int end = BLI_listbase_count(&text->lines) - 1; + if (startl < 0) { + startl = end + startl + 1; + } + if (endl < 0) { + endl = end + endl + 1; + } + } + CLAMP_MIN(startl, 0); + CLAMP_MIN(endl, 0); + + froml = BLI_findlink(&text->lines, startl); + if (froml == NULL) { + froml = text->lines.last; + } + if (startl == endl) { + tol = froml; + } + else { + tol = BLI_findlink(&text->lines, endl); + if (tol == NULL) { + tol = text->lines.last; + } + } + + fromllen = BLI_strlen_utf8(froml->line); + tollen = BLI_strlen_utf8(tol->line); + + /* Support negative indices. */ + if (startc < 0) { + startc = fromllen + startc + 1; + } + if (endc < 0) { + endc = tollen + endc + 1; + } + + CLAMP(startc, 0, fromllen); + CLAMP(endc, 0, tollen); + + text->curl = froml; + text->curc = BLI_str_utf8_offset_from_index(froml->line, startc); + text->sell = tol; + text->selc = BLI_str_utf8_offset_from_index(tol->line, endc); +} + /* -------------------------------------------------------------------- */ /** \name Buffer Conversion for Undo/Redo * diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h index bd1cd327d3c..312991e7f15 100644 --- a/source/blender/blenlib/BLI_compiler_compat.h +++ b/source/blender/blenlib/BLI_compiler_compat.h @@ -15,7 +15,7 @@ */ #ifndef __BLI_COMPILER_COMPAT_H__ -# define __BLI_COMPILER_COMPAT_H__ +#define __BLI_COMPILER_COMPAT_H__ /** \file * \ingroup bli @@ -23,32 +23,32 @@ * Use to help with cross platform portability. */ -# if defined(_MSC_VER) -# define alloca _alloca -# endif +#if defined(_MSC_VER) +# define alloca _alloca +#endif -# if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus) +#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus) extern "C++" { /* Some magic to be sure we don't have reference in the type. */ template<typename T> static inline T decltype_helper(T x) { return x; } -# define typeof(x) decltype(decltype_helper(x)) +# define typeof(x) decltype(decltype_helper(x)) } -# endif +#endif /* little macro so inline keyword works */ -# if defined(_MSC_VER) -# define BLI_INLINE static __forceinline -# else -# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) -# endif +#if defined(_MSC_VER) +# define BLI_INLINE static __forceinline +#else +# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) +#endif -# if defined(__GNUC__) -# define BLI_NOINLINE __attribute__((noinline)) -# else -# define BLI_NOINLINE -# endif +#if defined(__GNUC__) +# define BLI_NOINLINE __attribute__((noinline)) +#else +# define BLI_NOINLINE +#endif #endif /* __BLI_COMPILER_COMPAT_H__ */ diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index d78f167a8fd..bdf7588291f 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -50,6 +50,7 @@ int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_copy(const char *path, const char *to) ATTR_NONNULL(); int BLI_rename(const char *from, const char *to) ATTR_NONNULL(); int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL(); +int BLI_delete_soft(const char *path, const char **error_message) ATTR_NONNULL(); #if 0 /* Unused */ int BLI_move(const char *path, const char *to) ATTR_NONNULL(); int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL(); diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h index 4bd53dfddbe..b8a87e9d9fa 100644 --- a/source/blender/blenlib/BLI_gsqueue.h +++ b/source/blender/blenlib/BLI_gsqueue.h @@ -26,7 +26,7 @@ typedef struct _GSQueue GSQueue; -GSQueue *BLI_gsqueue_new(size_t elem_size); +GSQueue *BLI_gsqueue_new(const size_t elem_size); bool BLI_gsqueue_is_empty(const GSQueue *gq); size_t BLI_gsqueue_len(const GSQueue *gq); void BLI_gsqueue_pop(GSQueue *gq, void *r_item); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 87517ebe060..eec5d214473 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -97,10 +97,10 @@ bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); bool is_poly_convex_v2(const float verts[][2], unsigned int nr); int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); -bool is_quad_flip_v3_first_third_fast(const float v0[3], - const float v1[3], +bool is_quad_flip_v3_first_third_fast(const float v1[3], const float v2[3], - const float v3[3]); + const float v3[3], + const float v4[3]); /********************************* Distance **********************************/ diff --git a/source/blender/blenlib/intern/BLI_temporary_allocator.cc b/source/blender/blenlib/intern/BLI_temporary_allocator.cc index e41cf36f66d..b145e65530d 100644 --- a/source/blender/blenlib/intern/BLI_temporary_allocator.cc +++ b/source/blender/blenlib/intern/BLI_temporary_allocator.cc @@ -73,7 +73,7 @@ struct ThreadLocalBuffers { } }; -thread_local ThreadLocalBuffers local_storage; +static thread_local ThreadLocalBuffers local_storage; void *BLI_temporary_allocate(uint size) { diff --git a/source/blender/blenlib/intern/BLI_timer.c b/source/blender/blenlib/intern/BLI_timer.c index 0443dea9a2e..af987587d90 100644 --- a/source/blender/blenlib/intern/BLI_timer.c +++ b/source/blender/blenlib/intern/BLI_timer.c @@ -42,7 +42,6 @@ typedef struct TimedFunction { typedef struct TimerContainer { ListBase funcs; - bool file_load_cb_registered; } TimerContainer; static TimerContainer GlobalTimer = {{0}}; diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c index d5dcd40346f..af4fa9fa54e 100644 --- a/source/blender/blenlib/intern/delaunay_2d.c +++ b/source/blender/blenlib/intern/delaunay_2d.c @@ -325,6 +325,18 @@ static bool exists_edge(const CDTVert *a, const CDTVert *b) return false; } +/** Is the vertex v incident on face f? */ +static bool vert_touches_face(const CDTVert *v, const CDTFace *f) +{ + SymEdge *se = v->symedge; + do { + if (se->face == f) { + return true; + } + } while ((se = se->rot) != v->symedge); + return false; +} + /** * Assume s1 and s2 are both SymEdges in a face with > 3 sides, * and one is not the next of the other. @@ -1901,35 +1913,108 @@ static void dissolve_symedge(CDT_state *cdt, SymEdge *se) delete_edge(cdt, se); } -static void remove_non_constraint_edges(CDT_state *cdt, const bool valid_bmesh) +/* Remove all non-constraint edges. */ +static void remove_non_constraint_edges(CDT_state *cdt) +{ + LinkNode *ln; + CDTEdge *e; + SymEdge *se; + + for (ln = cdt->edges; ln; ln = ln->next) { + e = (CDTEdge *)ln->link; + se = &e->symedges[0]; + if (!is_deleted_edge(e) && !is_constrained_edge(e)) { + dissolve_symedge(cdt, se); + } + } +} + +/* + * Remove the non-constraint edges, but leave enough of them so that all of the + * faces that would be bmesh faces (that is, the faces that have some input representative) + * are valid: they can't have holes, they can't have repeated vertices, and they can't have + * repeated edges. + * + * Not essential, but to make the result look more aesthetically nice, + * remove the edges in order of decreasing length, so that it is more likely that the + * final remaining support edges are short, and therefore likely to make a fairly + * direct path from an outer face to an inner hole face. + */ + +/* For sorting edges by decreasing length (squared). */ +struct EdgeToSort { + double len_squared; + CDTEdge *e; +}; + +static int edge_to_sort_cmp(const void *a, const void *b) +{ + const struct EdgeToSort *e1 = a; + const struct EdgeToSort *e2 = b; + + if (e1->len_squared > e2->len_squared) { + return -1; + } + else if (e1->len_squared < e2->len_squared) { + return 1; + } + return 0; +} + +static void remove_non_constraint_edges_leave_valid_bmesh(CDT_state *cdt) { LinkNode *ln; CDTEdge *e; SymEdge *se, *se2; CDTFace *fleft, *fright; bool dissolve; + size_t nedges; + int i, ndissolvable; + const double *co1, *co2; + struct EdgeToSort *sorted_edges; + nedges = 0; + for (ln = cdt->edges; ln; ln = ln->next) { + nedges++; + } + if (nedges == 0) { + return; + } + sorted_edges = BLI_memarena_alloc(cdt->arena, nedges * sizeof(*sorted_edges)); + i = 0; for (ln = cdt->edges; ln; ln = ln->next) { e = (CDTEdge *)ln->link; - dissolve = !is_deleted_edge(e) && !is_constrained_edge(e); - if (dissolve) { - se = &e->symedges[0]; - if (valid_bmesh && !edge_touches_frame(e)) { - fleft = se->face; - fright = sym(se)->face; - if (fleft != cdt->outer_face && fright != cdt->outer_face && - (fleft->input_ids != NULL || fright->input_ids != NULL)) { - /* Is there another symedge with same left and right faces? */ - for (se2 = se->next; dissolve && se2 != se; se2 = se2->next) { - if (sym(se2)->face == fright) { - dissolve = false; - } + if (!is_deleted_edge(e) && !is_constrained_edge(e)) { + sorted_edges[i].e = e; + co1 = e->symedges[0].vert->co; + co2 = e->symedges[1].vert->co; + sorted_edges[i].len_squared = len_squared_v2v2_db(co1, co2); + i++; + } + } + ndissolvable = i; + qsort(sorted_edges, ndissolvable, sizeof(*sorted_edges), edge_to_sort_cmp); + for (i = 0; i < ndissolvable; i++) { + e = sorted_edges[i].e; + se = &e->symedges[0]; + dissolve = true; + if (!edge_touches_frame(e)) { + fleft = se->face; + fright = sym(se)->face; + if (fleft != cdt->outer_face && fright != cdt->outer_face && + (fleft->input_ids != NULL || fright->input_ids != NULL)) { + /* Is there another symedge with same left and right faces? + * Or is there a vertex not part of e touching the same left and right faces? */ + for (se2 = se->next; dissolve && se2 != se; se2 = se2->next) { + if (sym(se2)->face == fright || + (se2->vert != se->next->vert && vert_touches_face(se2->vert, fright))) { + dissolve = false; } } } - if (dissolve) { - dissolve_symedge(cdt, se); - } + } + if (dissolve) { + dissolve_symedge(cdt, se); } } } @@ -2066,8 +2151,11 @@ static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_ UNUSED_VARS(f); #endif - if (output_type == CDT_CONSTRAINTS || output_type == CDT_CONSTRAINTS_VALID_BMESH) { - remove_non_constraint_edges(cdt, output_type == CDT_CONSTRAINTS_VALID_BMESH); + if (output_type == CDT_CONSTRAINTS) { + remove_non_constraint_edges(cdt); + } + else if (output_type == CDT_CONSTRAINTS_VALID_BMESH) { + remove_non_constraint_edges_leave_valid_bmesh(cdt); } else if (output_type == CDT_FULL || output_type == CDT_INSIDE) { remove_outer_edges(cdt, output_type == CDT_INSIDE); diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c index 14fc4c5bf26..c7631f8991e 100644 --- a/source/blender/blenlib/intern/expr_pylike_eval.c +++ b/source/blender/blenlib/intern/expr_pylike_eval.c @@ -504,7 +504,9 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void * if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) { UnaryOpFunc func = funcptr; - double result = func(prev_ops[-1].arg.dval); + /* volatile because some compilers overly aggressive optimize this call out. + * see D6012 for details. */ + volatile double result = func(prev_ops[-1].arg.dval); if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { prev_ops[-1].arg.dval = result; @@ -520,7 +522,9 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void * prev_ops[-1].opcode == OPCODE_CONST) { BinaryOpFunc func = funcptr; - double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval); + /* volatile because some compilers overly aggressive optimize this call out. + * see D6012 for details. */ + volatile double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval); if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { prev_ops[-2].arg.dval = result; diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 99149f5ea42..3a45989fb63 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -33,16 +33,24 @@ #include "zlib.h" #ifdef WIN32 +# include <windows.h> +# include <shellapi.h> +# include <shobjidl.h> # include <io.h> # include "BLI_winstuff.h" # include "BLI_fileops_types.h" # include "utf_winfunc.h" # include "utfconv.h" #else +# if defined(__APPLE__) +# include <CoreFoundation/CoreFoundation.h> +# include <objc/runtime.h> +# include <objc/message.h> +# endif # include <sys/param.h> # include <dirent.h> # include <unistd.h> -# include <sys/stat.h> +# include <sys/wait.h> #endif #include "MEM_guardedalloc.h" @@ -288,6 +296,64 @@ int BLI_access(const char *filename, int mode) return uaccess(filename, mode); } +static bool delete_soft(const wchar_t *path_16, const char **error_message) +{ + /* Deletes file or directory to recycling bin. The latter moves all contained files and + * directories recursively to the recycling bin as well. */ + IFileOperation *pfo; + IShellItem *pSI; + + HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + if (FAILED(hr)) { + *error_message = "Failed to initialize COM"; + goto error_1; + } + + hr = CoCreateInstance( + &CLSID_FileOperation, NULL, CLSCTX_ALL, &IID_IFileOperation, (void **)&pfo); + if (FAILED(hr)) { + *error_message = "Failed to create FileOperation instance"; + goto error_2; + } + + /* Flags for deletion: + * FOF_ALLOWUNDO: Enables moving file to recycling bin. + * FOF_SILENT: Don't show progress dialog box. + * FOF_WANTNUKEWARNING: Show dialog box if file can't be moved to recycling bin. */ + hr = pfo->lpVtbl->SetOperationFlags(pfo, FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING); + + if (FAILED(hr)) { + *error_message = "Failed to set operation flags"; + goto error_2; + } + + hr = SHCreateItemFromParsingName(path_16, NULL, &IID_IShellItem, (void **)&pSI); + if (FAILED(hr)) { + *error_message = "Failed to parse path"; + goto error_2; + } + + hr = pfo->lpVtbl->DeleteItem(pfo, pSI, NULL); + if (FAILED(hr)) { + *error_message = "Failed to prepare delete operation"; + goto error_2; + } + + hr = pfo->lpVtbl->PerformOperations(pfo); + + if (FAILED(hr)) { + *error_message = "Failed to delete file or directory"; + } + +error_2: + pfo->lpVtbl->Release(pfo); + CoUninitialize(); /* Has to be uninitialized when CoInitializeEx returns either S_OK or S_FALSE + */ +error_1: + return FAILED(hr); +} + static bool delete_unique(const char *path, const bool dir) { bool err; @@ -370,6 +436,24 @@ int BLI_delete(const char *file, bool dir, bool recursive) return err; } +/** + * Moves the files or directories to the recycling bin. + */ +int BLI_delete_soft(const char *file, const char **error_message) +{ + int err; + + BLI_assert(!BLI_path_is_rel(file)); + + UTF16_ENCODE(file); + + err = delete_soft(file_16, error_message); + + UTF16_UN_ENCODE(file); + + return err; +} + /* Not used anywhere! */ # if 0 int BLI_move(const char *file, const char *to) @@ -720,6 +804,100 @@ static int delete_single_file(const char *from, const char *UNUSED(to)) return RecursiveOp_Callback_OK; } +# ifdef __APPLE__ +static int delete_soft(const char *file, const char **error_message) +{ + int ret = -1; + + Class NSAutoreleasePoolClass = objc_getClass("NSAutoreleasePool"); + SEL allocSel = sel_registerName("alloc"); + SEL initSel = sel_registerName("init"); + id poolAlloc = ((id(*)(Class, SEL))objc_msgSend)(NSAutoreleasePoolClass, allocSel); + id pool = ((id(*)(id, SEL))objc_msgSend)(poolAlloc, initSel); + + Class NSStringClass = objc_getClass("NSString"); + SEL stringWithUTF8StringSel = sel_registerName("stringWithUTF8String:"); + id pathString = ((id(*)(Class, SEL, const char *))objc_msgSend)( + NSStringClass, stringWithUTF8StringSel, file); + + Class NSFileManagerClass = objc_getClass("NSFileManager"); + SEL defaultManagerSel = sel_registerName("defaultManager"); + id fileManager = ((id(*)(Class, SEL))objc_msgSend)(NSFileManagerClass, defaultManagerSel); + + Class NSURLClass = objc_getClass("NSURL"); + SEL fileURLWithPathSel = sel_registerName("fileURLWithPath:"); + id nsurl = ((id(*)(Class, SEL, id))objc_msgSend)(NSURLClass, fileURLWithPathSel, pathString); + + SEL trashItemAtURLSel = sel_registerName("trashItemAtURL:resultingItemURL:error:"); + BOOL deleteSuccessful = ((BOOL(*)(id, SEL, id, id, id))objc_msgSend)( + fileManager, trashItemAtURLSel, nsurl, nil, nil); + + if (deleteSuccessful) { + ret = 0; + } + else { + *error_message = "The Cocoa API call to delete file or directory failed"; + } + + SEL drainSel = sel_registerName("drain"); + ((void (*)(id, SEL))objc_msgSend)(pool, drainSel); + + return ret; +} +# else +static int delete_soft(const char *file, const char **error_message) +{ + const char *args[5]; + const char *process_failed; + + char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP"); + char *xdg_session_desktop = getenv("XDG_SESSION_DESKTOP"); + + if ((xdg_current_desktop != NULL && strcmp(xdg_current_desktop, "KDE") == 0) || + (xdg_session_desktop != NULL && strcmp(xdg_session_desktop, "KDE") == 0)) { + args[0] = "kioclient5"; + args[1] = "move"; + args[2] = file; + args[3] = "trash:/"; + args[4] = NULL; + process_failed = "kioclient5 reported failure"; + } + else { + args[0] = "gio"; + args[1] = "trash"; + args[2] = file; + args[3] = NULL; + process_failed = "gio reported failure"; + } + + int pid = fork(); + + if (pid != 0) { + /* Parent process */ + int wstatus = 0; + + waitpid(pid, &wstatus, 0); + + if (!WIFEXITED(wstatus)) { + *error_message = + "Blender may not support moving files or directories to trash on your system."; + return -1; + } + else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus)) { + *error_message = process_failed; + return -1; + } + + return 0; + } + + execvp(args[0], (char **)args); + + *error_message = "Forking process failed."; + return -1; /* This should only be reached if execvp fails and stack isn't replaced. */ +} +# endif + FILE *BLI_fopen(const char *filename, const char *mode) { BLI_assert(!BLI_path_is_rel(filename)); @@ -770,6 +948,19 @@ int BLI_delete(const char *file, bool dir, bool recursive) } /** + * Soft deletes the specified file or directory (depending on dir) by moving the files to the + * recycling bin, optionally doing recursive delete of directory contents. + * + * \return zero on success (matching 'remove' behavior). + */ +int BLI_delete_soft(const char *file, const char **error_message) +{ + BLI_assert(!BLI_path_is_rel(file)); + + return delete_soft(file, error_message); +} + +/** * Do the two paths denote the same file-system object? */ static bool check_the_same(const char *path_a, const char *path_b) diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index 08c3653153e..c9b0eb3ed5e 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -907,7 +907,7 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const return 0; } - axis_dominant_v3_to_m3(mat_2d, n); + axis_dominant_v3_to_m3_negate(mat_2d, n); } /* STEP 1: COUNT POLYS */ diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 05a2d766fe0..fd5de717a24 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -209,7 +209,6 @@ int BLI_exists(const char *name) BLI_stat_t st; wchar_t *tmp_16 = alloc_utf16_from_8(name, 1); int len, res; - unsigned int old_error_mode; len = wcslen(tmp_16); /* in Windows #stat doesn't recognize dir ending on a slash diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 545659d06c2..7257c26e1d2 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8240,9 +8240,9 @@ void blo_lib_link_restore(Main *oldmain, } /* Restore all ID pointers in Main database itself - * (especially IDProperties might point to some worspace of other 'weirdly unchanged' ID + * (especially IDProperties might point to some word-space of other 'weirdly unchanged' ID * pointers, see T69146). - * Note that this will re;ap again a few pointers in workspaces or so, + * Note that this will re-apply again a few pointers in workspaces or so, * but since we are remapping final ones already set above, * that is just some minor harmless double-processing. */ lib_link_main_data_restore(id_map, newmain); @@ -10101,7 +10101,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) } else { /* Convert any previously read weak link to regular link - * to signal that we want to read this datablock. */ + * to signal that we want to read this data-block. */ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) { id->flag &= ~LIB_INDIRECT_WEAK_LINK; } @@ -10151,7 +10151,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) } else { /* Convert any previously read weak link to regular link - * to signal that we want to read this datablock. */ + * to signal that we want to read this data-block. */ if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) { id->flag &= ~LIB_INDIRECT_WEAK_LINK; } @@ -12002,7 +12002,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) Main *main_newid = BKE_main_new(); for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) { - /* Drop weak links for which no datablock was found. */ + /* Drop weak links for which no data-block was found. */ read_library_clear_weak_links(basefd, mainlist, mainptr); /* Do versioning for newly added linked data-locks. If no data-locks diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 72013bc6eed..d8e4f3d97a5 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -1673,15 +1673,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) } for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene) { - Sequence *seq; - SEQ_BEGIN (scene->ed, seq) { - if (seq->sat == 0.0f) { - seq->sat = 1.0f; - } + Sequence *seq; + SEQ_BEGIN (scene->ed, seq) { + if (seq->sat == 0.0f) { + seq->sat = 1.0f; } - SEQ_END; } + SEQ_END; } /* GSOC 2010 Sculpt - New settings for Brush */ diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 7ea1d25f86d..9e0d3b7a419 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -585,13 +585,18 @@ static void do_versions_fix_annotations(bGPdata *gpd) } } -static void do_versions_remove_region(ListBase *regionbase, int regiontype) +static void do_versions_remove_region(ListBase *regionbase, ARegion *ar) +{ + BLI_freelinkN(regionbase, ar); +} + +static void do_versions_remove_regions_by_type(ListBase *regionbase, int regiontype) { ARegion *ar, *ar_next; for (ar = regionbase->first; ar; ar = ar_next) { ar_next = ar->next; if (ar->regiontype == regiontype) { - BLI_freelinkN(regionbase, ar); + do_versions_remove_region(regionbase, ar); } } } @@ -1267,6 +1272,22 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) ma->blend_method = MA_BM_BLEND; } } + + { + /* Update all ruler layers to set new flag. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + bGPdata *gpd = scene->gpd; + if (gpd == NULL) { + continue; + } + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (STREQ(gpl->info, "RulerData3D")) { + gpl->flag |= GP_LAYER_IS_RULER; + break; + } + } + } + } } } @@ -3340,7 +3361,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; /* Remove multiple footers that were added by mistake. */ - do_versions_remove_region(regionbase, RGN_TYPE_FOOTER); + do_versions_remove_regions_by_type(regionbase, RGN_TYPE_FOOTER); /* Add footer. */ ARegion *ar = do_versions_add_region(RGN_TYPE_FOOTER, "footer for text"); @@ -3844,8 +3865,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - { - /* Versioning code until next subversion bump goes here. */ + if (!MAIN_VERSION_ATLEAST(bmain, 281, 15)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->toolsettings->snap_node_mode == SCE_SNAP_MODE_NODE_X) { + scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; + } + } + if (!DNA_struct_elem_find( fd->filesdna, "LayerCollection", "short", "local_collections_bits")) { LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { @@ -3887,7 +3913,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) /* We temporarily had two tools regions, get rid of the second one. */ if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) { - do_versions_remove_region(regionbase, RGN_TYPE_TOOLS); + do_versions_remove_region(regionbase, ar_next); } BLI_remlink(regionbase, ar_tools); @@ -3903,4 +3929,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + { + /* Versioning code until next subversion bump goes here. */ + } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 62bd605a2c2..1b30c7371a2 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -1705,19 +1705,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) /* add default radius values to old curve points */ for (cu = bmain->curves.first; cu; cu = cu->id.next) { for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu) { - if (nu->bezt) { - for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { - if (!bezt->radius) { - bezt->radius = 1.0; - } + if (nu->bezt) { + for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { + if (!bezt->radius) { + bezt->radius = 1.0; } } - else if (nu->bp) { - for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { - if (!bp->radius) { - bp->radius = 1.0; - } + } + else if (nu->bp) { + for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (!bp->radius) { + bp->radius = 1.0; } } } @@ -2515,17 +2513,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) for (cu = bmain->curves.first; cu; cu = cu->id.next) { for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu) { - nu->radius_interp = 3; - - /* resolu and resolv are now used differently for surfaces - * rather than using the resolution to define the entire number of divisions, - * use it for the number of divisions per segment - */ - if (nu->pntsv > 1) { - nu->resolu = MAX2(1, (int)(((float)nu->resolu / (float)nu->pntsu) + 0.5f)); - nu->resolv = MAX2(1, (int)(((float)nu->resolv / (float)nu->pntsv) + 0.5f)); - } + nu->radius_interp = 3; + + /* resolu and resolv are now used differently for surfaces + * rather than using the resolution to define the entire number of divisions, + * use it for the number of divisions per segment + */ + if (nu->pntsv > 1) { + nu->resolu = MAX2(1, (int)(((float)nu->resolu / (float)nu->pntsu) + 0.5f)); + nu->resolv = MAX2(1, (int)(((float)nu->resolv / (float)nu->pntsv) + 0.5f)); } } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index bbae1c8e85e..d2192f1e22a 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -30,6 +30,7 @@ #include "DNA_windowmanager_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" +#include "DNA_anim_types.h" #include "BKE_addon.h" #include "BKE_colorband.h" @@ -146,14 +147,18 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_outliner.active); } - /** - * Include next version bump. - */ - { + if (!USER_VERSION_ATLEAST(281, 14)) { FROM_DEFAULT_V4_UCHAR(space_file.execution_buts); FROM_DEFAULT_V4_UCHAR(tui.icon_folder); FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_before); FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_after); + copy_v4_v4_uchar(btheme->space_nla.nla_track, btheme->space_nla.header); + } + + /** + * Include next version bump. + */ + { } #undef FROM_DEFAULT_V4_UCHAR @@ -623,15 +628,20 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef) userdef->filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW; } + if (!USER_VERSION_ATLEAST(281, 13)) { + userdef->auto_smoothing_new = FCURVE_SMOOTH_CONT_ACCEL; + + if (userdef->file_space_data.display_type == FILE_DEFAULTDISPLAY) { + memcpy( + &userdef->file_space_data, &U_default.file_space_data, sizeof(userdef->file_space_data)); + } + } + /** * Include next version bump. */ { /* pass */ - if (userdef->file_space_data.display_type == FILE_DEFAULTDISPLAY) { - memcpy( - &userdef->file_space_data, &U_default.file_space_data, sizeof(userdef->file_space_data)); - } } if (userdef->pixelsize == 0.0f) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index aae5072c8de..d24fca4391a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -26,35 +26,36 @@ * FILE FORMAT * =========== * - * IFF-style structure (but not IFF compatible!) + * IFF-style structure (but not IFF compatible!) * - * start file: + * Start file: * <pre> - * BLENDER_V100 12 bytes (version 1.00) - * V = big endian, v = little endian - * _ = 4 byte pointer, - = 8 byte pointer + * `BLENDER_V100` `12` bytes (version 1.00 is just an example). + * `V` = big endian, `v` = little endian. + * `_` = 4 byte pointer, `-` = 8 byte pointer. * </pre> * * data-blocks: (also see struct #BHead). * <pre> - * <bh.code> 4 chars - * <bh.len> int, len data after BHead - * <bh.old> void, old pointer - * <bh.SDNAnr> int - * <bh.nr> int, in case of array: number of structs - * data - * ... - * ... + * `bh.code` `char[4]` see `BLO_blend_defs.h` for a list of known types. + * `bh.len` `int32` length data after #BHead in bytes. + * `bh.old` `void *` old pointer (the address at the time of writing the file). + * `bh.SDNAnr` `int32` struct index of structs stored in #DNA1 data. + * `bh.nr` `int32` in case of array: number of structs. + * data + * ... + * ... * </pre> * * Almost all data in Blender are structures. Each struct saved * gets a BHead header. With BHead the struct can be linked again - * and compared with StructDNA . + * and compared with #StructDNA. + * WRITE * ===== * * Preferred writing order: (not really a must, but why would you do it random?) - * Any case: direct data is ALWAYS after the lib block + * Any case: direct data is ALWAYS after the lib block. * * (Local file data) * - for each LibBlock diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt index 1b46efb1bb5..0361137f5b1 100644 --- a/source/blender/blentranslation/msgfmt/CMakeLists.txt +++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt @@ -32,6 +32,10 @@ set(SRC add_cc_flags_custom_test(msgfmt) +if(APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}") +endif() + add_executable(msgfmt ${SRC}) target_link_libraries(msgfmt bf_blenlib) diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index ff7dcc388b3..64687ac154c 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1507,7 +1507,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) 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.000001); + BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.0000005 * depth); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 79593f07383..47325c4dece 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -104,7 +104,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED); fcu->array_index = 0; - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; for (unsigned int j = 0; j < curve->getKeyCount(); j++) { BezTriple bez; diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp index bf32ec9148c..f944a77196c 100644 --- a/source/blender/collada/BCAnimationCurve.cpp +++ b/source/blender/collada/BCAnimationCurve.cpp @@ -383,7 +383,7 @@ void BCAnimationCurve::adjust_range(const int frame_index) void BCAnimationCurve::add_value(const float val, const int frame_index) { FCurve *fcu = get_edit_fcurve(); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; insert_vert_fcurve(fcu, frame_index, val, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NOFLAGS); if (fcu->totvert == 1) { diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index 71201c8a55c..6e31e17fb26 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -107,7 +107,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) /* make absolute source path */ BLI_strncpy(source_path, image->name, sizeof(source_path)); - BLI_path_abs(source_path, BKE_main_blendfile_path_from_global()); + BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id)); BLI_cleanup_path(NULL, source_path); if (use_copies) { diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 2a8914c8cd9..f0685b169fa 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -566,6 +566,7 @@ if(WITH_OPENIMAGEDENOISE) add_definitions(-DOIDN_STATIC_LIB) list(APPEND INC_SYS ${OPENIMAGEDENOISE_INCLUDE_DIRS} + ${TBB_INCLUDE_DIRS} ) endif() diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index e44dddbcf54..d5a93d21b99 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -179,14 +179,14 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSce /* Evaluation ----------------------------------- */ +bool DEG_is_evaluating(struct Depsgraph *depsgraph); + bool DEG_is_active(const struct Depsgraph *depsgraph); void DEG_make_active(struct Depsgraph *depsgraph); void DEG_make_inactive(struct Depsgraph *depsgraph); /* Evaluation Debug ------------------------------ */ -bool DEG_debug_is_evaluating(struct Depsgraph *depsgraph); - void DEG_debug_print_begin(struct Depsgraph *depsgraph); void DEG_debug_print_eval(struct Depsgraph *depsgraph, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 7dfc863b847..d0e40d49527 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -527,6 +527,9 @@ void DepsgraphNodeBuilder::build_object(int base_index, eDepsNode_LinkedState_Type linked_state, bool is_visible) { + if (object->proxy != NULL) { + object->proxy->proxy_from = object; + } const bool has_object = built_map_.checkIsBuiltAndTag(object); /* Skip rest of components if the ID node was already there. */ if (has_object) { diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index dcdea87fe1a..8f9595d2476 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -76,7 +76,7 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati ctime(BKE_scene_frame_get(scene)), scene_cow(NULL), is_active(false), - debug_is_evaluating(false), + is_evaluating(false), is_render_pipeline_depsgraph(false) { BLI_spin_init(&lock); @@ -334,6 +334,12 @@ void DEG_graph_free(Depsgraph *graph) OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph); } +bool DEG_is_evaluating(struct Depsgraph *depsgraph) +{ + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + return deg_graph->is_evaluating; +} + bool DEG_is_active(const struct Depsgraph *depsgraph) { if (depsgraph == NULL) { diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 30ae4edde34..43829f4e045 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -198,7 +198,7 @@ struct Depsgraph { int debug_flags; string debug_name; - bool debug_is_evaluating; + bool is_evaluating; /* Is set to truth for dependency graph which are used for post-processing (compositor and * sequencer). diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index d079c958e04..bb60db5209c 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -246,12 +246,6 @@ void DEG_stats_simple(const Depsgraph *graph, } } -bool DEG_debug_is_evaluating(struct Depsgraph *depsgraph) -{ - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); - return deg_graph->debug_is_evaluating; -} - static DEG::string depsgraph_name_for_logging(struct Depsgraph *depsgraph) { const char *name = DEG_debug_name_get(depsgraph); diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index b2b7d2a9d00..665a32b886c 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -73,7 +73,7 @@ void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime) /* Update time on primary timesource. */ DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); tsrc->cfra = ctime; - tsrc->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_TIME); + deg_graph->need_update_time = true; DEG::deg_graph_flush_updates(bmain, deg_graph); /* Update time in scene. */ if (deg_graph->scene_cow) { diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 28789968286..db469612f76 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -152,7 +152,7 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) copy_v4_v4(temp_dupli_object->color, dupli_parent->color); /* Duplicated elements shouldn't care whether their original collection is visible or not. */ - temp_dupli_object->base_flag |= BASE_VISIBLE; + temp_dupli_object->base_flag |= BASE_VISIBLE_DEPSGRAPH; int ob_visibility = BKE_object_visibility(temp_dupli_object, data->eval_mode); if ((ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) == 0) { diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 2fdce0e30a5..ce5917110d6 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -367,7 +367,7 @@ static void graph_id_tag_update_single_flag(Main *bmain, eUpdateSource update_source) { if (tag == ID_RECALC_EDITORS) { - if (graph != NULL) { + if (graph != NULL && graph->is_active) { depsgraph_update_editors_tag(bmain, graph, id); } return; @@ -462,7 +462,8 @@ const char *update_source_as_string(eUpdateSource source) int deg_recalc_flags_for_legacy_zero() { - return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE); + return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE | + ID_RECALC_TIME | ID_RECALC_EDITORS); } int deg_recalc_flags_effective(Depsgraph *graph, int flags) @@ -510,6 +511,14 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti * to evaluation though) with `do_time=true`. This means early output checks should be aware of * this. */ for (DEG::IDNode *id_node : graph->id_nodes) { + const ID_Type id_type = GS(id_node->id_orig->name); + if (id_type == ID_OB) { + Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig); + if (object_orig->proxy != NULL) { + object_orig->proxy->proxy_from = object_orig; + } + } + if (!id_node->visible_components_mask) { /* ID has no components which affects anything visible. * No need bother with it to tag or anything. */ @@ -536,7 +545,6 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti * other type of cache). * * TODO(sergey): Need to generalize this somehow. */ - const ID_Type id_type = GS(id_node->id_orig->name); if (id_type == ID_OB) { flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; } @@ -614,6 +622,12 @@ void graph_id_tag_update( Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) { const int debug_flags = (graph != NULL) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug; + if (graph != NULL && graph->is_evaluating) { + if (debug_flags & G_DEBUG_DEPSGRAPH) { + printf("ID tagged for update during dependency graph evaluation."); + } + return; + } if (debug_flags & G_DEBUG_DEPSGRAPH_TAG) { printf("%s: id=%s flags=%s source=%s\n", __func__, @@ -808,24 +822,6 @@ static void deg_graph_clear_id_recalc_flags(ID *id) } } -static void deg_graph_clear_id_node_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) -{ - /* TODO: we clear original ID recalc flags here, but this may not work - * correctly when there are multiple depsgraph with others still using - * the recalc flag. */ - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(data_v); - DEG::IDNode *id_node = deg_graph->id_nodes[i]; - - id_node->is_user_modified = false; - - deg_graph_clear_id_recalc_flags(id_node->id_cow); - if (deg_graph->is_active) { - deg_graph_clear_id_recalc_flags(id_node->id_orig); - } -} - void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph) { DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); @@ -835,10 +831,15 @@ void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph) return; } /* Go over all ID nodes nodes, clearing tags. */ - const int num_id_nodes = deg_graph->id_nodes.size(); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_id_nodes, deg_graph, deg_graph_clear_id_node_func, &settings); + for (DEG::IDNode *id_node : deg_graph->id_nodes) { + /* TODO: we clear original ID recalc flags here, but this may not work + * correctly when there are multiple depsgraph with others still using + * the recalc flag. */ + id_node->is_user_modified = false; + deg_graph_clear_id_recalc_flags(id_node->id_cow); + if (deg_graph->is_active) { + deg_graph_clear_id_recalc_flags(id_node->id_orig); + } + } memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated)); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index b2415c9e89d..d6b3c54a149 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -91,10 +91,6 @@ static void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id) BLI_task_pool_delayed_push_end(pool, thread_id); } -struct CalculatePendingData { - Depsgraph *graph; -}; - static bool check_operation_node_visible(OperationNode *op_node) { const ComponentNode *comp_node = op_node->owner; @@ -106,13 +102,8 @@ static bool check_operation_node_visible(OperationNode *op_node) return comp_node->affects_directly_visible; } -static void calculate_pending_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) +static void calculate_pending_parents_for_node(OperationNode *node) { - CalculatePendingData *data = (CalculatePendingData *)data_v; - Depsgraph *graph = data->graph; - OperationNode *node = graph->operations[i]; /* Update counters, applies for both visible and invisible IDs. */ node->num_links_pending = 0; node->scheduled = false; @@ -134,7 +125,7 @@ static void calculate_pending_func(void *__restrict data_v, if (!check_operation_node_visible(from)) { continue; } - /* No need to vait for operation which is up to date. */ + /* No need to wait for operation which is up to date. */ if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { continue; } @@ -145,13 +136,9 @@ static void calculate_pending_func(void *__restrict data_v, static void calculate_pending_parents(Depsgraph *graph) { - const int num_operations = graph->operations.size(); - CalculatePendingData data; - data.graph = graph; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, &settings); + for (OperationNode *node : graph->operations) { + calculate_pending_parents_for_node(node); + } } static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph) @@ -221,7 +208,7 @@ static void schedule_node( static void schedule_graph(TaskPool *pool, Depsgraph *graph) { for (OperationNode *node : graph->operations) { - schedule_node(pool, graph, node, false, 0); + schedule_node(pool, graph, node, false, -1); } } @@ -270,7 +257,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph) } const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0); const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0; - graph->debug_is_evaluating = true; + graph->is_evaluating = true; depsgraph_ensure_view_layer(graph); /* Set up evaluation state. */ DepsgraphEvalState state; @@ -311,7 +298,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph) if (need_free_scheduler) { BLI_task_scheduler_free(task_scheduler); } - graph->debug_is_evaluating = false; + graph->is_evaluating = false; if (do_time_debug) { printf("Depsgraph updated in %f seconds.\n", PIL_check_seconds_timer() - start_time); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 2479373b687..96e2974a7ab 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -87,15 +87,6 @@ typedef std::deque<OperationNode *> FlushQueue; namespace { -void flush_init_operation_node_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) -{ - Depsgraph *graph = (Depsgraph *)data_v; - OperationNode *node = graph->operations[i]; - node->scheduled = false; -} - void flush_init_id_node_func(void *__restrict data_v, const int i, const TaskParallelTLS *__restrict /*tls*/) @@ -110,13 +101,10 @@ void flush_init_id_node_func(void *__restrict data_v, BLI_INLINE void flush_prepare(Depsgraph *graph) { - { - const int num_operations = graph->operations.size(); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, graph, flush_init_operation_node_func, &settings); + for (OperationNode *node : graph->operations) { + node->scheduled = false; } + { const int num_id_nodes = graph->id_nodes.size(); TaskParallelSettings settings; @@ -351,9 +339,6 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) BLI_assert(bmain != NULL); BLI_assert(graph != NULL); /* Nothing to update, early out. */ - if (BLI_gset_len(graph->entry_tags) == 0 && !graph->need_update_time) { - return; - } if (graph->need_update_time) { const Scene *scene_orig = graph->scene; const float ctime = BKE_scene_frame_get(scene_orig); @@ -361,6 +346,9 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) graph->ctime = ctime; time_source->tag_update(graph, DEG::DEG_UPDATE_SOURCE_TIME); } + if (BLI_gset_len(graph->entry_tags) == 0) { + return; + } /* Reset all flags, get ready for the flush. */ flush_prepare(graph); /* Starting from the tagged "entry" nodes, flush outwards. */ @@ -395,27 +383,13 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) invalidate_tagged_evaluated_data(graph); } -static void graph_clear_operation_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) -{ - Depsgraph *graph = (Depsgraph *)data_v; - OperationNode *node = graph->operations[i]; - /* Clear node's "pending update" settings. */ - node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE | - DEPSOP_FLAG_USER_MODIFIED); -} - /* Clear tags from all operation nodes. */ void deg_graph_clear_tags(Depsgraph *graph) { /* Go over all operation nodes, clearing tags. */ - { - const int num_operations = graph->operations.size(); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, graph, graph_clear_operation_func, &settings); + for (OperationNode *node : graph->operations) { + node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE | + DEPSOP_FLAG_USER_MODIFIED); } /* Clear any entry tags which haven't been flushed. */ BLI_gset_clear(graph->entry_tags, NULL); diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 188e252a285..0dd1a4fd686 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -72,7 +72,6 @@ static struct { typedef struct BASIC_PrivateData { DRWShadingGroup *depth_shgrp; DRWShadingGroup *depth_shgrp_cull; - DRWShadingGroup *depth_shgrp_hair; } BASIC_PrivateData; /* Transient data */ /* Functions */ diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 7df1c299454..d59d1f56e92 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -29,6 +29,7 @@ #include "eevee_private.h" #include "GPU_texture.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_state.h" static struct { diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 19f3983998e..4b0af273f7f 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -51,7 +51,6 @@ static struct { struct GPUTexture *planar_pool_placeholder; struct GPUTexture *depth_placeholder; struct GPUTexture *depth_array_placeholder; - struct GPUTexture *cube_face_minmaxz; struct GPUVertFormat *format_probe_display_cube; struct GPUVertFormat *format_probe_display_planar; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index f01c6363ccb..701d73461fc 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1588,7 +1588,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* Shadow Pass */ struct GPUMaterial *gpumat; - switch (ma_array[i]->blend_shadow) { + const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree); + char blend_shadow = use_gpumat ? ma_array[i]->blend_shadow : MA_BS_SOLID; + switch (blend_shadow) { case MA_BS_SOLID: EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob); *cast_shadow = true; diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index 924b3d3b19b..48e9b5bcc13 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -33,6 +33,7 @@ #include "eevee_private.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_state.h" static struct { @@ -40,7 +41,6 @@ static struct { struct GPUShader *gtao_sh; struct GPUShader *gtao_layer_sh; struct GPUShader *gtao_debug_sh; - struct GPUTexture *src_depth; struct GPUTexture *dummy_horizon_tx; } e_data = {NULL}; /* Engine data */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 2daf2388d63..591ca31017c 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -46,7 +46,6 @@ static struct { /* These are just references, not actually allocated */ struct GPUTexture *depth_src; - struct GPUTexture *color_src; } e_data = {{NULL}}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index fac87bad41a..aaa351a1922 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -54,7 +54,6 @@ static struct { struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh; - GPUTexture *color_src; GPUTexture *depth_src; GPUTexture *dummy_density; diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 98012aea303..1f68935403c 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -918,14 +918,15 @@ void main() Closure cl = nodetree_exec(); float holdout = 1.0 - saturate(cl.holdout); + float transmit = saturate(avg(cl.transmittance)); + float alpha = 1.0 - transmit; # ifdef USE_ALPHA_BLEND vec2 uvs = gl_FragCoord.xy * volCoordScale.zw; vec3 vol_transmit, vol_scatter; volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter); - float transmit = saturate(avg(cl.transmittance)); - outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, (1.0 - transmit) * holdout); + outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, alpha * holdout); outTransmittance = vec4(cl.transmittance, transmit * holdout); # else outRadiance = vec4(cl.radiance, holdout); @@ -953,6 +954,15 @@ void main() outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac; # endif + +# ifndef USE_ALPHA_BLEND + float alpha_div = 1.0 / max(1e-8, alpha); + outRadiance *= alpha_div; + ssrData.rgb *= alpha_div; +# ifdef USE_SSS + sssAlbedo.rgb *= alpha_div; +# endif +# endif } # endif /* MESH_SHADER && !SHADOW_SHADER */ diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 33e6d73eeeb..f9df1342bf8 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -50,10 +50,6 @@ static bool gpencil_has_noninstanced_object(Object *ob_instance) if (ob->type != OB_GPENCIL) { continue; } - /* object must be visible (invisible objects don't create VBO data) */ - if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { - continue; - } /* is not duplicated and the name is equals */ if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { if (STREQ(ob->id.name, ob_instance->id.name)) { diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index ce5d8cbf732..0997568ed22 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -37,7 +37,6 @@ #include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_view3d_types.h" -#include "DNA_gpencil_modifier_types.h" /* If builtin shaders are needed */ #include "GPU_shader.h" @@ -141,13 +140,9 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl, Object *ob = cache_ob->ob; const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool main_onion = draw_ctx->v3d != NULL ? - (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : - true; + const bool main_onion = stl->storage->is_main_onion; const bool playing = stl->storage->is_playing; - const bool overlay = draw_ctx->v3d != NULL ? - (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : - true; + const bool overlay = stl->storage->is_main_overlay; const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && main_onion && !playing && gpencil_onion_active(gpd); @@ -225,23 +220,6 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl, cache->b_point.tot_vertex = cache_ob->tot_vertex; cache->b_edit.tot_vertex = cache_ob->tot_vertex; cache->b_edlin.tot_vertex = cache_ob->tot_vertex; - - /* some modifiers can change the number of points */ - int factor = 0; - GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - /* only modifiers that change size */ - if (mti && mti->getDuplicationFactor) { - factor = mti->getDuplicationFactor(md); - - cache->b_fill.tot_vertex *= factor; - cache->b_stroke.tot_vertex *= factor; - cache->b_point.tot_vertex *= factor; - cache->b_edit.tot_vertex *= factor; - cache->b_edlin.tot_vertex *= factor; - } - } } /* Helper for doing all the checks on whether a stroke can be drawn */ @@ -1781,8 +1759,8 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data, const bool overlay = draw_ctx->v3d != NULL ? (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true; - const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; - const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion && + const bool screen_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; + const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && screen_onion && overlay && gpencil_onion_active(gpd); int start_stroke = 0; @@ -2062,13 +2040,9 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data, bGPdata *gpd_eval = (bGPdata *)ob->data; bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id); - const bool main_onion = draw_ctx->v3d != NULL ? - (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : - true; + const bool main_onion = stl->storage->is_main_onion; const bool playing = stl->storage->is_playing; - const bool overlay = draw_ctx->v3d != NULL ? - (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : - true; + const bool overlay = stl->storage->is_main_overlay; const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && main_onion && !playing && gpencil_onion_active(gpd); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 7d9f2d1fdf3..aed6789fe26 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -24,11 +24,13 @@ #include "BKE_gpencil.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_shader_fx.h" #include "DNA_gpencil_types.h" +#include "DNA_screen_types.h" #include "DNA_view3d_types.h" #include "draw_mode_engines.h" @@ -310,6 +312,43 @@ static void GPENCIL_engine_free(void) GPENCIL_delete_fx_shaders(&e_data); } +/* Helper: Check if the main overlay and onion switches are enabled in any screen. + * + * This is required to generate the onion skin and limit the times the cache is updated because the + * cache is generated only in the first screen and if the first screen has the onion disabled the + * cache for onion skin is not generated. The loop adds time, but always is faster than regenerate + * the cache all the times. + */ +static void gpencil_check_screen_switches(const DRWContextState *draw_ctx, + GPENCIL_StorageList *stl) +{ + stl->storage->is_main_overlay = false; + stl->storage->is_main_onion = false; + /* Check if main onion switch is enabled in any screen. */ + Main *bmain = CTX_data_main(draw_ctx->evil_C); + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + if (sa && sa->spacetype == SPACE_VIEW3D) { + View3D *v3d = sa->spacedata.first; + if (v3d == NULL) { + continue; + } + if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) { + stl->storage->is_main_overlay = true; + } + if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) { + stl->storage->is_main_onion = true; + } + } + /* If found, don't need loop more. */ + if ((stl->storage->is_main_overlay) && (stl->storage->is_main_onion)) { + return; + } + } + } +} + void GPENCIL_cache_init(void *vedata) { GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; @@ -320,6 +359,7 @@ void GPENCIL_cache_init(void *vedata) ToolSettings *ts = scene->toolsettings; View3D *v3d = draw_ctx->v3d; Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); + const View3DCursor *cursor = &scene->cursor; /* Special handling for when active object is GP object (e.g. for draw mode) */ Object *obact = draw_ctx->obact; @@ -395,10 +435,15 @@ void GPENCIL_cache_init(void *vedata) stl->storage->reset_cache = true; } stl->storage->is_playing = playing; + + /* Found if main overlay and onion switches are enabled in any screen. */ + gpencil_check_screen_switches(draw_ctx, stl); } else { stl->storage->is_playing = false; stl->storage->reset_cache = false; + stl->storage->is_main_overlay = false; + stl->storage->is_main_onion = false; } /* save render state */ stl->storage->is_render = DRW_state_is_image_render(); @@ -546,11 +591,42 @@ void GPENCIL_cache_init(void *vedata) } /* grid pass */ - if (v3d) { + if ((v3d) && (obact) && (obact->type == OB_GPENCIL)) { psl->grid_pass = DRW_pass_create("GPencil Grid Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass); + + /* define grid orientation */ + switch (ts->gp_sculpt.lock_axis) { + case GP_LOCKAXIS_VIEW: { + /* align always to view */ + invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat); + /* copy ob location */ + copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]); + break; + } + case GP_LOCKAXIS_CURSOR: { + float scale[3] = {1.0f, 1.0f, 1.0f}; + loc_eul_size_to_mat4( + stl->storage->grid_matrix, cursor->location, cursor->rotation_euler, scale); + break; + } + default: { + copy_m4_m4(stl->storage->grid_matrix, obact->obmat); + break; + } + } + + /* Move the origin to Object or Cursor */ + if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { + copy_v3_v3(stl->storage->grid_matrix[3], cursor->location); + } + else { + copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]); + } + DRW_shgroup_uniform_mat4( + stl->g_data->shgrps_grid, "gpModelMatrix", stl->storage->grid_matrix); } /* blend layers pass */ @@ -633,8 +709,6 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) Scene *scene = draw_ctx->scene; ToolSettings *ts = scene->toolsettings; View3D *v3d = draw_ctx->v3d; - const View3DCursor *cursor = &scene->cursor; - float grid_matrix[4][4]; if (ob->type == OB_GPENCIL && ob->data) { bGPdata *gpd = (bGPdata *)ob->data; @@ -695,36 +769,7 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) == 0)) { stl->g_data->batch_grid = gpencil_get_grid(ob); - - /* define grid orientation */ - switch (ts->gp_sculpt.lock_axis) { - case GP_LOCKAXIS_VIEW: { - /* align always to view */ - invert_m4_m4(grid_matrix, draw_ctx->rv3d->viewmat); - /* copy ob location */ - copy_v3_v3(grid_matrix[3], ob->obmat[3]); - break; - } - case GP_LOCKAXIS_CURSOR: { - float scale[3] = {1.0f, 1.0f, 1.0f}; - loc_eul_size_to_mat4(grid_matrix, cursor->location, cursor->rotation_euler, scale); - break; - } - default: { - copy_m4_m4(grid_matrix, ob->obmat); - break; - } - } - - /* Move the origin to Object or Cursor */ - if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { - copy_v3_v3(grid_matrix[3], cursor->location); - } - else { - copy_v3_v3(grid_matrix[3], ob->obmat[3]); - } - - DRW_shgroup_call_obmat(stl->g_data->shgrps_grid, stl->g_data->batch_grid, grid_matrix); + DRW_shgroup_call(stl->g_data->shgrps_grid, stl->g_data->batch_grid, NULL); } } } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index c475c343d22..5638639cbf2 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -145,6 +145,8 @@ typedef struct GPENCIL_Storage { bool is_playing; bool is_render; bool is_mat_preview; + bool is_main_overlay; + bool is_main_onion; bool background_ready; int is_xray; bool is_ontop; @@ -155,6 +157,7 @@ typedef struct GPENCIL_Storage { int do_select_outline; float select_color[4]; short multisamples; + float grid_matrix[4][4]; short framebuffer_flag; /* flag what framebuffer need to create */ diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 15522ba0dfb..2e8b952f234 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -78,7 +78,6 @@ static struct { struct GPUTexture *object_id_tx; /* ref only, not alloced */ struct GPUTexture *color_buffer_tx; /* ref only, not alloced */ struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *metallic_buffer_tx; /* ref only, not alloced */ struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */ struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index ac27ff0b736..941a6741998 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -131,7 +131,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd, static void compute_parallel_lines_nor_and_dist(const float v1[2], const float v2[2], const float v3[2], - float r_line[2]) + float r_line[4]) { sub_v2_v2v2(r_line, v2, v1); /* Find orthogonal vector. */ diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index e017661b6cd..23f0898c138 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -46,8 +46,6 @@ enum { static struct { struct GPUShader *volume_sh[VOLUME_SH_MAX]; struct GPUShader *volume_coba_sh; - struct GPUShader *volume_slice_sh; - struct GPUShader *volume_slice_coba_sh; struct GPUTexture *dummy_tex; struct GPUTexture *dummy_coba_tex; } e_data = {{NULL}}; diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 865cfea14e3..5cd6a4a1286 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -60,7 +60,6 @@ static struct { Object *ob; /* Reset when changing current_armature */ DRWCallBuffer *bone_octahedral_solid; - DRWCallBuffer *bone_octahedral_wire; DRWCallBuffer *bone_octahedral_outline; DRWCallBuffer *bone_box_solid; DRWCallBuffer *bone_box_wire; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 019098e5b90..b085d402e81 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -53,7 +53,6 @@ static struct DRWShapeCache { GPUBatch *drw_cursor; GPUBatch *drw_cursor_only_circle; GPUBatch *drw_fullscreen_quad; - GPUBatch *drw_fullscreen_quad_texcoord; GPUBatch *drw_quad; GPUBatch *drw_quad_wires; GPUBatch *drw_grid; @@ -72,8 +71,6 @@ static struct DRWShapeCache { GPUBatch *drw_empty_capsule_body; GPUBatch *drw_empty_capsule_cap; GPUBatch *drw_empty_cone; - GPUBatch *drw_arrows; - GPUBatch *drw_axis_names; GPUBatch *drw_image_plane; GPUBatch *drw_image_plane_wire; GPUBatch *drw_field_wind; @@ -99,7 +96,6 @@ static struct DRWShapeCache { GPUBatch *drw_bone_octahedral_wire; GPUBatch *drw_bone_box; GPUBatch *drw_bone_box_wire; - GPUBatch *drw_bone_wire_wire; GPUBatch *drw_bone_envelope; GPUBatch *drw_bone_envelope_outline; GPUBatch *drw_bone_point; @@ -111,7 +107,6 @@ static struct DRWShapeCache { GPUBatch *drw_camera; GPUBatch *drw_camera_frame; GPUBatch *drw_camera_tria; - GPUBatch *drw_camera_focus; GPUBatch *drw_particle_cross; GPUBatch *drw_particle_circle; GPUBatch *drw_particle_axis; diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index 75b8d820884..46193e255b5 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -48,6 +48,9 @@ typedef struct DRW_MeshCDMask { uint32_t vcol : 8; uint32_t orco : 1; uint32_t tan_orco : 1; + /** Edit uv layer is from the base edit mesh as + * modifiers could remove it. (see T68857) */ + uint32_t edit_uv : 1; } DRW_MeshCDMask; typedef enum eMRIterType { diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index 40a36acc3d9..2ac97196b99 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -1601,6 +1601,14 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; uint32_t uv_layers = mr->cache->cd_used.uv; + /* HACK to fix T68857 */ + if (mr->extract_type == MR_EXTRACT_BMESH && mr->cache->cd_used.edit_uv == 1) { + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + uv_layers |= (1 << layer); + } + } + for (int i = 0; i < MAX_MTFACE; i++) { if (uv_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME]; diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 4a69aa3e008..b8b657354b2 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -90,9 +90,15 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a) *((uint32_t *)a) = 0; } +static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used) +{ + cd_used->edit_uv = 1; +} + static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { @@ -102,7 +108,8 @@ 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 CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { @@ -112,7 +119,8 @@ 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 CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); if (layer != -1) { @@ -124,7 +132,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, struct GPUMaterial **gpumat_array, int gpumat_array_len) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -227,7 +236,8 @@ static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me, int **r_auto_layers_srgb, int *r_auto_layers_len) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int uv_len_used = count_bits_i(cd_used.uv); int vcol_len_used = count_bits_i(cd_used.vcol); @@ -458,6 +468,16 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, } } +static void mesh_batch_cache_discard_shaded_batches(MeshBatchCache *cache) +{ + if (cache->surface_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); + } + } + cache->batch_ready &= ~MBC_SURF_PER_MAT; +} + static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) { FOREACH_MESH_BUFFER_CACHE(cache, mbufcache) @@ -468,21 +488,13 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol); GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco); } + mesh_batch_cache_discard_shaded_batches(cache); + mesh_cd_layers_type_clear(&cache->cd_used); - if (cache->surface_per_mat) { - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); - } - } MEM_SAFE_FREE(cache->surface_per_mat); - - cache->batch_ready &= ~MBC_SURF_PER_MAT; - MEM_SAFE_FREE(cache->auto_layer_names); MEM_SAFE_FREE(cache->auto_layer_is_srgb); - mesh_cd_layers_type_clear(&cache->cd_used); - cache->mat_len = 0; } @@ -513,6 +525,37 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) cache->tot_uv_area = 0.0f; cache->batch_ready &= ~MBC_EDITUV; + + /* We discarded the vbo.uv so we need to reset the cd_used flag. */ + cache->cd_used.uv = 0; + cache->cd_used.edit_uv = 0; + + /* Discard other batches that uses vbo.uv */ + mesh_batch_cache_discard_shaded_batches(cache); + + GPU_BATCH_DISCARD_SAFE(cache->batch.surface); + cache->batch_ready &= ~MBC_SURFACE; +} + +static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) +{ + FOREACH_MESH_BUFFER_CACHE(cache, mbufcache) + { + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots); + } + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots); + GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs); + cache->batch_ready &= ~MBC_EDITUV; } void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) @@ -541,8 +584,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS | MBC_EDIT_SELECTION_FACES | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_VERTS | MBC_EDIT_MESH_ANALYSIS); - /* Because visible UVs depends on edit mode selection, discard everything. */ - mesh_batch_cache_discard_uvedit(cache); + /* Because visible UVs depends on edit mode selection, discard topology. */ + mesh_batch_cache_discard_uvedit_select(cache); break; case BKE_MESH_BATCH_DIRTY_SELECT_PAINT: /* Paint mode selection flag is packed inside the nor attrib. @@ -876,6 +919,19 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me) /** \name UV Image editor API * \{ */ +static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_edit_uv_layer(me, &cd_needed); + + BLI_assert(cd_needed.edit_uv != 0 && + "No uv layer available in edituv, but batches requested anyway!"); + + mesh_cd_calc_active_mask_uv_layer(me, &cd_needed); + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + /* Creates the GPUBatch for drawing the UV Stretching Area Overlay. * Optional retrieves the total area or total uv area of the mesh. * @@ -886,7 +942,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me, float **tot_uv_area) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA); if (tot_area != NULL) { @@ -901,7 +957,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me, GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE); return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle); } @@ -909,7 +965,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES); return DRW_batch_request(&cache->batch.edituv_faces); } @@ -917,7 +973,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES); return DRW_batch_request(&cache->batch.edituv_edges); } @@ -925,7 +981,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS); return DRW_batch_request(&cache->batch.edituv_verts); } @@ -933,7 +989,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS); return DRW_batch_request(&cache->batch.edituv_fdots); } @@ -941,7 +997,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS); return DRW_batch_request(&cache->batch.wire_loops_uvs); } @@ -1108,9 +1164,6 @@ void DRW_mesh_batch_cache_create_requested( FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_angle); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_area); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv); GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv); GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris); GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines); diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 7f679dd5581..988859c64a5 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -277,7 +277,6 @@ static struct { struct GPUVertFormat *instance_scaled; struct GPUVertFormat *instance_sized; struct GPUVertFormat *instance_outline; - struct GPUVertFormat *instance; struct GPUVertFormat *instance_camera; struct GPUVertFormat *instance_distance_lines; struct GPUVertFormat *instance_spot; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 6387cecc01f..9e28627ba3d 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -164,7 +164,7 @@ struct DRWTextStore *DRW_text_cache_ensure(void) bool DRW_object_is_renderable(const Object *ob) { - BLI_assert((ob->base_flag & BASE_VISIBLE) != 0); + BLI_assert((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0); if (ob->type == OB_MESH) { if ((ob == DST.draw_ctx.object_edit) || BKE_object_is_in_editmode(ob)) { @@ -1171,7 +1171,7 @@ static void drw_engines_cache_finish(void) MEM_freeN(DST.vedata_array); } -static void drw_engines_draw_background(void) +static bool drw_engines_draw_background(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; @@ -1185,10 +1185,20 @@ static void drw_engines_draw_background(void) DRW_stats_group_end(); PROFILE_END_UPDATE(data->background_time, stime); - return; + return true; } } + /* No draw engines draw the background. We clear the background. + * We draw the background after drawing of the scene so the camera background + * images can be drawn using ALPHA Under. Otherwise the background always + * interfered with the alpha blending. */ + DRW_clear_background(); + return false; +} + +static void drw_draw_background_alpha_under(void) +{ /* No draw_background found, doing default background */ const bool do_alpha_checker = !DRW_state_draw_background(); DRW_draw_background(do_alpha_checker); @@ -1565,20 +1575,6 @@ void DRW_draw_view(const bContext *C) DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C); } -static bool is_object_visible_in_viewport(View3D *v3d, Object *ob) -{ - if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { - return false; - } - - if ((v3d->flag & V3D_LOCAL_COLLECTIONS) && - ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) { - return false; - } - - return true; -} - /** * Used for both regular and off-screen drawing. * Need to reset DST before calling this function @@ -1654,7 +1650,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; } - if (!is_object_visible_in_viewport(v3d, ob)) { + if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; } DST.dupli_parent = data_.dupli_parent; @@ -1685,7 +1681,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DRW_hair_update(); - drw_engines_draw_background(); + const bool background_drawn = drw_engines_draw_background(); GPU_framebuffer_bind(DST.default_framebuffer); @@ -1696,6 +1692,10 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, drw_engines_draw_scene(); + if (!background_drawn) { + drw_draw_background_alpha_under(); + } + /* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */ GPU_flush(); @@ -2350,7 +2350,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, v3d->object_type_exclude_select); bool filter_exclude = false; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { - if (!is_object_visible_in_viewport(v3d, ob)) { + if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; } if ((ob->base_flag & BASE_SELECTABLE) && @@ -2500,7 +2500,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; } - if (!is_object_visible_in_viewport(v3d, ob)) { + if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; } DST.dupli_parent = data_.dupli_parent; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index dcf526679bf..330f72eda18 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1846,11 +1846,6 @@ void DRW_pass_foreach_shgroup(DRWPass *pass, } } -typedef struct ZSortData { - const float *axis; - const float *origin; -} ZSortData; - static int pass_shgroup_dist_sort(const void *a, const void *b) { const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a; diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 3de9ce74dbc..fa7c44c1b1f 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -29,6 +29,7 @@ #include "BKE_global.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "intern/gpu_shader_private.h" #include "intern/gpu_primitive_private.h" diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 7aa2e007f79..58643eb12a8 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -41,11 +41,9 @@ #include "BKE_object.h" #include "BKE_paint.h" -#include "DRW_render.h" - #include "view3d_intern.h" -#include "draw_view.h" +#include "draw_manager.h" /* ******************** region info ***************** */ @@ -60,18 +58,17 @@ void DRW_draw_region_info(void) } /* ************************* Background ************************** */ +void DRW_clear_background() +{ + GPU_clear_color(0.0, 0.0, 0.0, 0.0); + GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT); +} void DRW_draw_background(bool do_alpha_checker) { - /* Just to make sure */ - glDepthMask(GL_TRUE); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0xFF); - + drw_state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL); if (do_alpha_checker) { /* Transparent render, do alpha checker. */ - GPU_depth_test(false); - GPU_matrix_push(); GPU_matrix_identity_set(); GPU_matrix_identity_projection_set(); @@ -79,18 +76,11 @@ void DRW_draw_background(bool do_alpha_checker) imm_draw_box_checker_2d(-1.0f, -1.0f, 1.0f, 1.0f); GPU_matrix_pop(); - - GPU_clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT); - - GPU_depth_test(true); } - else if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + else { float m[4][4]; unit_m4(m); - /* Gradient background Color */ - GPU_depth_test(false); - GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); uint color = GPU_vertformat_attr_add( @@ -103,8 +93,8 @@ void DRW_draw_background(bool do_alpha_checker) immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR_DITHER); - UI_GetThemeColor3ubv(TH_BACK_GRAD, col_lo); UI_GetThemeColor3ubv(TH_BACK, col_hi); + UI_GetThemeColor3ubv(UI_GetThemeValue(TH_SHOW_BACK_GRAD) ? TH_BACK_GRAD : TH_BACK, col_lo); immBegin(GPU_PRIM_TRI_FAN, 4); immAttr3ubv(color, col_lo); @@ -119,16 +109,6 @@ void DRW_draw_background(bool do_alpha_checker) immUnbindProgram(); GPU_matrix_pop(); - - GPU_clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT); - - GPU_depth_test(true); - } - else { - /* Solid background Color */ - UI_ThemeClearColorAlpha(TH_BACK, 1.0f); - - GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT); } } diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h index 715c3c0d40c..7be186f1c72 100644 --- a/source/blender/draw/intern/draw_view.h +++ b/source/blender/draw/intern/draw_view.h @@ -24,6 +24,7 @@ #define __DRAW_VIEW_H__ void DRW_draw_region_info(void); +void DRW_clear_background(void); void DRW_draw_background(bool do_alpha_checker); void DRW_draw_cursor(void); void DRW_draw_gizmo_3d(void); diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 05a915185df..21e1dff7128 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -122,8 +122,9 @@ typedef struct OBJECT_PassList { struct DRWPass *bone_axes[2]; struct DRWPass *particle; struct DRWPass *lightprobes; - struct DRWPass *camera_images_back; - struct DRWPass *camera_images_front; + struct DRWPass *camera_images_back_alpha_under; + struct DRWPass *camera_images_back_alpha_over; + struct DRWPass *camera_images_front_alpha_over; } OBJECT_PassList; typedef struct OBJECT_FramebufferList { @@ -991,13 +992,19 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data, } } -/* Draw Camera Background Images */ +/* -------------------------------------------------------------------- */ +/** \name Camera Background Images + * \{ */ typedef struct CameraEngineData { DrawData dd; ListBase bg_data; } CameraEngineData; + typedef struct CameraEngineBGData { + CameraBGImage *camera_image; + GPUTexture *texture; float transform_mat[4][4]; + bool premultiplied; } CameraEngineBGData; static void camera_engine_data_free(DrawData *dd) @@ -1032,6 +1039,26 @@ static void camera_background_images_stereo_setup(Scene *scene, iuser->flag &= ~IMA_SHOW_STEREO; } } +static void camera_background_images_add_shgroup(DRWPass *pass, + CameraEngineBGData *bg_data, + GPUShader *shader, + GPUBatch *batch) +{ + CameraBGImage *camera_image = bg_data->camera_image; + DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + + DRW_shgroup_uniform_float_copy( + grp, "depth", camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND ? 0.000001f : 0.999999f); + DRW_shgroup_uniform_float_copy(grp, "alpha", camera_image->alpha); + DRW_shgroup_uniform_texture(grp, "image", bg_data->texture); + DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", bg_data->premultiplied); + DRW_shgroup_uniform_float_copy( + grp, "flipX", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0); + DRW_shgroup_uniform_float_copy( + grp, "flipY", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0); + DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat); + DRW_shgroup_call(grp, batch, NULL); +} static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data, OBJECT_PassList *psl, @@ -1255,25 +1282,46 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data, scale_m4, uv2img_space); - DRWPass *pass = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? psl->camera_images_front : - psl->camera_images_back; - GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm : - sh_data->object_camera_image; - DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + /* Keep the references so we can reverse the loop */ + bg_data->camera_image = bgpic; + bg_data->texture = tex; + bg_data->premultiplied = premultiplied; + } - DRW_shgroup_uniform_float_copy( - grp, "depth", (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? 0.000001 : 0.999999); - DRW_shgroup_uniform_float_copy(grp, "alpha", bgpic->alpha); - DRW_shgroup_uniform_texture(grp, "image", tex); - DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", premultiplied); + /* Mark the rest bg_data's to be reused in the next drawing call */ + LinkData *last_node = list_node ? list_node->prev : camera_engine_data->bg_data.last; + while (list_node != NULL) { + CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data; + bg_data->texture = NULL; + bg_data->camera_image = NULL; + list_node = list_node->next; + } - DRW_shgroup_uniform_float_copy( - grp, "flipX", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0); - DRW_shgroup_uniform_float_copy( - grp, "flipY", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0); - DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat); + GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm : + sh_data->object_camera_image; + /* loop 1: camera images alpha under */ + for (list_node = last_node; list_node; list_node = list_node->prev) { + CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data; + CameraBGImage *camera_image = bg_data->camera_image; + if ((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) == 0) { + camera_background_images_add_shgroup( + psl->camera_images_back_alpha_under, bg_data, shader, batch); + } + } - DRW_shgroup_call(grp, batch, NULL); + /* loop 2: camera images alpha over */ + for (list_node = camera_engine_data->bg_data.first; list_node; list_node = list_node->next) { + CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data; + CameraBGImage *camera_image = bg_data->camera_image; + if (camera_image == NULL) { + break; + } + camera_background_images_add_shgroup((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) ? + psl->camera_images_front_alpha_over : + psl->camera_images_back_alpha_over, + bg_data, + shader, + batch); } } } @@ -1286,6 +1334,7 @@ static void camera_background_images_free_textures(void) } BLI_freelistN(&e_data.movie_clips); } +/* \} */ static void OBJECT_cache_init(void *vedata) { @@ -1427,9 +1476,15 @@ static void OBJECT_cache_init(void *vedata) /* Camera background images */ { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA; - psl->camera_images_back = DRW_pass_create("Camera Images Back", state); - psl->camera_images_front = DRW_pass_create("Camera Images Front", state); + psl->camera_images_back_alpha_over = DRW_pass_create( + "Camera Images Back Over", + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL); + psl->camera_images_back_alpha_under = DRW_pass_create( + "Camera Images Back Under", + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL); + psl->camera_images_front_alpha_over = DRW_pass_create( + "Camera Images Front Over", + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL); } for (int i = 0; i < 2; i++) { @@ -3486,6 +3541,10 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) if (hide_object_extra) { break; } + if ((ob->base_flag & BASE_FROM_DUPLI) && (ob->transflag & OB_DUPLICOLLECTION) && + ob->instance_collection) { + break; + } DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg); break; case OB_SPEAKER: @@ -3666,7 +3725,8 @@ static void OBJECT_draw_scene(void *vedata) float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - DRW_draw_pass(psl->camera_images_back); + DRW_draw_pass(psl->camera_images_back_alpha_under); + DRW_draw_pass(psl->camera_images_back_alpha_over); /* Don't draw Transparent passes in MSAA buffer. */ // DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */ @@ -3774,7 +3834,7 @@ static void OBJECT_draw_scene(void *vedata) batch_camera_path_free(&stl->g_data->sgl_ghost.camera_path); - DRW_draw_pass(psl->camera_images_front); + DRW_draw_pass(psl->camera_images_front_alpha_over); camera_background_images_free_textures(); DRW_draw_pass(psl->ob_center); diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index 1b196cd8bb7..9749619cffe 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -156,7 +156,8 @@ static void SCULPT_cache_populate(void *vedata, Object *ob) const DRWContextState *draw_ctx = DRW_context_state_get(); if ((ob == draw_ctx->obact) && - (BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) || !ob->sculpt->modifiers_active)) { + (BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) || + ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) { PBVH *pbvh = ob->sculpt->pbvh; if (pbvh && pbvh_has_mask(pbvh)) { DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false); diff --git a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl index 5d8ad3c79ea..7804ebdb8c9 100644 --- a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl +++ b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl @@ -19,5 +19,7 @@ void main() #endif color.a *= alpha; + color.rgb *= color.a; + fragColor = color; } diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index d80b96f0d74..8951677b32f 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -3411,7 +3411,7 @@ static void acf_nlatrack_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, flo } /* set color for nla track */ - UI_GetThemeColorShade3fv(TH_HEADER, ((nonSolo == false) ? 20 : -20), r_color); + UI_GetThemeColorShade3fv(TH_NLA_TRACK, ((nonSolo == false) ? 20 : -20), r_color); } /* name for nla track entries */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 48493c9e961..f73c8a5b71a 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1818,7 +1818,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { /* Layer visibility - we check both object and base, * since these may not be in sync yet. */ - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { continue; } @@ -3017,7 +3017,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_m */ if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { /* layer visibility - we check both object and base, since these may not be in sync yet */ - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return false; } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 2a35acdefcb..36583ecf060 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -1148,33 +1148,48 @@ static void deselect_markers(ListBase *markers) } /* select/deselect TimeMarker at current frame */ -static void select_timeline_marker_frame(ListBase *markers, int frame, bool extend) +static int select_timeline_marker_frame(ListBase *markers, + int frame, + bool extend, + bool wait_to_deselect_others) { - TimeMarker *marker, *marker_first = NULL; + TimeMarker *marker, *marker_selected = NULL; + int ret_val = OPERATOR_FINISHED; + + if (extend) { + wait_to_deselect_others = false; + } /* support for selection cycling */ for (marker = markers->first; marker; marker = marker->next) { if (marker->frame == frame) { if (marker->flag & SELECT) { - marker_first = marker->next; + marker_selected = marker->next; break; } } } - /* if extend is not set, then deselect markers */ - if (extend == false) { - deselect_markers(markers); + if (wait_to_deselect_others && marker_selected) { + ret_val = OPERATOR_RUNNING_MODAL; } + /* if extend is not set, then deselect markers */ + else { + if (extend == false) { + deselect_markers(markers); + } - LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { - /* this way a not-extend select will always give 1 selected marker */ - if (marker->frame == frame) { - marker->flag ^= SELECT; - break; + LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_selected) { + /* this way a not-extend select will always give 1 selected marker */ + if (marker->frame == frame) { + marker->flag ^= SELECT; + break; + } } + LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_selected); } - LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_first); + + return ret_val; } static void select_marker_camera_switch( @@ -1221,17 +1236,17 @@ static void select_marker_camera_switch( #endif } -static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera) +static int ed_marker_select( + bContext *C, const int mval[2], bool extend, bool camera, bool wait_to_deselect_others) { ListBase *markers = ED_context_get_markers(C); - ARegion *ar = CTX_wm_region(C); View2D *v2d = UI_view2d_fromcontext(C); + int ret_val = OPERATOR_FINISHED; - float mouse_region_x = event->x - ar->winrct.xmin; - if (region_position_is_over_marker(v2d, markers, mouse_region_x)) { - float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mouse_region_x); + if (region_position_is_over_marker(v2d, markers, mval[0])) { + float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mval[0]); int cfra = ED_markers_find_nearest_marker_time(markers, frame_at_mouse_position); - select_timeline_marker_frame(markers, cfra, extend); + ret_val = select_timeline_marker_frame(markers, cfra, extend, wait_to_deselect_others); select_marker_camera_switch(C, camera, extend, markers, cfra); } @@ -1243,17 +1258,22 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_val | OPERATOR_PASS_THROUGH; } -static int ed_marker_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int ed_marker_select_exec(bContext *C, wmOperator *op) { const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); bool camera = false; #ifdef DURIAN_CAMERA_SWITCH camera = RNA_boolean_get(op->ptr, "camera"); #endif - return ed_marker_select(C, event, extend, camera); + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + + return ed_marker_select(C, mval, extend, camera, wait_to_deselect_others); } static void MARKER_OT_select(wmOperatorType *ot) @@ -1266,12 +1286,15 @@ static void MARKER_OT_select(wmOperatorType *ot) ot->idname = "MARKER_OT_select"; /* api callbacks */ - ot->invoke = ed_marker_select_invoke; ot->poll = ed_markers_poll_markers_exist; + ot->exec = ed_marker_select_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + WM_operator_properties_generic_select(ot); prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); #ifdef DURIAN_CAMERA_SWITCH diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 61c8da08954..64f7fe034dc 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -111,7 +111,7 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve"); fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; /* store path - make copy, and store that */ if (rna_path) { diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index c174ce83bea..479e7192b0e 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -545,8 +545,7 @@ int actkeyblock_get_valid_hold(ActKeyColumn *ac) return 0; } - const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | - ACTKEYBLOCK_FLAG_ANY_HOLD); + const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD); return (ac->block.flag & ~ac->block.conflict) & hold_mask; } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 0f8b8742659..8203a9131fa 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -202,7 +202,7 @@ FCurve *verify_fcurve(Main *bmain, fcu = MEM_callocN(sizeof(FCurve), "FCurve"); fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; if (BLI_listbase_is_empty(&act->curves)) { fcu->flag |= FCURVE_ACTIVE; /* first one added active */ } diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 616daf94e57..7ed41b5b4d0 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -368,30 +368,14 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo switch (pso->mode) { case POSESLIDE_PUSH: /* make the current pose more pronounced */ { - /* perform a weighted average here, favoring the middle pose - * - numerator should be larger than denominator to 'expand' the result - * - perform this weighting a number of times given by the percentage... - */ - /* TODO: maybe a sensitivity ctrl on top of this is needed */ - int iters = (int)ceil(10.0f * pso->percentage); - - while (iters-- > 0) { - (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f)) / 5.0f; - } + /* Slide the pose away from the breakdown pose in the timeline */ + (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage; break; } case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */ { - /* perform a weighted average here, favoring the middle pose - * - numerator should be smaller than denominator to 'relax' the result - * - perform this weighting a number of times given by the percentage... - */ - /* TODO: maybe a sensitivity ctrl on top of this is needed */ - int iters = (int)ceil(10.0f * pso->percentage); - - while (iters-- > 0) { - (*val) = (((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f)) / 6.0f; - } + /* Slide the pose towards the breakdown pose in the timeline */ + (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage; break; } case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 3f6db956643..8d2d7d790d2 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -32,6 +32,7 @@ #include "DNA_scene_types.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_idprop.h" #include "BKE_layer.h" @@ -223,6 +224,11 @@ void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + + AnimData *adt = BKE_animdata_from_id(&ob->id); + if (adt && adt->action) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } } /* reset changes made to current pose */ diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 603b0967ace..e11807d818f 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1876,6 +1876,7 @@ void ED_curve_editfont_make(Object *obedit) memcpy(ef->textbufinfo, cu->strinfo, ef->len * sizeof(CharInfo)); + ef->pos = cu->pos; if (ef->pos > ef->len) { ef->pos = ef->len; } @@ -1883,7 +1884,6 @@ void ED_curve_editfont_make(Object *obedit) cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0]; /* Other vars */ - ef->pos = cu->pos; ef->selstart = cu->selstart; ef->selend = cu->selend; diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index af49587f9ad..3d56cb0fcb1 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -54,6 +54,9 @@ #include "ED_object.h" #include "ED_gpencil.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "gpencil_intern.h" /* Free all of a gp-colors */ @@ -111,6 +114,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op) ob = BKE_object_add_for_data( bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false); zero_v3(ob->loc); + DEG_relations_tag_update(bmain); /* added object */ /* convert grease pencil palettes (version >= 2.78) to materials and weights */ for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) { diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 7c3aac6c688..c3e61f5f2b2 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -246,7 +246,8 @@ ScrArea *ED_screen_temp_space_open(struct bContext *C, int sizex, int sizey, eSpace_Type space_type, - int display_type); + int display_type, + bool dialog); void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg); void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg); void ED_screens_navigation_bar_tools_menu_create(struct bContext *C, diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 76ab4a53eb8..89579b88d24 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -283,6 +283,7 @@ typedef enum ThemeColorID { TH_NLA_TWEAK, /* 'tweaking' track in NLA */ TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */ + TH_NLA_TRACK, TH_NLA_TRANSITION, TH_NLA_TRANSITION_SEL, TH_NLA_META, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index bc8d25e8d9e..d33023c69a1 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -50,6 +50,7 @@ set(SRC interface_eyedropper_datablock.c interface_eyedropper_depth.c interface_eyedropper_driver.c + interface_eyedropper_gpencil_color.c interface_handlers.c interface_icons.c interface_icons_event.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index f05100e9065..54fd91e5361 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -786,6 +786,8 @@ static bool ui_but_update_from_old_block(const bContext *C, oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy); oldbut->drawflag = (oldbut->drawflag & ~drawflag_copy) | (but->drawflag & drawflag_copy); + SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons); + /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position * when scrolling without moving mouse (see [#28432]) */ if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) { @@ -3389,7 +3391,7 @@ static void ui_but_build_drawstr_float(uiBut *but, double value) if (value == (double)FLT_MAX) { STR_CONCAT(but->drawstr, slen, "inf"); } - else if (value == (double)-FLT_MIN) { + else if (value == (double)-FLT_MAX) { STR_CONCAT(but->drawstr, slen, "-inf"); } else if (subtype == PROP_PERCENTAGE) { diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 3c26c37b610..988dea270f5 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -69,6 +69,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver"); + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_gpencil_color"); return keymap; } diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c new file mode 100644 index 00000000000..02d4596e93c --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c @@ -0,0 +1,324 @@ +/* + * 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) 2009 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edinterface + * + * Eyedropper (RGB Color) + * + * Defines: + * - #UI_OT_eyedropper_gpencil_color + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_string.h" + +#include "BLT_translation.h" + +#include "DNA_gpencil_types.h" +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_report.h" + +#include "UI_interface.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_undo.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +typedef struct EyedropperGPencil { + struct ColorManagedDisplay *display; + /** color under cursor RGB */ + float color[3]; +} EyedropperGPencil; + +/* Helper: Draw status message while the user is running the operator */ +static void eyedropper_gpencil_status_indicators(bContext *C) +{ + char msg_str[UI_MAX_DRAW_STR]; + BLI_strncpy( + msg_str, TIP_("LMB: Stroke - Shift: Fill - Shift+Ctrl: Stroke + Fill"), UI_MAX_DRAW_STR); + + ED_workspace_status_text(C, msg_str); +} + +/* Initialize. */ +static bool eyedropper_gpencil_init(bContext *C, wmOperator *op) +{ + EyedropperGPencil *eye = MEM_callocN(sizeof(EyedropperGPencil), __func__); + + op->customdata = eye; + Scene *scene = CTX_data_scene(C); + + const char *display_device; + display_device = scene->display_settings.display_device; + eye->display = IMB_colormanagement_display_get_named(display_device); + + return true; +} + +/* Exit and free memory. */ +static void eyedropper_gpencil_exit(bContext *C, wmOperator *op) +{ + /* Clear status message area. */ + ED_workspace_status_text(C, NULL); + + MEM_SAFE_FREE(op->customdata); +} + +/* Set the material. */ +static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, EyedropperGPencil *eye) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + Material *ma = NULL; + + const bool only_stroke = ((!event->ctrl) && (!event->shift)); + const bool only_fill = ((!event->ctrl) && (event->shift)); + const bool both = ((event->ctrl) && (event->shift)); + + float col_conv[4]; + bool found = false; + + /* Convert from linear rgb space to display space because grease pencil colors are in display + * space, and this conversion is needed to undo the conversion to linear performed by + * eyedropper_color_sample_fl. */ + if (eye->display) { + copy_v3_v3(col_conv, eye->color); + IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); + } + else { + copy_v3_v3(col_conv, eye->color); + } + + /* Look for a similar material in grease pencil slots. */ + short *totcol = give_totcolp(ob); + for (short i = 0; i < *totcol; i++) { + ma = give_current_material(ob, i + 1); + if (ma == NULL) { + continue; + } + + MaterialGPencilStyle *gp_style = ma->gp_style; + if (gp_style != NULL) { + /* Check stroke color. */ + bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) && + (gp_style->flag & GP_STYLE_STROKE_SHOW); + /* Check fill color. */ + bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) && + (gp_style->flag & GP_STYLE_FILL_SHOW); + + if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) { + found = true; + } + else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0)) { + found = true; + } + else if ((both) && (found_stroke) && (found_fill)) { + found = true; + } + + /* Found existing material. */ + if (found) { + ob->actcol = i + 1; + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL); + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); + return; + } + } + } + + /* If material was not found add a new material with stroke and/or fill color + * depending of the secondary key (LMB: Stroke, Shift: Fill, Shift+Ctrl: Stroke/Fill) + */ + int idx; + Material *ma_new = BKE_gpencil_object_material_new(bmain, ob, "Material", &idx); + WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, &ob->id); + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL); + DEG_relations_tag_update(bmain); + + BLI_assert(ma_new != NULL); + + MaterialGPencilStyle *gp_style_new = ma_new->gp_style; + BLI_assert(gp_style_new != NULL); + + /* Only create Stroke (default option). */ + if (only_stroke) { + /* Stroke color. */ + gp_style_new->flag |= GP_STYLE_STROKE_SHOW; + gp_style_new->flag &= ~GP_STYLE_FILL_SHOW; + copy_v3_v3(gp_style_new->stroke_rgba, col_conv); + zero_v4(gp_style_new->fill_rgba); + } + /* Fill Only. */ + else if (only_fill) { + /* Fill color. */ + gp_style_new->flag &= ~GP_STYLE_STROKE_SHOW; + gp_style_new->flag |= GP_STYLE_FILL_SHOW; + zero_v4(gp_style_new->stroke_rgba); + copy_v3_v3(gp_style_new->fill_rgba, col_conv); + } + /* Stroke and Fill. */ + else if (both) { + gp_style_new->flag |= GP_STYLE_STROKE_SHOW | GP_STYLE_FILL_SHOW; + copy_v3_v3(gp_style_new->stroke_rgba, col_conv); + copy_v3_v3(gp_style_new->fill_rgba, col_conv); + } + /* Push undo for new created material. */ + ED_undo_push(C, "Add Grease Pencil Material"); +} + +/* Sample the color below cursor. */ +static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, int mx, int my) +{ + eyedropper_color_sample_fl(C, mx, my, eye->color); +} + +/* Cancel operator. */ +static void eyedropper_gpencil_cancel(bContext *C, wmOperator *op) +{ + eyedropper_gpencil_exit(C, op); +} + +/* Main modal status check. */ +static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperGPencil *eye = (EyedropperGPencil *)op->customdata; + /* Handle modal keymap */ + switch (event->type) { + case EVT_MODAL_MAP: { + switch (event->val) { + case EYE_MODAL_SAMPLE_BEGIN: { + return OPERATOR_RUNNING_MODAL; + } + case EYE_MODAL_CANCEL: { + eyedropper_gpencil_cancel(C, op); + return OPERATOR_CANCELLED; + } + case EYE_MODAL_SAMPLE_CONFIRM: { + eyedropper_gpencil_color_sample(C, eye, event->x, event->y); + + /* Create material. */ + eyedropper_gpencil_color_set(C, event, eye); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + eyedropper_gpencil_exit(C, op); + return OPERATOR_FINISHED; + break; + } + default: { + break; + } + } + break; + } + case MOUSEMOVE: + case INBETWEEN_MOUSEMOVE: { + eyedropper_gpencil_color_sample(C, eye, event->x, event->y); + break; + } + default: { + break; + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int eyedropper_gpencil_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* Init. */ + if (eyedropper_gpencil_init(C, op)) { + /* Add modal temp handler. */ + WM_event_add_modal_handler(C, op); + /* Status message. */ + eyedropper_gpencil_status_indicators(C); + + return OPERATOR_RUNNING_MODAL; + } + else { + return OPERATOR_PASS_THROUGH; + } +} + +/* Repeat operator */ +static int eyedropper_gpencil_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_gpencil_init(C, op)) { + + /* cleanup */ + eyedropper_gpencil_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_PASS_THROUGH; + } +} + +static bool eyedropper_gpencil_poll(bContext *C) +{ + /* Only valid if the current active object is grease pencil. */ + Object *obact = CTX_data_active_object(C); + if ((obact == NULL) || (obact->type != OB_GPENCIL)) { + return false; + } + + /* Test we have a window below. */ + return (CTX_wm_window(C) != NULL); +} + +void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Eyedropper"; + ot->idname = "UI_OT_eyedropper_gpencil_color"; + ot->description = "Sample a color from the Blender Window and create Grease Pencil material"; + + /* api callbacks */ + ot->invoke = eyedropper_gpencil_invoke; + ot->modal = eyedropper_gpencil_modal; + ot->cancel = eyedropper_gpencil_cancel; + ot->exec = eyedropper_gpencil_exec; + ot->poll = eyedropper_gpencil_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; +} diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e0442ebcca2..83820c919c8 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -108,6 +108,7 @@ static int ui_do_but_EXIT(bContext *C, const wmEvent *event); static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b); static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str); +static void button_tooltip_timer_reset(bContext *C, uiBut *but); #ifdef USE_KEYNAV_LIMIT static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event); @@ -3967,8 +3968,11 @@ static bool ui_do_but_extra_operator_icon(bContext *C, uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event); if (op_icon) { + ED_region_tag_redraw(data->region); + button_tooltip_timer_reset(C, but); + ui_but_extra_operator_icon_apply(C, but, op_icon); - button_activate_exit(C, but, data, false, false); + /* Note: 'but', 'data' may now be freed, don't access. */ return true; } @@ -7493,6 +7497,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData"); data->wm = CTX_wm_manager(C); data->window = CTX_wm_window(C); + BLI_assert(ar != NULL); data->region = ar; #ifdef USE_CONT_MOUSE_CORRECT @@ -8005,6 +8010,7 @@ void ui_but_execute_begin(struct bContext *UNUSED(C), *active_back = but->active; data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData_Fake"); but->active = data; + BLI_assert(ar != NULL); data->region = ar; } @@ -9816,9 +9822,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle if (but && (U.pie_menu_confirm > 0) && (dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm))) { - if (but) { - return ui_but_pie_menu_apply(C, menu, but, true); - } + return ui_but_pie_menu_apply(C, menu, but, true); } retval = ui_but_pie_menu_apply(C, menu, but, true); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index b844e237366..1495fb7e716 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1583,7 +1583,6 @@ static struct { IconTextureDrawCall normal; IconTextureDrawCall border; bool enabled; - float mat[4][4]; } g_icon_draw_cache = {{{{{0}}}}}; void UI_icon_draw_cache_begin(void) diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c index e1ce77b8b61..b7fd953ed63 100644 --- a/source/blender/editors/interface/interface_icons_event.c +++ b/source/blender/editors/interface/interface_icons_event.c @@ -171,12 +171,13 @@ void icon_draw_rect_input(float x, const bool simple_text = false; - if ((event_type >= AKEY) || (ZKEY <= event_type)) { + if ((event_type >= AKEY) && (event_type <= ZKEY)) { char str[2] = {'A' + (event_type - AKEY), '\0'}; icon_draw_rect_input_default_text(&rect, color, margin, str); } - if ((event_type >= F1KEY) || (F12KEY <= event_type)) { - char str[3] = {'F', '1' + (event_type - F1KEY), '\0'}; + else if ((event_type >= F1KEY) && (event_type <= F12KEY)) { + char str[4]; + SNPRINTF(str, "F%d", 1 + (event_type - F1KEY)); icon_draw_rect_input_default_text(&rect, color, margin, str); } else if (event_type == LEFTSHIFTKEY) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 4351b75eb86..81979b1fc8f 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -971,6 +971,9 @@ void UI_OT_eyedropper_depth(struct wmOperatorType *ot); /* interface_eyedropper_driver.c */ void UI_OT_eyedropper_driver(struct wmOperatorType *ot); +/* interface_eyedropper_gpencil_color.c */ +void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot); + /* interface_util.c */ /** diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 4e56a02997b..7ce4242c697 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1751,6 +1751,7 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_eyedropper_id); WM_operatortype_append(UI_OT_eyedropper_depth); WM_operatortype_append(UI_OT_eyedropper_driver); + WM_operatortype_append(UI_OT_eyedropper_gpencil_color); } /** diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index 028d99ac052..cd0421dde09 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -334,7 +334,8 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep } if (block) { - UI_block_active_only_flagged_buttons(C, CTX_wm_region(C), block); + uiPopupBlockHandle *handle = block->handle; + UI_block_active_only_flagged_buttons(C, handle->region, block); } return OPERATOR_INTERFACE; } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 9f1b11d1354..b3e039292e1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -4638,9 +4638,6 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct case UI_BTYPE_SEARCH_MENU: wt = widget_type(UI_WTYPE_NAME); - if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) { - wt->wcol_theme = &btheme->tui.wcol_menu_back; - } break; case UI_BTYPE_TAB: @@ -4914,9 +4911,10 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol, { /* tsk, this isn't nice. */ const float unit_half = unit_size / 2; - const float cent_x = mval_origin ? - CLAMPIS(mval_origin[0], rect->xmin + unit_size, rect->xmax - unit_size) : - BLI_rcti_cent_x(rect); + const float cent_x = mval_origin ? CLAMPIS(mval_origin[0], + rect->xmin + unit_size, + rect->xmax - unit_size) : + BLI_rcti_cent_x(rect); rect->ymax -= unit_half; rect->ymin += unit_half; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 8a570933a33..99594cf0803 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -371,7 +371,6 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_OBCENTER_DIA: cp = &ts->obcenter_dia; break; - break; case TH_EDGE: cp = ts->edge; break; @@ -841,6 +840,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = ts->nla_tweakdupli; break; + case TH_NLA_TRACK: + cp = ts->nla_track; + break; case TH_NLA_TRANSITION: cp = ts->nla_transition; break; diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c index 7155348fed5..993898bddd5 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c @@ -522,7 +522,6 @@ typedef struct GizmoGroupData_SpinRedo { PropertyRNA *prop_axis_no; PropertyRNA *prop_angle; - float rotate_axis[3]; #ifdef USE_ANGLE_Z_ORIENT /* Apply 'orient_mat' for the final value. */ float orient_axis_relative[3]; diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 3be94cf99c1..3c3e91e8afe 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -386,7 +386,6 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) bool ok = true; if (is_interactive == false) { if (exec_data.base_index >= bases_len) { - return OPERATOR_CANCELLED; ok = false; } else { diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index d066e9ecddc..8d98a3bf231 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -101,16 +101,21 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) BMIter face_iter; /* Delete all unmasked faces */ + const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); + BLI_assert(cd_vert_mask_offset != -1); BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); float mask_threshold = RNA_float_get(op->ptr, "mask_threshold"); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - bool delete_face = false; + bool keep_face = true; BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) { - float mask = BM_elem_float_data_get(&bm->vdata, v, CD_PAINT_MASK); - delete_face = mask < mask_threshold; + const float mask = BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); + if (mask < mask_threshold) { + keep_face = false; + break; + } } - BM_elem_flag_set(f, BM_ELEM_TAG, delete_face); + BM_elem_flag_set(f, BM_ELEM_TAG, !keep_face); } BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES); @@ -173,7 +178,6 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) } BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BKE_editmesh_free_derivedmesh(em); BKE_mesh_free(new_mesh); new_mesh = BKE_mesh_from_bmesh_nomain(bm, @@ -182,7 +186,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) }), mesh); - BM_mesh_free(bm); + BKE_editmesh_free(em); + MEM_freeN(em); if (new_mesh->totvert == 0) { BKE_mesh_free(new_mesh); @@ -196,8 +201,6 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) Object *new_ob = ED_object_add_type(C, OB_MESH, NULL, ob->loc, ob->rot, false, local_view_bits); BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob, &CD_MASK_EVERYTHING, true); - BKE_mesh_free(new_mesh); - if (RNA_boolean_get(op->ptr, "apply_shrinkwrap")) { BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob); } @@ -212,6 +215,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) } } + BKE_mesh_calc_normals(new_ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob); BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL); DEG_relations_tag_update(bmain); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 4636d1ee71e..cf3170b5446 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2044,11 +2044,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) } if (tot_failed_all != 0) { - BKE_reportf(op->reports, - RPT_WARNING, - tot_failed_all == 1 ? "Unable to rotate %d edge" : - "Unable to rotate %d edges", - tot_failed_all); + BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all); } return OPERATOR_FINISHED; @@ -3165,11 +3161,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); - BKE_reportf(op->reports, - RPT_INFO, - count_multi == 1 ? "Removed %d vertex" : - "Removed %d vertices", - count_multi); + BKE_reportf(op->reports, RPT_INFO, "Removed %d vertice(s)", count_multi); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 569994bead1..a0d424e083c 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -880,14 +880,14 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot) void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose) { - if (calc_edges_loose && mesh->totedge) { - BKE_mesh_calc_edges_loose(mesh); - } - if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) { BKE_mesh_calc_edges(mesh, calc_edges, true); } + if (calc_edges_loose && mesh->totedge) { + BKE_mesh_calc_edges_loose(mesh); + } + /* Default state is not to have tessface's so make sure this is the case. */ BKE_mesh_tessface_clear(mesh); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index d6816ddbe73..bdb23c5ce6f 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1030,7 +1030,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv return OPERATOR_CANCELLED; } /* handled below */ - id_us_min((ID *)ima); + id_us_min(&ima->id); Object *ob = NULL; Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval); @@ -1581,11 +1581,7 @@ static int object_delete_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - BKE_reportf(op->reports, - RPT_INFO, - changed_count == 1 ? "Deleted %u object" : - "Deleted %u objects", - changed_count); + BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count); if (changed_count == 0) { return OPERATOR_CANCELLED; @@ -2149,6 +2145,7 @@ static int convert_exec(bContext *C, wmOperator *op) const short target = RNA_enum_get(op->ptr, "target"); bool keep_original = RNA_boolean_get(op->ptr, "keep_original"); int a, mballConverted = 0; + bool gpencilConverted = false; /* don't forget multiple users! */ @@ -2389,20 +2386,20 @@ static int convert_exec(bContext *C, wmOperator *op) } else if (target == OB_GPENCIL) { if (ob->type != OB_CURVE) { + ob->flag &= ~OB_DONE; BKE_report( op->reports, RPT_ERROR, "Convert Surfaces to Grease Pencil is not supported."); } else { - /* Create a new grease pencil object only if it was not created before. - * All curves selected are converted as strokes of the same grease pencil object. + /* Create a new grease pencil object and copy transformations. * Nurbs Surface are not supported. */ - if (gpencil_ob == NULL) { - const float *cur = scene->cursor.location; - ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; - gpencil_ob = ED_gpencil_add_object(C, scene, cur, local_view_bits); - } + ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; + gpencil_ob = ED_gpencil_add_object(C, scene, ob->loc, local_view_bits); + copy_v3_v3(gpencil_ob->rot, ob->rot); + copy_v3_v3(gpencil_ob->scale, ob->scale); BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true); + gpencilConverted = true; } } } @@ -2502,6 +2499,17 @@ static int convert_exec(bContext *C, wmOperator *op) } FOREACH_SCENE_OBJECT_END; } + /* Remove curves converted to Grease Pencil object. */ + if (gpencilConverted) { + FOREACH_SCENE_OBJECT_BEGIN (scene, ob_curve) { + if (ob_curve->type == OB_CURVE) { + if (ob_curve->flag & OB_DONE) { + ED_object_base_free_and_unlink(bmain, scene, ob_curve); + } + } + } + FOREACH_SCENE_OBJECT_END; + } } // XXX ED_object_editmode_enter(C, 0); @@ -2580,7 +2588,7 @@ static Base *object_add_duplicate_internal( DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); base = BKE_view_layer_base_find(view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE)) { + if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { BKE_collection_object_add_from(bmain, scene, ob, obn); } else { diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index d9baec7c3ca..9e9cfe1beed 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -879,7 +879,7 @@ static int bake(Render *re, else { ob_cage_eval = DEG_get_evaluated_object(depsgraph, ob_cage); ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); } } } @@ -976,7 +976,7 @@ static int bake(Render *re, highpoly[i].ob = ob_iter; highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; - highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); + highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false); /* lowpoly to highpoly transformation matrix */ @@ -992,10 +992,10 @@ static int bake(Render *re, if (ob_cage != NULL) { ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); } ob_low_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_low_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + ob_low_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); /* populate the pixel arrays with the corresponding face data for each high poly object */ if (!RE_bake_pixels_populate_from_objects(me_low, diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 4759a3cb0db..70d024c7902 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -218,7 +218,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op) /* Hide selected or unselected objects. */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (!(base->flag & BASE_VISIBLE)) { + if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) { continue; } @@ -292,7 +292,7 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); if (v3d->flag & V3D_LOCAL_COLLECTIONS) { - if ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) { + if (lc->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) { return OPERATOR_CANCELLED; } if (toggle) { @@ -300,11 +300,11 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op) BKE_layer_collection_local_sync(view_layer, v3d); } else { - BKE_layer_collection_local_isolate(view_layer, v3d, lc, extend); + BKE_layer_collection_isolate_local(view_layer, v3d, lc, extend); } } else { - BKE_layer_collection_isolate(scene, view_layer, lc, extend); + BKE_layer_collection_isolate_global(scene, view_layer, lc, extend); } WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -1547,7 +1547,7 @@ static int move_to_collection_exec(bContext *C, wmOperator *op) } int collection_index = RNA_property_int_get(op->ptr, prop); - collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); + collection = BKE_collection_from_index(scene, collection_index); if (collection == NULL) { BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index d56791e5da0..c030c551374 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2051,7 +2051,7 @@ void ED_object_single_users(Main *bmain, single_object_action_users(bmain, scene, NULL, NULL, 0); single_mat_users_expand(bmain); /* Duplicating obdata and other IDs may require another update of the collections and objects - * pointers, especially reguarding drivers and custom props, see T66641. + * pointers, especially regarding drivers and custom props, see T66641. * Note that this whole scene duplication code and 'make single user' functions have te be * rewritten at some point to make use of proper modern ID management code, * but that is no small task. diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index 2c05ae14f2e..35762c5861e 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -92,6 +92,12 @@ static bool object_remesh_poll(bContext *C) return false; } + if (modifiers_usesMultires(ob)) { + CTX_wm_operator_poll_msg_set( + C, "The remesher cannot run with a Multires modifier in the modifier stack."); + return false; + } + return ED_operator_object_active_editable_mesh(C); } @@ -111,8 +117,13 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) ED_sculpt_undo_geometry_begin(ob); } + float isovalue = 0.0f; + if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) { + isovalue = mesh->remesh_voxel_size * 0.3f; + } + new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain( - mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity); + mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity, isovalue); if (!new_mesh) { return OPERATOR_CANCELLED; @@ -204,6 +215,57 @@ typedef struct QuadriFlowJob { int success; } QuadriFlowJob; +static bool mesh_is_manifold_consistent(Mesh *mesh) +{ + /* In this check we count boundary edges as manifold. Additionally, we also + * check that the direction of the faces are consistent and doesn't suddenly + * flip + */ + + bool is_manifold_consistent = true; + const MLoop *mloop = mesh->mloop; + char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check"); + int *edge_vert = (int *)MEM_malloc_arrayN( + mesh->totedge, sizeof(unsigned int), "remesh_consistent_check"); + + for (unsigned int i = 0; i < mesh->totedge; i++) { + edge_vert[i] = -1; + } + + for (unsigned int loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) { + const MLoop *loop = &mloop[loop_idx]; + edge_faces[loop->e] += 1; + if (edge_faces[loop->e] > 2) { + is_manifold_consistent = false; + break; + } + + if (edge_vert[loop->e] == -1) { + edge_vert[loop->e] = loop->v; + } + else if (edge_vert[loop->e] == loop->v) { + /* Mesh has flips in the surface so it is non consistent */ + is_manifold_consistent = false; + break; + } + } + + if (is_manifold_consistent) { + /* check for wire edges */ + for (unsigned int i = 0; i < mesh->totedge; i++) { + if (edge_faces[i] == 0) { + is_manifold_consistent = false; + break; + } + } + } + + MEM_freeN(edge_faces); + MEM_freeN(edge_vert); + + return is_manifold_consistent; +} + static void quadriflow_free_job(void *customdata) { QuadriFlowJob *qj = customdata; @@ -320,6 +382,12 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update Mesh *new_mesh; Mesh *bisect_mesh; + /* Check if the mesh is manifold. Quadriflow requires manifold meshes */ + if (!mesh_is_manifold_consistent(mesh)) { + qj->success = -2; + return; + } + /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without * freeing the original ID */ bisect_mesh = BKE_mesh_copy(qj->bmain, mesh); @@ -390,17 +458,22 @@ static void quadriflow_end_job(void *customdata) WM_set_locked_interface(G_MAIN->wm.first, false); - if (qj->success > 0) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!"); - } - else { - if (qj->success == 0) { + switch (qj->success) { + case 1: + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!"); + break; + case 0: WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!"); - } - else { + break; + case -1: WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!"); - } + break; + case -2: + WM_report(RPT_WARNING, + "QuadriFlow: The mesh needs to be manifold and have face normals that point in a " + "consistent direction."); + break; } } @@ -602,7 +675,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot) RNA_def_enum(ot->srna, "mode", mode_type_items, - 0, + QUADRIFLOW_REMESH_FACES, "Mode", "How to specify the amount of detail for the new mesh"); @@ -628,7 +701,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot) prop = RNA_def_int(ot->srna, "target_faces", - 1, + 4000, 1, INT_MAX, "Number of Faces", diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 28242b986f1..40fa11994f4 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -214,7 +214,7 @@ bool ED_object_base_deselect_all(ViewLayer *view_layer, View3D *v3d, int action) static int get_base_select_priority(Base *base) { - if (base->flag & BASE_VISIBLE) { + if (base->flag & BASE_VISIBLE_DEPSGRAPH) { if (base->flag & BASE_SELECTABLE) { return 3; } @@ -288,7 +288,7 @@ bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_ if (!(base->flag & BASE_SELECTED)) { ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); - if (base->flag & BASE_VISIBLE) { + if (BASE_VISIBLE(v3d, base)) { ED_object_base_select(base, BA_SELECT); } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 2ea0e9dc018..3978f7ba3b5 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3076,11 +3076,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_reportf(op->reports, - RPT_INFO, - totremoved == 1 ? "Removed %d double particle" : - "Removed %d double particles", - totremoved); + BKE_reportf(op->reports, RPT_INFO, "Removed %d double particle(s)", totremoved); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob); diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 4b1d51ee6c2..303a0714388 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -115,13 +115,7 @@ bool ED_rigidbody_constraint_add( void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob) { - RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); - - BKE_rigidbody_remove_constraint(scene, ob); - if (rbw) { - BKE_collection_object_remove(bmain, rbw->constraints, ob, false); - DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE); - } + BKE_rigidbody_remove_constraint(bmain, scene, ob, false); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index bc8a1799fa0..43ca421b9d0 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -105,7 +105,7 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob) { - BKE_rigidbody_remove_object(bmain, scene, ob); + BKE_rigidbody_remove_object(bmain, scene, ob, false); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 053ca3d8f9f..7106af25a82 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -859,7 +859,7 @@ static void screen_render_cancel(bContext *C, wmOperator *op) static void clean_viewport_memory_base(Base *base) { - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return; } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 3e001ef25b5..6dc3a1ec1ac 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -115,7 +115,7 @@ ImBuf *get_brush_icon(Brush *brush) // first use the path directly to try and load the file BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath)); - BLI_path_abs(path, BKE_main_blendfile_path_from_global()); + BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id)); /* use default colorspaces for brushes */ brush->icon_imbuf = IMB_loadiffname(path, flags, NULL); @@ -474,7 +474,7 @@ static Scene *preview_prepare_scene( } } else if (base->object->type == OB_LAMP) { - base->flag |= BASE_VISIBLE; + base->flag |= BASE_VISIBLE_DEPSGRAPH; } } } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 9f13431f25a..7970d491877 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -103,15 +103,17 @@ static Object **object_array_for_shading(bContext *C, uint *r_objects_len) ScrArea *sa = CTX_wm_area(C); SpaceProperties *sbuts = NULL; View3D *v3d = NULL; - if (sa->spacetype == SPACE_PROPERTIES) { - sbuts = sa->spacedata.first; - } - else if (sa->spacetype == SPACE_VIEW3D) { - v3d = sa->spacedata.first; + if (sa != NULL) { + if (sa->spacetype == SPACE_PROPERTIES) { + sbuts = sa->spacedata.first; + } + else if (sa->spacetype == SPACE_VIEW3D) { + v3d = sa->spacedata.first; + } } Object **objects; - if (sbuts && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) { + if (sbuts != NULL && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) { objects = MEM_mallocN(sizeof(*objects), __func__); objects[0] = (Object *)sbuts->pinid; *r_objects_len = 1; diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c index 6873495e962..a54701f8725 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -156,8 +156,8 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) } /* changes context! */ - if (WM_window_open_temp(C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE) == - NULL) { + if (WM_window_open_temp( + C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE, false) == NULL) { BKE_report(reports, RPT_ERROR, "Failed to open window!"); return NULL; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index c068fbdf7cb..9957fe0515c 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2869,7 +2869,7 @@ void ED_region_info_draw(ARegion *ar, float fill_color[4], const bool full_redraw) { - ED_region_info_draw_multiline(ar, (const char * [2]){text, NULL}, fill_color, full_redraw); + ED_region_info_draw_multiline(ar, (const char *[2]){text, NULL}, fill_color, full_redraw); } #define MAX_METADATA_STR 1024 diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 316604156de..a6b8bba73e3 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -21,7 +21,7 @@ #include "ED_screen.h" #include "GPU_batch_presets.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_matrix.h" diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index c8008fe3cc7..bbdddfadc30 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1375,13 +1375,14 @@ ScrArea *ED_screen_temp_space_open(bContext *C, int sizex, int sizey, eSpace_Type space_type, - int display_type) + int display_type, + bool dialog) { ScrArea *sa = NULL; switch (display_type) { case USER_TEMP_SPACE_DISPLAY_WINDOW: - if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type)) { + if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type, dialog)) { sa = CTX_wm_area(C); } break; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 0b374617cce..cc1f53eabde 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3946,7 +3946,7 @@ static int region_toggle_exec(bContext *C, wmOperator *op) region = CTX_wm_region(C); } - if (region) { + if (region && (region->alignment != RGN_ALIGN_NONE)) { ED_region_toggle_hidden(C, region); } ED_region_tag_redraw(region); @@ -4828,9 +4828,14 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even int sizey = 520 * UI_DPI_FAC; /* changes context! */ - if (WM_window_open_temp( - C, IFACE_("Blender Preferences"), event->x, event->y, sizex, sizey, SPACE_USERPREF) != - NULL) { + if (WM_window_open_temp(C, + IFACE_("Blender Preferences"), + event->x, + event->y, + sizex, + sizey, + SPACE_USERPREF, + false) != NULL) { /* The header only contains the editor switcher and looks empty. * So hiding in the temp window makes sense. */ ScrArea *area = CTX_wm_area(C); @@ -4879,9 +4884,14 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent but = UI_context_active_but_prop_get(C, &ptr, &prop, &index); /* changes context! */ - if (WM_window_open_temp( - C, IFACE_("Blender Drivers Editor"), event->x, event->y, sizex, sizey, SPACE_GRAPH) != - NULL) { + if (WM_window_open_temp(C, + IFACE_("Blender Drivers Editor"), + event->x, + event->y, + sizex, + sizey, + SPACE_GRAPH, + false) != NULL) { ED_drivers_editor_init(C, CTX_wm_area(C)); /* activate driver F-Curve for the property under the cursor */ @@ -4939,9 +4949,14 @@ static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *even int shift_y = 480; /* changes context! */ - if (WM_window_open_temp( - C, IFACE_("Blender Info Log"), event->x, event->y + shift_y, sizex, sizey, SPACE_INFO) != - NULL) { + if (WM_window_open_temp(C, + IFACE_("Blender Info Log"), + event->x, + event->y + shift_y, + sizex, + sizey, + SPACE_INFO, + false) != NULL) { return OPERATOR_FINISHED; } else { diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 774d4ef09b1..c59ab6279cd 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -410,7 +410,7 @@ static void load_tex_cursor_task_cb(void *__restrict userdata, if (len <= 1.0f) { float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */ - buffer[index] = 255 - (GLubyte)(255 * avg); + buffer[index] = (GLubyte)(255 * avg); } else { buffer[index] = 0; @@ -1359,13 +1359,14 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) { prev_active_vertex_index = ss->active_vertex_index; is_cursor_over_mesh = sculpt_cursor_geometry_info_update( - C, &gi, mouse, !(brush->falloff_shape & BRUSH_AIRBRUSH)); + C, &gi, mouse, (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)); } /* Use special paint crosshair cursor in all paint modes*/ wmWindow *win = CTX_wm_window(C); WM_cursor_set(win, WM_CURSOR_PAINT); - if ((mode == PAINT_MODE_SCULPT) && ss && !(brush->falloff_shape & BRUSH_AIRBRUSH)) { + if ((mode == PAINT_MODE_SCULPT) && ss && + (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; if (!ups->stroke_active) { @@ -1393,7 +1394,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) } /* Draw pose brush origin */ - if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) { + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f); if (update_previews) { BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false); @@ -1439,14 +1440,14 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) GPU_matrix_mul(vc.obact->obmat); if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) && !is_multires) { - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) { sculpt_geometry_preview_lines_update(C, ss, rds); sculpt_geometry_preview_lines_draw(pos, ss); } } /* Draw pose brush line preview */ - if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) { + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f); GPU_line_width(2.0f); immBegin(GPU_PRIM_LINES, 2); @@ -1492,7 +1493,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* Draw cached dynamic mesh preview lines */ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) && !is_multires) { - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) { GPU_matrix_push_projection(); ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_depsgraph_pointer(C), diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 24c2dfb6c6b..b4388f6c324 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -540,7 +540,7 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po RNA_float_get_array(itemptr, "mouse", mouse); pressure = RNA_float_get(itemptr, "pressure"); eraser = RNA_boolean_get(itemptr, "pen_flip"); - size = max_ff(1.0f, RNA_float_get(itemptr, "size")); + size = RNA_float_get(itemptr, "size"); /* stroking with fill tool only acts on stroke end */ if (brush->imagepaint_tool == PAINT_TOOL_FILL) { diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 4f1ae10aa62..9c95a3cee4d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -374,25 +374,65 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, /* create a mask with the falloff strength */ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, - float radius) + float radius, + const float pos[2]) { Brush *brush = painter->brush; - int xoff = -radius; - int yoff = -radius; + int offset = (int)floorf(diameter / 2.0f); unsigned short *mask, *m; - int x, y; mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); m = mask; - for (y = 0; y < diameter; y++) { - for (x = 0; x < diameter; x++, m++) { - float xy[2] = {x + xoff, y + yoff}; - float len = len_v2(xy); + int aa_samples = 1.0f / (radius * 0.20f); + aa_samples = clamp_i(aa_samples, 3, 16); - *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius)); + /* Temporal until we have the brush properties */ + const float hardness = 1.0f; + const float rotation = 0.0f; + + float aa_offset = 1.0f / (2.0f * (float)aa_samples); + float aa_step = 1.0f / (float)aa_samples; + + float bpos[2]; + bpos[0] = pos[0] - floorf(pos[0]) + offset + aa_offset; + bpos[1] = pos[1] - floorf(pos[1]) + offset + aa_offset; + + const float co = cosf(DEG2RADF(rotation)); + const float si = sinf(DEG2RADF(rotation)); + + float norm_factor = 65535.0f / (float)(aa_samples * aa_samples); + + for (int y = 0; y < diameter; y++) { + for (int x = 0; x < diameter; x++, m++) { + float total_samples = 0; + for (int i = 0; i < aa_samples; i++) { + for (int j = 0; j < aa_samples; j++) { + float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)}; + float xy_rot[2]; + sub_v2_v2(pixel_xy, bpos); + + xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1]; + xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1]; + + float len = len_v2(xy_rot); + float p = len / radius; + if (hardness < 1.0f) { + p = (p - hardness) / (1 - hardness); + p = 1.0f - p; + CLAMP(p, 0, 1); + } + else { + p = 1.0; + } + float hardness_factor = 3.0f * p * p - 2.0f * p * p * p; + float curve = BKE_brush_curve_strength_clamped(brush, len, radius); + total_samples += curve * hardness_factor; + } + } + *m = (unsigned short)(total_samples * norm_factor); } } @@ -721,7 +761,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; - const int diameter = 2 * size; + /* Adding 4 pixels of padding for brush antialiasing */ + const int diameter = MAX2(1, size * 2) + 4; bool do_random = false; bool do_partial_update = false; @@ -802,15 +843,13 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, } /* curve mask can only change if the size changes */ - if (diameter != cache->lastdiameter) { - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - cache->curve_mask = NULL; - } - - cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size); + if (cache->curve_mask) { + MEM_freeN(cache->curve_mask); + cache->curve_mask = NULL; } + cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos); + /* detect if we need to recreate image brush buffer */ if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) || do_random || update_color) { diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 69eed84fe2b..19380fb9022 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -29,7 +29,6 @@ struct Brush; struct ColorManagedDisplay; struct ColorSpace; struct ImagePool; -struct ListBase; struct MTex; struct Object; struct Paint; @@ -37,7 +36,6 @@ struct PaintStroke; struct PointerRNA; struct RegionView3D; struct Scene; -struct UndoStep; struct VPaint; struct ViewContext; struct bContext; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index a93e55685d2..d160fba4013 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -166,9 +166,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) .value = value, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); @@ -343,9 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * .clip_planes_final = clip_planes_final, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); if (nodes) { MEM_freeN(nodes); @@ -532,9 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.mode = mode; data.task_data.value = value; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); if (nodes) { MEM_freeN(nodes); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index d8be345cc84..36418045551 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -256,6 +256,7 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ELASTIC_DEFORM, SCULPT_TOOL_POSE)) { return false; @@ -668,7 +669,7 @@ static float paint_space_stroke_spacing(bContext *C, return max_ff(0.001f, size_clamp * spacing / 50.f); } else { - return max_ff(1.0, size_clamp * spacing / 50.0f); + return max_ff(stroke->zoom_2d, size_clamp * spacing / 50.0f); } } @@ -909,16 +910,21 @@ PaintStroke *paint_stroke_new(bContext *C, void paint_stroke_free(bContext *C, wmOperator *op) { RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d) { + rv3d->rflag &= ~RV3D_PAINTING; + } + + BKE_paint_set_overlay_override(0); + PaintStroke *stroke = op->customdata; - UnifiedPaintSettings *ups = stroke->ups; + if (stroke == NULL) { + return; + } + UnifiedPaintSettings *ups = stroke->ups; ups->draw_anchored = false; ups->stroke_active = false; - if (rv3d) { - rv3d->rflag &= ~RV3D_PAINTING; - } - if (stroke->timer) { WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer); } @@ -933,7 +939,6 @@ void paint_stroke_free(bContext *C, wmOperator *op) BLI_freelistN(&stroke->line); - BKE_paint_set_overlay_override(0); MEM_SAFE_FREE(op->customdata); } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 3554a6cc546..77c95c6acb3 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2072,9 +2072,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data, struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); uint accum_len = 0; double accum_weight = 0.0; @@ -2120,22 +2120,22 @@ static void wpaint_paint_leaves(bContext *C, data.strength = BKE_brush_weight_get(scene, brush); /* NOTE: current mirroring code cannot be run in parallel */ - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode); switch ((eBrushWeightPaintTool)brush->weightpaint_tool) { case WPAINT_TOOL_AVERAGE: calculate_average_weight(&data, nodes, totnode); - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; case WPAINT_TOOL_SMEAR: - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); break; case WPAINT_TOOL_BLUR: - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); break; case WPAINT_TOOL_DRAW: - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; } } @@ -2587,11 +2587,6 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) * - revise whether op->customdata should be added in object, in set_vpaint */ -typedef struct PolyFaceMap { - struct PolyFaceMap *next, *prev; - int facenr; -} PolyFaceMap; - struct VPaintData { ViewContext vc; struct NormalAnglePrecalc normal_angle_precalc; @@ -3131,9 +3126,9 @@ static void calculate_average_color(SculptThreadedTaskData *data, struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); uint accum_len = 0; uint accum_value[3] = {0}; @@ -3177,21 +3172,21 @@ static void vpaint_paint_leaves(bContext *C, .lcol = (uint *)me->mloopcol, .me = me, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) { case VPAINT_TOOL_AVERAGE: calculate_average_color(&data, nodes, totnode); - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; case VPAINT_TOOL_BLUR: - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); break; case VPAINT_TOOL_SMEAR: - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); break; case VPAINT_TOOL_DRAW: - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b9d621fc1fb..d2d424745da 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -64,6 +64,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" #include "DEG_depsgraph.h" @@ -185,7 +186,6 @@ static float sculpt_vertex_mask_get(SculptSession *ss, int index) static int sculpt_active_vertex_get(SculptSession *ss) { - BLI_assert(BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: return ss->active_vertex_index; @@ -211,14 +211,19 @@ static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3]) #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 typedef struct SculptVertexNeighborIter { + /* Storage */ int *neighbors; int size; int capacity; - int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; - int index; + /* Internal iterator. */ + int num_duplicates; int i; + + /* Public */ + int index; + bool is_duplicate; } SculptVertexNeighborIter; static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index) @@ -254,6 +259,7 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss, BMIter liter; BMLoop *l; iter->size = 0; + iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; @@ -276,6 +282,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, int i; MeshElemMap *vert_map = &ss->pmap[(int)index]; iter->size = 0; + iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; @@ -293,20 +300,44 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, } } -static void sculpt_vertex_neighbors_get_grids(SculptSession *UNUSED(ss), - int UNUSED(index), +static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, + const int index, + const bool include_duplicates, SculptVertexNeighborIter *iter) { - /* TODO: implement this for multires. It might also be worth changing this - * iterator to provide a coordinate and mask pointer directly for effiency, - * rather than converting back and forth between CCGElem and global index. */ + /* TODO: optimize this. We could fill SculptVertexNeighborIter directly, + * maybe provide coordinate and mask pointers directly rather than converting + * back and forth between CCGElem and global index. */ + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + + SubdivCCGCoord coord = {.grid_index = grid_index, + .x = vertex_index % key->grid_size, + .y = vertex_index / key->grid_size}; + + SubdivCCGNeighbors neighbors; + BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors); + iter->size = 0; + iter->num_duplicates = neighbors.num_duplicates; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; + + for (int i = 0; i < neighbors.size; i++) { + sculpt_vertex_neighbor_add(iter, + neighbors.coords[i].grid_index * key->grid_area + + neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x); + } + + if (neighbors.coords != neighbors.coords_fixed) { + MEM_freeN(neighbors.coords); + } } static void sculpt_vertex_neighbors_get(SculptSession *ss, - int index, + const int index, + const bool include_duplicates, SculptVertexNeighborIter *iter) { switch (BKE_pbvh_type(ss->pbvh)) { @@ -317,17 +348,28 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss, sculpt_vertex_neighbors_get_bmesh(ss, index, iter); return; case PBVH_GRIDS: - sculpt_vertex_neighbors_get_grids(ss, index, iter); + sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter); return; } } +/* Iterator over neighboring vertices. */ #define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \ - sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \ + 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]; +/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come + * first since they are nearest for floodfill. */ +#define sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, v_index, neighbor_iterator) \ + 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.size - neighbor_iterator.num_duplicates); + #define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \ } \ if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \ @@ -381,16 +423,19 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void nearest_vertex_get_finalize(void *__restrict userdata, void *__restrict tls) +static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - NearestVertexTLSData *nvtd = tls; - if (data->nearest_vertex_index == -1) { - data->nearest_vertex_index = nvtd->nearest_vertex_index; + NearestVertexTLSData *join = chunk_join; + NearestVertexTLSData *nvtd = chunk; + if (join->nearest_vertex_index == -1) { + join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } - else if (nvtd->nearest_vertex_distance_squared < data->nearest_vertex_distance_squared) { - data->nearest_vertex_index = nvtd->nearest_vertex_index; - data->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; + else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { + join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } } @@ -417,25 +462,23 @@ static int sculpt_nearest_vertex_get( .ob = ob, .nodes = nodes, .max_distance_squared = max_distance * max_distance, - .nearest_vertex_index = -1, }; copy_v3_v3(task_data.nearest_vertex_search_co, co); - task_data.nearest_vertex_distance_squared = FLT_MAX; NearestVertexTLSData nvtd; nvtd.nearest_vertex_index = -1; nvtd.nearest_vertex_distance_squared = FLT_MAX; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = nearest_vertex_get_finalize; + settings.func_reduce = nearest_vertex_get_reduce; settings.userdata_chunk = &nvtd; settings.userdata_chunk_size = sizeof(NearestVertexTLSData); - BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); MEM_SAFE_FREE(nodes); - return task_data.nearest_vertex_index; + return nvtd.nearest_vertex_index; } static bool is_symmetry_iteration_valid(char i, char symm) @@ -470,28 +513,18 @@ typedef struct SculptFloodFill { char *visited_vertices; } SculptFloodFill; -typedef struct SculptFloodFillIterator { - int v; - int it; - float edge_factor; -} SculptFloodFillIterator; - static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood) { int vertex_count = sculpt_vertex_count_get(ss); sculpt_vertex_random_access_init(ss); - flood->queue = BLI_gsqueue_new(sizeof(SculptFloodFillIterator)); + flood->queue = BLI_gsqueue_new(sizeof(int)); flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices"); } static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index) { - SculptFloodFillIterator mevit; - mevit.v = index; - mevit.it = 0; - mevit.edge_factor = 1.0f; - BLI_gsqueue_push(flood->queue, &mevit); + BLI_gsqueue_push(flood->queue, &index); } static void sculpt_floodfill_add_active( @@ -518,32 +551,24 @@ static void sculpt_floodfill_add_active( } } -static void sculpt_floodfill_execute(SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, - const SculptFloodFillIterator *from, - SculptFloodFillIterator *to, - void *userdata), - void *userdata) +static void sculpt_floodfill_execute( + SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), + void *userdata) { - /* TODO: multires support, taking into account duplicate vertices and - * correctly handling them in the pose, automask and mask expand callbacks. */ while (!BLI_gsqueue_is_empty(flood->queue)) { - SculptFloodFillIterator from; - BLI_gsqueue_pop(flood->queue, &from); + int from_v; + BLI_gsqueue_pop(flood->queue, &from_v); SculptVertexNeighborIter ni; - sculpt_vertex_neighbors_iter_begin(ss, from.v, ni) + sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni) { - if (flood->visited_vertices[ni.index] == 0) { - flood->visited_vertices[ni.index] = 1; + const int to_v = ni.index; + if (flood->visited_vertices[to_v] == 0) { + flood->visited_vertices[to_v] = 1; - SculptFloodFillIterator to; - to.v = ni.index; - to.it = from.it + 1; - to.edge_factor = 0.0f; - - if (func(ss, &from, &to, userdata)) { - BLI_gsqueue_push(flood->queue, &to); + if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { + BLI_gsqueue_push(flood->queue, &to_v); } } } @@ -912,9 +937,9 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode); - BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); MEM_SAFE_FREE(nodes); } @@ -1097,9 +1122,8 @@ bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float loca local_co[1] = fabsf(local_co[1]); local_co[2] = fabsf(local_co[2]); + const float p = 8.0f; if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) { - float p = 4.0f; - test->dist = ((powf(local_co[0], p) + powf(local_co[1], p) + powf(local_co[2], p)) / powf(side, p)); @@ -1194,11 +1218,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br) { - // REMOVE WITH PBVH_GRIDS - if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return false; - } - if (sculpt_stroke_is_dynamic_topology(ss, br)) { return false; } @@ -1229,7 +1248,7 @@ static void sculpt_automasking_end(Object *ob) static bool sculpt_automasking_is_constrained_by_radius(Brush *br) { /* 2D falloff is not constrained by radius */ - if (br->falloff_shape & BRUSH_AIRBRUSH) { + if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { return false; } @@ -1247,17 +1266,15 @@ typedef struct AutomaskFloodFillData { char symm; } AutomaskFloodFillData; -static bool automask_floodfill_cb(SculptSession *ss, - const SculptFloodFillIterator *UNUSED(from), - SculptFloodFillIterator *to, - void *userdata) +static bool automask_floodfill_cb( + SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata) { AutomaskFloodFillData *data = userdata; - data->automask_factor[to->v] = 1.0f; + data->automask_factor[to_v] = 1.0f; return (!data->use_radius || sculpt_is_vertex_inside_brush_radius_symm( - sculpt_vertex_co_get(ss, to->v), data->location, data->radius, data->symm)); + sculpt_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); } static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) @@ -1396,9 +1413,10 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * \{ */ typedef struct AreaNormalCenterTLSData { - float private_co[2][3]; - float private_no[2][3]; - int private_count[2]; + /* 0=towards view, 1=flipped */ + float area_cos[2][3]; + float area_nos[2][3]; + int area_count[2]; } AreaNormalCenterTLSData; static void calc_area_normal_and_center_task_cb(void *__restrict userdata, @@ -1408,8 +1426,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; AreaNormalCenterTLSData *anctd = tls->userdata_chunk; - float(*area_nos)[3] = data->area_nos; - float(*area_cos)[3] = data->area_cos; + const bool use_area_nos = data->use_area_nos; + const bool use_area_cos = data->use_area_cos; PBVHVertexIter vd; SculptUndoNode *unode = NULL; @@ -1428,7 +1446,10 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, /* Update the test radius to sample the normal using the normal radius of the brush */ if (data->brush->ob_mode == OB_MODE_SCULPT) { float test_radius = sqrtf(test.radius_squared); - test_radius *= data->brush->normal_radius_factor; + /* Layer brush produces artifacts with normal radius */ + if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) { + test_radius *= data->brush->normal_radius_factor; + } test.radius_squared = test_radius * test_radius; } @@ -1459,13 +1480,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, normal_tri_v3(no, UNPACK3(co_tri)); flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f); - if (area_cos) { - add_v3_v3(anctd->private_co[flip_index], co); + if (use_area_cos) { + add_v3_v3(anctd->area_cos[flip_index], co); } - if (area_nos) { - add_v3_v3(anctd->private_no[flip_index], no); + if (use_area_nos) { + add_v3_v3(anctd->area_nos[flip_index], no); } - anctd->private_count[flip_index] += 1; + anctd->area_count[flip_index] += 1; } } } @@ -1511,40 +1532,37 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <= 0.0f); - if (area_cos) { - add_v3_v3(anctd->private_co[flip_index], co); + if (use_area_cos) { + add_v3_v3(anctd->area_cos[flip_index], co); } - if (area_nos) { - add_v3_v3(anctd->private_no[flip_index], no); + if (use_area_nos) { + add_v3_v3(anctd->area_nos[flip_index], no); } - anctd->private_count[flip_index] += 1; + anctd->area_count[flip_index] += 1; } } BKE_pbvh_vertex_iter_end; } } -static void calc_area_normal_and_center_finalize(void *__restrict userdata, void *__restrict tls) +static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - AreaNormalCenterTLSData *anctd = tls; - float(*area_nos)[3] = data->area_nos; - float(*area_cos)[3] = data->area_cos; + AreaNormalCenterTLSData *join = chunk_join; + AreaNormalCenterTLSData *anctd = chunk; + /* for flatten center */ - if (area_cos) { - add_v3_v3(area_cos[0], anctd->private_co[0]); - add_v3_v3(area_cos[1], anctd->private_co[1]); - } + add_v3_v3(join->area_cos[0], anctd->area_cos[0]); + add_v3_v3(join->area_cos[1], anctd->area_cos[1]); /* for area normal */ - if (area_nos) { - add_v3_v3(area_nos[0], anctd->private_no[0]); - add_v3_v3(area_nos[1], anctd->private_no[1]); - } + add_v3_v3(join->area_nos[0], anctd->area_nos[0]); + add_v3_v3(join->area_nos[1], anctd->area_nos[1]); /* weights */ - data->count[0] += anctd->private_count[0]; - data->count[1] += anctd->private_count[1]; + join->area_count[0] += anctd->area_count[0]; + join->area_count[1] += anctd->area_count[1]; } static void calc_area_center( @@ -1555,11 +1573,6 @@ static void calc_area_center( const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); int n; - /* 0=towards view, 1=flipped */ - float area_cos[2][3] = {{0.0f}}; - - int count[2] = {0}; - /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */ SculptThreadedTaskData data = { .sd = NULL, @@ -1568,24 +1581,22 @@ static void calc_area_center( .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, - .area_cos = area_cos, - .area_nos = NULL, - .count = count, + .use_area_cos = true, }; AreaNormalCenterTLSData anctd = {{{0}}}; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = calc_area_normal_and_center_finalize; + settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* for flatten center */ - for (n = 0; n < ARRAY_SIZE(area_cos); n++) { - if (count[n] != 0) { - mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]); + for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { + if (anctd.area_count[n] != 0) { + mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]); break; } } @@ -1613,11 +1624,6 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush, SculptSession *ss = ob->sculpt; const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); - /* 0=towards view, 1=flipped */ - float area_nos[2][3] = {{0.0f}}; - - int count[2] = {0}; - /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { .sd = NULL, @@ -1626,24 +1632,22 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, - .area_cos = NULL, - .area_nos = area_nos, - .count = count, + .use_area_nos = true, .any_vertex_sampled = false, }; AreaNormalCenterTLSData anctd = {{{0}}}; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode); - settings.func_finalize = calc_area_normal_and_center_finalize; + settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* for area normal */ - for (int i = 0; i < ARRAY_SIZE(area_nos); i++) { - if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) { + for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) { + if (normalize_v3_v3(r_area_no, anctd.area_nos[i]) != 0.0f) { break; } } @@ -1661,12 +1665,6 @@ static void calc_area_normal_and_center( const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); int n; - /* 0=towards view, 1=flipped */ - float area_cos[2][3] = {{0.0f}}; - float area_nos[2][3] = {{0.0f}}; - - int count[2] = {0}; - /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { .sd = NULL, @@ -1675,24 +1673,23 @@ static void calc_area_normal_and_center( .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, - .area_cos = area_cos, - .area_nos = area_nos, - .count = count, + .use_area_cos = true, + .use_area_nos = true, }; AreaNormalCenterTLSData anctd = {{{0}}}; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = calc_area_normal_and_center_finalize; + settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* for flatten center */ - for (n = 0; n < ARRAY_SIZE(area_cos); n++) { - if (count[n] != 0) { - mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]); + for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { + if (anctd.area_count[n] != 0) { + mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]); break; } } @@ -1701,8 +1698,8 @@ static void calc_area_normal_and_center( } /* for area normal */ - for (n = 0; n < ARRAY_SIZE(area_nos); n++) { - if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) { + for (n = 0; n < ARRAY_SIZE(anctd.area_nos); n++) { + if (normalize_v3_v3(r_area_no, anctd.area_nos[n]) != 0.0f) { break; } } @@ -1736,11 +1733,13 @@ static float brush_strength(const Sculpt *sd, switch (brush->sculpt_tool) { case SCULPT_TOOL_CLAY: - case SCULPT_TOOL_CLAY_STRIPS: case SCULPT_TOOL_DRAW: case SCULPT_TOOL_DRAW_SHARP: case SCULPT_TOOL_LAYER: return alpha * flip * pressure * overlap * feather; + case SCULPT_TOOL_CLAY_STRIPS: + /* Clay Strips needs extra strength to compensate for its default normal radius */ + return alpha * flip * pressure * overlap * feather * 1.3f; case SCULPT_TOOL_MASK: overlap = (1 + overlap) / 2; @@ -2083,9 +2082,15 @@ static void update_sculpt_normal(Sculpt *sd, Object *ob, PBVHNode **nodes, int t { const Brush *brush = BKE_paint_brush(&sd->paint); StrokeCache *cache = ob->sculpt->cache; + /* Grab brush does not update the sculpt normal during a stroke */ + const bool update_normal = !(brush->flag & BRUSH_ORIGINAL_NORMAL) && + !(brush->sculpt_tool == SCULPT_TOOL_GRAB) && + !(brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) && + !(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK && + cache->normal_weight > 0.0f); if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 && - (cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { + (cache->first_time || update_normal)) { calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal); if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal); @@ -2796,7 +2801,7 @@ static void smooth(Sculpt *sd, .strength = strength, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); switch (type) { @@ -2814,16 +2819,16 @@ static void smooth(Sculpt *sd, settings.userdata_chunk = data_chunk; settings.userdata_chunk_size = size; - BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); MEM_freeN(data_chunk); break; } case PBVH_FACES: - BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); break; case PBVH_BMESH: - BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); break; } @@ -2855,10 +2860,10 @@ static void bmesh_topology_rake( .nodes = nodes, .strength = factor, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); } } @@ -2912,9 +2917,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); } static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) @@ -2999,9 +3004,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .offset = offset, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); } static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, @@ -3075,9 +3080,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .offset = offset, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); } /** @@ -3191,9 +3196,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .flippedbstrength = flippedbstrength, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); } static void do_pinch_brush_task_cb_ex(void *__restrict userdata, @@ -3253,9 +3258,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); } static void do_grab_brush_task_cb_ex(void *__restrict userdata, @@ -3325,9 +3330,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); } /* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity @@ -3566,6 +3571,10 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + SculptThreadedTaskData data = { .sd = sd, .ob = ob, @@ -3574,9 +3583,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .grab_delta = grab_delta, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); } static void do_pose_brush_task_cb_ex(void *__restrict userdata, @@ -3628,10 +3637,6 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) float pose_initial_co[3]; float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4]; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return; - } - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); copy_v3_v3(pose_origin, ss->cache->pose_origin); @@ -3667,14 +3672,14 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .transform_trans_inv = transform_trans_inv, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); } typedef struct PoseGrowFactorTLSData { float pos_avg[3]; - int tot_pos_avg; + int pos_count; } PoseGrowFactorTLSData; static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, @@ -3703,7 +3708,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, data->pose_factor[vd.index] = max; if (check_vertex_pivot_symmetry(vd.co, active_co, symm)) { add_v3_v3(gftd->pos_avg, vd.co); - gftd->tot_pos_avg++; + gftd->pos_count++; } } } @@ -3711,12 +3716,14 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void pose_brush_grow_factor_finalize(void *__restrict userdata, void *__restrict tls) +static void pose_brush_grow_factor_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - PoseGrowFactorTLSData *gftd = tls; - add_v3_v3(data->tot_pos_avg, gftd->pos_avg); - data->tot_pos_count += gftd->tot_pos_avg; + PoseGrowFactorTLSData *join = chunk_join; + PoseGrowFactorTLSData *gftd = chunk; + add_v3_v3(join->pos_avg, gftd->pos_avg); + join->pos_count += gftd->pos_count; } /* Grow the factor until its boundary is near to the offset pose origin */ @@ -3735,12 +3742,12 @@ static void sculpt_pose_grow_pose_factor( .totnode = totnode, .pose_factor = pose_factor, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; PoseGrowFactorTLSData gftd; - gftd.tot_pos_avg = 0; + gftd.pos_count = 0; zero_v3(gftd.pos_avg); BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = pose_brush_grow_factor_finalize; + settings.func_reduce = pose_brush_grow_factor_reduce; settings.userdata_chunk = &gftd; settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData); @@ -3748,15 +3755,13 @@ static void sculpt_pose_grow_pose_factor( float prev_len = FLT_MAX; data.prev_mask = MEM_mallocN(sculpt_vertex_count_get(ss) * sizeof(float), "prev mask"); while (grow_next_iteration) { - zero_v3(data.tot_pos_avg); - data.tot_pos_count = 0; zero_v3(gftd.pos_avg); - gftd.tot_pos_avg = 0; + gftd.pos_count = 0; memcpy(data.prev_mask, pose_factor, sculpt_vertex_count_get(ss) * sizeof(float)); - BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); - if (data.tot_pos_count != 0) { - mul_v3_fl(data.tot_pos_avg, 1.0f / (float)data.tot_pos_count); - float len = len_v3v3(data.tot_pos_avg, pose_origin); + BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); + if (gftd.pos_count != 0) { + mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count); + float len = len_v3v3(gftd.pos_avg, pose_origin); if (len < prev_len) { prev_len = len; grow_next_iteration = true; @@ -3806,25 +3811,25 @@ typedef struct PoseFloodFillData { int tot_co; } PoseFloodFillData; -static bool pose_floodfill_cb(SculptSession *ss, - const SculptFloodFillIterator *UNUSED(from), - SculptFloodFillIterator *to, - void *userdata) +static bool pose_floodfill_cb( + SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; if (data->pose_factor) { - data->pose_factor[to->v] = 1.0f; + data->pose_factor[to_v] = 1.0f; } - const float *co = sculpt_vertex_co_get(ss, to->v); + const float *co = sculpt_vertex_co_get(ss, to_v); if (sculpt_pose_brush_is_vertex_inside_brush_radius( co, data->pose_initial_co, data->radius, data->symm)) { return true; } else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) { - add_v3_v3(data->pose_origin, co); - data->tot_co++; + if (!is_duplicate) { + add_v3_v3(data->pose_origin, co); + data->tot_co++; + } } return false; @@ -3925,9 +3930,9 @@ static void sculpt_pose_brush_init( /* Smooth the pose brush factor for cleaner deformation */ for (int i = 0; i < 4; i++) { - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); } MEM_SAFE_FREE(nodes); @@ -3995,9 +4000,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); } static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, @@ -4116,9 +4121,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .grab_delta = grab_delta, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); } static void do_thumb_brush_task_cb_ex(void *__restrict userdata, @@ -4188,9 +4193,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); } static void do_rotate_brush_task_cb_ex(void *__restrict userdata, @@ -4261,9 +4266,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .angle = angle, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); } static void do_layer_brush_task_cb_ex(void *__restrict userdata, @@ -4358,9 +4363,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; BLI_mutex_init(&data.mutex); - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); BLI_mutex_end(&data.mutex); } @@ -4426,9 +4431,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); } static void calc_sculpt_plane( @@ -4635,9 +4640,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); } static void do_clay_brush_task_cb_ex(void *__restrict userdata, @@ -4733,9 +4738,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); } static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, @@ -4863,9 +4868,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .mat = mat, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); } static void do_fill_brush_task_cb_ex(void *__restrict userdata, @@ -4956,9 +4961,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); } static void do_scrape_brush_task_cb_ex(void *__restrict userdata, @@ -5048,9 +5053,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); } static void do_gravity_task_cb_ex(void *__restrict userdata, @@ -5117,9 +5122,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl .offset = offset, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); } void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) @@ -5271,7 +5276,12 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe else { const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original; - const float radius_scale = 1.0f; + float radius_scale = 1.0f; + /* With these options enabled not all required nodes are inside the original brush radius, so + * the brush can produce artifacts in some situations */ + if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) { + radius_scale = 2.0f; + } nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode); } @@ -5286,9 +5296,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); if (sculpt_brush_needs_normal(ss, brush)) { update_sculpt_normal(sd, ob, nodes, totnode); @@ -5306,9 +5316,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) { - if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) { - sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius); - } + sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius); } /* Apply one type of brush action */ @@ -5425,7 +5433,7 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd) copy_v3_v3(ss->deform_cos[index], vd->co); copy_v3_v3(ss->orig_cos[index], newco); - if (!ss->kb) { + if (!ss->shapekey_active) { copy_v3_v3(me->mvert[index].co, newco); } } @@ -5481,7 +5489,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata, sculpt_clip(sd, ss, vd.co, val); - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { sculpt_flush_pbvhvert_deform(ob, &vd); } } @@ -5508,9 +5516,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); } MEM_SAFE_FREE(nodes); @@ -5532,7 +5540,7 @@ static void sculpt_update_keyblock(Object *ob) } if (vertCos) { - sculpt_vertcos_to_key(ob, ss->kb, vertCos); + sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos); if (vertCos != ss->orig_cos) { MEM_freeN(vertCos); @@ -5578,7 +5586,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use PBVHNode **nodes; float(*vertCos)[3] = NULL; - if (ss->kb) { + if (ss->shapekey_active) { vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts"); /* mesh could have isolated verts which wouldn't be in BVH, @@ -5598,12 +5606,12 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use .vertCos = vertCos, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings); if (vertCos) { - sculpt_vertcos_to_key(ob, ss->kb, vertCos); + sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos); MEM_freeN(vertCos); } @@ -5614,7 +5622,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use * after applying coords from keyblock on base mesh */ BKE_mesh_calc_normals(me); } - else if (ss->kb) { + else if (ss->shapekey_active) { sculpt_update_keyblock(ob); } } @@ -6378,7 +6386,8 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const B View3D *v3d = CTX_wm_view3d(C); bool need_pmap = sculpt_needs_conectivity_info(brush, ss, 0); - if (ss->kb || ss->modifiers_active || (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) { + if (ss->shapekey_active || ss->deform_modifiers_active || + (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false); } @@ -6559,13 +6568,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C, /* Update the active vertex of the SculptSession */ ss->active_vertex_index = srd.active_vertex_index; - - if (!ss->multires) { - copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss)); - } - else { - zero_v3(out->active_vertex_co); - } + copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss)); copy_v3_v3(out->location, ray_normal); mul_v3_fl(out->location, srd.depth); @@ -6877,7 +6880,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdate /* optimization: if there is locked key and active modifiers present in */ /* the stack, keyblock is updating at each step. otherwise we could update */ /* keyblock only when stroke is finished */ - if (ss->kb && !ss->modifiers_active) { + if (ss->shapekey_active && !ss->deform_modifiers_active) { sculpt_update_keyblock(ob); } @@ -6970,10 +6973,10 @@ static void sculpt_stroke_update_step(bContext *C, * Same applies to the DEG_id_tag_update() invoked from * sculpt_flush_update_step(). */ - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool)); } - else if (ss->kb) { + else if (ss->shapekey_active) { sculpt_update_keyblock(ob); } @@ -8146,43 +8149,36 @@ static void filter_cache_init_task_cb(void *__restrict userdata, const TaskParallelTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; PBVHNode *node = data->nodes[i]; - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { - if (!vd.mask || (vd.mask && *vd.mask < 1.0f)) { - data->node_mask[i] = 1; - } - } - BKE_pbvh_vertex_iter_end; - - if (data->node_mask[i] == 1) { - sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); - } + sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); } static void sculpt_filter_cache_init(Object *ob, Sculpt *sd) { SculptSession *ss = ob->sculpt; PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - int totnode; ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache"); ss->filter_cache->random_seed = rand(); + float center[3] = {0.0f}; SculptSearchSphereData search_data = { .original = true, - }; - BKE_pbvh_search_gather(pbvh, NULL, &search_data, &nodes, &totnode); + .center = center, + .radius_squared = FLT_MAX, + .ignore_fully_masked = true, - int *node_mask = MEM_callocN((unsigned int)totnode * sizeof(int), "node mask"); + }; + BKE_pbvh_search_gather(pbvh, + sculpt_search_sphere_cb, + &search_data, + &ss->filter_cache->nodes, + &ss->filter_cache->totnode); - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_normals_update(nodes[i]); + for (int i = 0; i < ss->filter_cache->totnode; i++) { + BKE_pbvh_node_mark_normals_update(ss->filter_cache->nodes[i]); } /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing. @@ -8194,40 +8190,14 @@ static void sculpt_filter_cache_init(Object *ob, Sculpt *sd) SculptThreadedTaskData data = { .sd = sd, .ob = ob, - .nodes = nodes, - .node_mask = node_mask, + .nodes = ss->filter_cache->nodes, }; - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, filter_cache_init_task_cb, &settings); - - int tot_active_nodes = 0; - int active_node_index = 0; - PBVHNode **active_nodes; - - /* Count number of PBVH nodes that are not fully masked */ - for (int i = 0; i < totnode; i++) { - if (node_mask[i] == 1) { - tot_active_nodes++; - } - } - - /* Create the final list of nodes that is going to be processed in the filter */ - active_nodes = MEM_callocN(tot_active_nodes * sizeof(PBVHNode *), "active nodes"); - - for (int i = 0; i < totnode; i++) { - if (node_mask[i] == 1) { - active_nodes[active_node_index] = nodes[i]; - active_node_index++; - } - } - - ss->filter_cache->nodes = active_nodes; - ss->filter_cache->totnode = tot_active_nodes; - - MEM_SAFE_FREE(nodes); - MEM_SAFE_FREE(node_mask); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range( + 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings); } static void sculpt_filter_cache_free(SculptSession *ss) @@ -8299,6 +8269,11 @@ static void mesh_filter_task_cb(void *__restrict userdata, float fade = vd.mask ? *vd.mask : 0.0f; fade = 1 - fade; fade *= data->filter_strength; + + if (fade == 0.0f) { + continue; + } + copy_v3_v3(orig_co, orig_data.co); switch (filter_type) { case MESH_FILTER_SMOOTH: @@ -8417,12 +8392,12 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * .filter_strength = filter_strength, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); - if (ss->modifiers_active || ss->kb) { + if (ss->deform_modifiers_active || ss->shapekey_active) { sculpt_flush_stroke_deform(sd, ob, true); } @@ -8440,10 +8415,6 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SculptSession *ss = ob->sculpt; PBVH *pbvh = ob->sculpt->pbvh; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - int deform_axis = RNA_enum_get(op->ptr, "deform_axis"); if (deform_axis == 0) { return OPERATOR_CANCELLED; @@ -8654,10 +8625,6 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) int totnode; int filter_type = RNA_enum_get(op->ptr, "filter_type"); - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); sculpt_vertex_random_access_init(ss); @@ -8702,9 +8669,9 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) .prev_mask = prev_mask, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { MEM_freeN(prev_mask); @@ -8813,13 +8780,14 @@ static void dirty_mask_compute_range_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void dirty_mask_compute_range_finalize(void *__restrict userdata, void *__restrict tls) +static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - DirtyMaskRangeData *range = tls; - - data->dirty_mask_min = min_ff(range->min, data->dirty_mask_min); - data->dirty_mask_max = max_ff(range->max, data->dirty_mask_max); + DirtyMaskRangeData *join = chunk_join; + DirtyMaskRangeData *range = chunk; + join->min = min_ff(range->min, join->min); + join->max = max_ff(range->max, join->max); } static void dirty_mask_apply_task_cb(void *__restrict userdata, @@ -8871,10 +8839,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) Sculpt *sd = CTX_data_tool_settings(C)->sculpt; int totnode; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); sculpt_vertex_random_access_init(ss); @@ -8894,8 +8858,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) .sd = sd, .ob = ob, .nodes = nodes, - .dirty_mask_min = FLT_MAX, - .dirty_mask_max = -FLT_MAX, .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"), }; DirtyMaskRangeData range = { @@ -8903,15 +8865,17 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) .max = -FLT_MAX, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = dirty_mask_compute_range_finalize; + settings.func_reduce = dirty_mask_compute_range_reduce; settings.userdata_chunk = ⦥ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData); - BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); - BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); + data.dirty_mask_min = range.min; + data.dirty_mask_max = range.max; + BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); MEM_SAFE_FREE(nodes); @@ -9070,10 +9034,10 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations"); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false); for (int i = 0; i < smooth_iterations; i++) { - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings); } /* Pivot position */ @@ -9139,10 +9103,10 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"), .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); ss->filter_cache->mask_update_current_it = mask_expand_update_it; } @@ -9157,26 +9121,37 @@ typedef struct MaskExpandFloodFillData { bool use_normals; } MaskExpandFloodFillData; -static bool mask_expand_floodfill_cb(SculptSession *ss, - const SculptFloodFillIterator *from, - SculptFloodFillIterator *to, - void *userdata) +static bool mask_expand_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) { MaskExpandFloodFillData *data = userdata; - ss->filter_cache->mask_update_it[to->v] = to->it; - if (to->it > ss->filter_cache->mask_update_last_it) { - ss->filter_cache->mask_update_last_it = to->it; - } + if (!is_duplicate) { + int to_it = ss->filter_cache->mask_update_it[from_v] + 1; + ss->filter_cache->mask_update_it[to_v] = to_it; + if (to_it > ss->filter_cache->mask_update_last_it) { + ss->filter_cache->mask_update_last_it = to_it; + } - if (data->use_normals) { - float current_normal[3], prev_normal[3]; - sculpt_vertex_normal_get(ss, to->v, current_normal); - sculpt_vertex_normal_get(ss, from->v, prev_normal); - to->edge_factor = dot_v3v3(current_normal, prev_normal) * from->edge_factor; - ss->filter_cache->normal_factor[to->v] = dot_v3v3(data->original_normal, current_normal) * - powf(from->edge_factor, data->edge_sensitivity); - CLAMP(ss->filter_cache->normal_factor[to->v], 0.0f, 1.0f); + if (data->use_normals) { + float current_normal[3], prev_normal[3]; + sculpt_vertex_normal_get(ss, to_v, current_normal); + sculpt_vertex_normal_get(ss, from_v, prev_normal); + const float from_edge_factor = ss->filter_cache->edge_factor[from_v]; + ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * + from_edge_factor; + ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) * + powf(from_edge_factor, data->edge_sensitivity); + CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f); + } + } + else { + /* PBVH_GRIDS duplicate handling */ + ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v]; + if (data->use_normals) { + ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v]; + ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v]; + } } return true; @@ -9197,10 +9172,6 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent mouse[0] = event->mval[0]; mouse[1] = event->mval[1]; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - sculpt_vertex_random_access_init(ss); op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position"); @@ -9228,6 +9199,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent if (use_normals) { ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count, "mask update normal factor"); + ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count, + "mask update normal factor"); + for (int i = 0; i < vertex_count; i++) { + ss->filter_cache->edge_factor[i] = 1.0f; + } } ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask"); @@ -9266,6 +9242,8 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent ss->filter_cache->normal_factor[i] = avg / ni.size; } } + + MEM_SAFE_FREE(ss->filter_cache->edge_factor); } SculptThreadedTaskData data = { @@ -9277,10 +9255,10 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"), .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); const char *status_str = TIP_( "Move the mouse to expand the mask from the active vertex. LBM: confirm mask, ESC/RMB: " @@ -9594,13 +9572,13 @@ void ED_sculpt_update_modal_transform(struct bContext *C) mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]); } - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range( + BKE_pbvh_parallel_range( 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings); - if (ss->modifiers_active || ss->kb) { + if (ss->deform_modifiers_active || ss->shapekey_active) { sculpt_flush_stroke_deform(sd, ob, true); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index e9af49a0b5a..93e4a777569 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -194,12 +194,9 @@ typedef struct SculptThreadedTaskData { int filter_type; float filter_strength; - int *node_mask; - /* 0=towards view, 1=flipped */ - float (*area_cos)[3]; - float (*area_nos)[3]; - int *count; + bool use_area_cos; + bool use_area_nos; bool any_vertex_sampled; float *prev_mask; @@ -209,13 +206,8 @@ typedef struct SculptThreadedTaskData { float *pose_factor; float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4]; - float tot_pos_avg[3]; - int tot_pos_count; - float max_distance_squared; float nearest_vertex_search_co[3]; - int nearest_vertex_index; - float nearest_vertex_distance_squared; int mask_expand_update_it; bool mask_expand_invert_mask; @@ -418,6 +410,7 @@ typedef struct FilterCache { int mask_update_last_it; int *mask_update_it; float *normal_factor; + float *edge_factor; float *prev_mask; float mask_expand_initial_co[3]; } FilterCache; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 788d07f6e78..5d95cc80280 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -86,6 +86,7 @@ static void update_cb(PBVHNode *node, void *rebuild) struct PartialUpdateData { PBVH *pbvh; bool rebuild; + char *modified_grids; }; /** @@ -94,8 +95,24 @@ struct PartialUpdateData { static void update_cb_partial(PBVHNode *node, void *userdata) { struct PartialUpdateData *data = userdata; - if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) { - update_cb(node, &(data->rebuild)); + if (BKE_pbvh_type(data->pbvh) == PBVH_GRIDS) { + int *node_grid_indices; + int totgrid; + bool update = false; + BKE_pbvh_node_get_grids(data->pbvh, node, &node_grid_indices, &totgrid, NULL, NULL, NULL); + for (int i = 0; i < totgrid; i++) { + if (data->modified_grids[node_grid_indices[i]] == 1) { + update = true; + } + } + if (update) { + update_cb(node, &(data->rebuild)); + } + } + else { + if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) { + update_cb(node, &(data->rebuild)); + } } } @@ -135,7 +152,7 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt if (unode->maxvert) { /* regular mesh restore */ - if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) { + if (ss->shapekey_active && !STREQ(ss->shapekey_active->name, unode->shapeName)) { /* shape key has been changed before calling undo operator */ Key *key = BKE_key_from_object(ob); @@ -157,12 +174,12 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt index = unode->index; mvert = ss->mvert; - if (ss->kb) { + if (ss->shapekey_active) { float(*vertCos)[3]; - vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb); + vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); if (unode->orig_co) { - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]); } @@ -180,36 +197,33 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt } /* propagate new coords to keyblock */ - sculpt_vertcos_to_key(ob, ss->kb, vertCos); + sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos); /* pbvh uses it's own mvert array, so coords should be */ /* propagated to pbvh here */ - BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->kb->totelem); + BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->shapekey_active->totelem); MEM_freeN(vertCos); } else { if (unode->orig_co) { - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { - if (sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co)) { - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; - } + sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; } } else { for (int i = 0; i < unode->totvert; i++) { - if (test_swap_v3_v3(mvert[index[i]].co, unode->orig_co[i])) { - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; - } + swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; } } } else { for (int i = 0; i < unode->totvert; i++) { - if (test_swap_v3_v3(mvert[index[i]].co, unode->co[i])) { - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; - } + swap_v3_v3(mvert[index[i]].co, unode->co[i]); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; } } } @@ -346,9 +360,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range( + BKE_pbvh_parallel_range( 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings); if (nodes) { @@ -485,7 +499,6 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase SculptUndoNode *unode; bool update = false, rebuild = false; bool need_mask = false; - bool partial_update = true; for (unode = lb->first; unode; unode = unode->next) { /* restore pivot */ @@ -527,6 +540,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase return; } + char *undo_modified_grids = NULL; + bool use_multires_undo = false; + for (unode = lb->first; unode; unode = unode->next) { if (!STREQ(unode->idname, ob->id.name)) { @@ -546,8 +562,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase continue; } - /* multi-res can't do partial updates since it doesn't flag edited vertices */ - partial_update = false; + use_multires_undo = true; } switch (unode->type) { @@ -577,21 +592,29 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } } + if (use_multires_undo) { + int max_grid; + unode = lb->first; + max_grid = unode->maxgrid; + undo_modified_grids = MEM_callocN(sizeof(char) * max_grid, "undo_grids"); + for (unode = lb->first; unode; unode = unode->next) { + for (int i = 0; i < unode->totgrid; i++) { + undo_modified_grids[unode->grids[i]] = 1; + } + } + } + if (update || rebuild) { bool tag_update = false; /* we update all nodes still, should be more clever, but also * needs to work correct when exiting/entering sculpt mode and * the nodes get recreated, though in that case it could do all */ - if (partial_update) { - struct PartialUpdateData data = { - .rebuild = rebuild, - .pbvh = ss->pbvh, - }; - BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data); - } - else { - BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); - } + struct PartialUpdateData data = { + .rebuild = rebuild, + .pbvh = ss->pbvh, + .modified_grids = undo_modified_grids, + }; + BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data); BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw); if (BKE_sculpt_multires_active(scene, ob)) { @@ -605,7 +628,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase tag_update |= ((Mesh *)ob->data)->id.us > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d); - if (ss->kb || ss->modifiers_active) { + if (ss->shapekey_active || ss->deform_modifiers_active) { Mesh *mesh = ob->data; BKE_mesh_calc_normals(mesh); @@ -620,6 +643,8 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase sculpt_update_object_bounding_box(ob); } } + + MEM_SAFE_FREE(undo_modified_grids); } static void sculpt_undo_free_list(ListBase *lb) @@ -806,7 +831,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index"); } - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos"); } @@ -828,7 +853,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) normal_float_to_short_v3(unode->no[vd.i], vd.fno); } - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]); } } @@ -1057,8 +1082,8 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType copy_v3_v3(unode->pivot_rot, ss->pivot_rot); /* store active shape key */ - if (ss->kb) { - BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name)); + if (ss->shapekey_active) { + BLI_strncpy(unode->shapeName, ss->shapekey_active->name, sizeof(ss->shapekey_active->name)); } else { unode->shapeName[0] = '\0'; diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 4e710d31cbb..69745663c02 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -273,8 +273,11 @@ static void sound_update_animation_flags(Scene *scene) static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op)) { + Scene *scene = CTX_data_scene(C); + BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false); sound_update_animation_flags(CTX_data_scene(C)); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 4a4ff5f5605..ca6efb5f69e 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -153,7 +153,8 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac, float region_x, float *r_selx, float *r_frame, - bool *r_found) + bool *r_found, + bool *r_is_selected) { *r_found = false; @@ -182,6 +183,7 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac, *r_selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); *r_frame = ak->cfra; *r_found = true; + *r_is_selected = (ak->sel & SELECT) != 0; break; } } @@ -197,14 +199,16 @@ static void actkeys_find_key_at_position(bAnimContext *ac, bAnimListElem **r_ale, float *r_selx, float *r_frame, - bool *r_found) + bool *r_found, + bool *r_is_selected) { *r_found = false; *r_ale = actkeys_find_list_element_at_position(ac, filter, region_x, region_y); if (*r_ale != NULL) { - actkeys_find_key_in_list_element(ac, *r_ale, region_x, r_selx, r_frame, r_found); + actkeys_find_key_in_list_element( + ac, *r_ale, region_x, r_selx, r_frame, r_found, r_is_selected); } } @@ -213,9 +217,11 @@ static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float r bAnimListElem *ale; float selx, frame; bool found; + bool is_selected; int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS; - actkeys_find_key_at_position(ac, filter, region_x, region_y, &ale, &selx, &frame, &found); + actkeys_find_key_at_position( + ac, filter, region_x, region_y, &ale, &selx, &frame, &found, &is_selected); if (ale != NULL) { MEM_freeN(ale); @@ -1681,20 +1687,29 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s /* ------------------- */ -static void mouse_action_keys(bAnimContext *ac, - const int mval[2], - short select_mode, - const bool deselect_all, - const bool column, - const bool same_channel) +static int mouse_action_keys(bAnimContext *ac, + const int mval[2], + short select_mode, + const bool deselect_all, + const bool column, + const bool same_channel, + bool wait_to_deselect_others) { int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS; bAnimListElem *ale = NULL; bool found = false; + bool is_selected = false; float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ float selx = 0.0f; /* frame of keyframe under mouse */ - actkeys_find_key_at_position(ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found); + int ret_value = OPERATOR_FINISHED; + + actkeys_find_key_at_position( + ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found, &is_selected); + + if (select_mode != SELECT_REPLACE) { + wait_to_deselect_others = false; + } /* For replacing selection, if we have something to select, we have to clear existing selection. * The same goes if we found nothing to select, and deselect_all is true @@ -1703,56 +1718,61 @@ static void mouse_action_keys(bAnimContext *ac, /* reset selection mode for next steps */ select_mode = SELECT_ADD; - /* deselect all keyframes */ - deselect_action_keys(ac, 0, SELECT_SUBTRACT); - - /* highlight channel clicked on */ - if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - - /* Highlight Action-Group or F-Curve? */ - if (ale != NULL && ale->data) { - if (ale->type == ANIMTYPE_GROUP) { - bActionGroup *agrp = ale->data; - - agrp->flag |= AGRP_SELECTED; - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); - } - else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { - FCurve *fcu = ale->data; - - fcu->flag |= FCURVE_SELECTED; - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); + if (wait_to_deselect_others && is_selected) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else { + /* deselect all keyframes */ + deselect_action_keys(ac, 0, SELECT_SUBTRACT); + + /* highlight channel clicked on */ + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight Action-Group or F-Curve? */ + if (ale != NULL && ale->data) { + if (ale->type == ANIMTYPE_GROUP) { + bActionGroup *agrp = ale->data; + + agrp->flag |= AGRP_SELECTED; + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + } + else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { + FCurve *fcu = ale->data; + + fcu->flag |= FCURVE_SELECTED; + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); + } } } - } - else if (ac->datatype == ANIMCONT_GPENCIL) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - - /* Highlight GPencil Layer */ - if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) { - bGPdata *gpd = (bGPdata *)ale->id; - bGPDlayer *gpl = ale->data; - - gpl->flag |= GP_LAYER_SELECT; - /* Update other layer status. */ - if (BKE_gpencil_layer_getactive(gpd) != gpl) { - BKE_gpencil_layer_setactive(gpd, gpl); - BKE_gpencil_layer_autolock_set(gpd, false); - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + else if (ac->datatype == ANIMCONT_GPENCIL) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight GPencil Layer */ + if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) { + bGPdata *gpd = (bGPdata *)ale->id; + bGPDlayer *gpl = ale->data; + + gpl->flag |= GP_LAYER_SELECT; + /* Update other layer status. */ + if (BKE_gpencil_layer_getactive(gpd) != gpl) { + BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_autolock_set(gpd, false); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } } } - } - else if (ac->datatype == ANIMCONT_MASK) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + else if (ac->datatype == ANIMCONT_MASK) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) { - MaskLayer *masklay = ale->data; + if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) { + MaskLayer *masklay = ale->data; - masklay->flag |= MASK_LAYERFLAG_SELECT; + masklay->flag |= MASK_LAYERFLAG_SELECT; + } } } } @@ -1787,12 +1807,15 @@ static void mouse_action_keys(bAnimContext *ac, /* free this channel */ MEM_freeN(ale); } + + return ret_value; } /* handle clicking */ -static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int actkeys_clickselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + int ret_value; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) { @@ -1805,20 +1828,26 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent /* select mode is either replace (deselect all, then add) or add/extend */ const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE; const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); + int mval[2]; /* column selection */ const bool column = RNA_boolean_get(op->ptr, "column"); const bool channel = RNA_boolean_get(op->ptr, "channel"); + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + /* select keyframe(s) based upon mouse position*/ - mouse_action_keys(&ac, event->mval, selectmode, deselect_all, column, channel); + ret_value = mouse_action_keys( + &ac, mval, selectmode, deselect_all, column, channel, wait_to_deselect_others); /* set notifier that keyframe selection (and channels too) have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_value | OPERATOR_PASS_THROUGH; } void ACTION_OT_clickselect(wmOperatorType *ot) @@ -1831,13 +1860,16 @@ void ACTION_OT_clickselect(wmOperatorType *ot) ot->description = "Select keyframes by clicking on them"; /* callbacks */ - ot->invoke = actkeys_clickselect_invoke; ot->poll = ED_operator_action_active; + ot->exec = actkeys_clickselect_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; /* flags */ ot->flag = OPTYPE_UNDO; /* properties */ + WM_operator_properties_generic_select(ot); prop = RNA_def_boolean( ot->srna, "extend", diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c index 1d2fc239a89..7e2671382b9 100644 --- a/source/blender/editors/space_clip/tracking_ops_solve.c +++ b/source/blender/editors/space_clip/tracking_ops_solve.c @@ -118,7 +118,11 @@ static void solve_camera_freejob(void *scv) MovieClip *clip = scj->clip; int solved; - WM_set_locked_interface(scj->wm, false); + /* WindowManager is missing in the job when initialization is incomplete. + * In this case the interface is not locked either. */ + if (scj->wm != NULL) { + WM_set_locked_interface(scj->wm, false); + } if (!scj->context) { /* job weren't fully initialized due to some error */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index b4b51de302d..3cdcc07f081 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2395,60 +2395,49 @@ void FILE_OT_filenum(struct wmOperatorType *ot) RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100); } -static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) +static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + const int numfiles = filelist_files_ensure(sfile->files); - if (sfile->params) { - int idx = sfile->params->highlight_file; - int numfiles = filelist_files_ensure(sfile->files); - if ((0 <= idx) && (idx < numfiles)) { - FileDirEntry *file = filelist_file(sfile->files, idx); + if ((file_idx >= 0) && (file_idx < numfiles)) { + FileDirEntry *file = filelist_file(sfile->files, file_idx); + + if ((require_selected == false) || + (filelist_entry_select_get(sfile->files, file, CHECK_ALL) & FILE_SEL_SELECTED)) { filelist_entry_select_index_set( - sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); + sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE); /* We can skip the pending state, * as we can directly set FILE_SEL_EDITING on the expected entry here. */ sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; } + } +} + +static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) +{ + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + + if (sfile->params) { + file_rename_state_activate(sfile, sfile->params->active_file, true); ED_area_tag_redraw(sa); } return OPERATOR_FINISHED; } -static bool file_rename_poll(bContext *C) +static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) { - bool poll = ED_operator_file_active(C); - SpaceFile *sfile = CTX_wm_space_file(C); - - if (sfile && sfile->params) { - int idx = sfile->params->highlight_file; - int numfiles = filelist_files_ensure(sfile->files); - - if ((0 <= idx) && (idx < numfiles)) { - FileDirEntry *file = filelist_file(sfile->files, idx); - if (FILENAME_IS_CURRPAR(file->relpath)) { - poll = false; - } - } + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - if (sfile->params->highlight_file < 0) { - poll = false; - } - else { - char dir[FILE_MAX_LIBEXTRA]; - if (filelist_islibrary(sfile->files, dir, NULL)) { - poll = false; - } - } - } - else { - poll = false; + if (sfile->params) { + file_rename_state_activate(sfile, sfile->params->highlight_file, false); + ED_area_tag_redraw(sa); } - return poll; + return OPERATOR_FINISHED; } void FILE_OT_rename(struct wmOperatorType *ot) @@ -2459,8 +2448,9 @@ void FILE_OT_rename(struct wmOperatorType *ot) ot->idname = "FILE_OT_rename"; /* api callbacks */ + ot->invoke = file_rename_invoke; ot->exec = file_rename_exec; - ot->poll = file_rename_poll; + ot->poll = ED_operator_file_active; } static bool file_delete_poll(bContext *C) @@ -2504,23 +2494,29 @@ int file_delete_exec(bContext *C, wmOperator *op) int numfiles = filelist_files_ensure(sfile->files); int i; + const char *error_message = NULL; bool report_error = false; errno = 0; for (i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { file = filelist_file(sfile->files, i); BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath); - if (BLI_delete(str, false, false) != 0 || BLI_exists(str)) { + if (BLI_delete_soft(str, &error_message) != 0 || BLI_exists(str)) { report_error = true; } } } if (report_error) { - BKE_reportf(op->reports, - RPT_ERROR, - "Could not delete file: %s", - errno ? strerror(errno) : "unknown error"); + if (error_message != NULL) { + BKE_reportf(op->reports, RPT_ERROR, "Could not delete file or directory: %s", error_message); + } + else { + BKE_reportf(op->reports, + RPT_ERROR, + "Could not delete file or directory: %s", + errno ? strerror(errno) : "unknown error"); + } } ED_fileselect_clear(wm, sa, sfile); @@ -2533,7 +2529,7 @@ void FILE_OT_delete(struct wmOperatorType *ot) { /* identifiers */ ot->name = "Delete Selected Files"; - ot->description = "Delete selected files"; + ot->description = "Move selected files to the trash or recycle bin"; ot->idname = "FILE_OT_delete"; /* api callbacks */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 27cccf6bab1..d29233618de 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -831,7 +831,7 @@ void filelist_setfilter_options(FileList *filelist, } if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) { filelist->filter_data.filter = filter; - filelist->filter_data.filter_id = filter_id; + filelist->filter_data.filter_id = (filter & FILE_TYPE_BLENDERLIB) ? filter_id : FILTER_ID_ALL; update = true; } if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) { diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index e2c9bb8d6e5..ba4ccb4fba9 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -247,13 +247,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) } /* For now, always init filterid to 'all true' */ - params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | - FILTER_ID_GD | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | - FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | - FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | - FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | - FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | - FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP; + params->filter_id = FILTER_ID_ALL; if (U.uiflag & USER_HIDE_DOT) { params->flag |= FILE_HIDE_DOT; @@ -362,10 +356,10 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile) /** * Update the user-preference data for the file space. In fact, this also contains some - * non-FileSelectParams data, but it's neglectable. + * non-FileSelectParams data, but we can safely ignore this. * - * \param temp_win_size: If the browser was opened in a temporary window, pass its size here so we - * can store that in the preferences. Otherwise NULL. + * \param temp_win_size: If the browser was opened in a temporary window, + * pass its size here so we can store that in the preferences. Otherwise NULL. */ void ED_fileselect_params_to_userdef(SpaceFile *sfile, int temp_win_size[2]) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 39f7bf001f3..a8dfad85232 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2298,12 +2298,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op) /* get a filename for menu */ BLI_split_dir_part(first_ibuf->name, di, sizeof(di)); - BKE_reportf(op->reports, - RPT_INFO, - tot == 1 ? "%d image will be saved in %s" : - "%d images will be saved in %s", - tot, - di); + BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di); iter = IMB_moviecacheIter_new(image->cache); while (!IMB_moviecacheIter_done(iter)) { diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index c450d5122eb..577c4e24b11 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -70,7 +70,7 @@ static CLG_LogRef LOG = {"ed.image.undo"}; /** \name Thread Locking * \{ */ -/* this is a static resource for non-globality, +/* This is a non-global static resource, * Maybe it should be exposed as part of the * paint operation, but for now just give a public interface */ static SpinLock paint_tiles_lock; @@ -457,6 +457,31 @@ static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf) IMB_freeImBuf(tmpibuf); } +/** Ensure we can copy the ubuf into the ibuf. */ +static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf) +{ + /* We could have both float and rect buffers, + * in this case free the float buffer if it's unused. */ + if ((ibuf->rect_float != NULL) && (ubuf->image_state.use_float == false)) { + imb_freerectfloatImBuf(ibuf); + } + + if (ibuf->x == ubuf->image_dims[0] && ibuf->y == ubuf->image_dims[1] && + (ubuf->image_state.use_float ? (void *)ibuf->rect_float : (void *)ibuf->rect)) { + return; + } + + imb_freerectImbuf_all(ibuf); + IMB_rect_size_set(ibuf, ubuf->image_dims); + + if (ubuf->image_state.use_float) { + imb_addrectfloatImBuf(ibuf); + } + else { + imb_addrectImBuf(ibuf); + } +} + static void ubuf_free(UndoImageBuf *ubuf) { UndoImageBuf *ubuf_post = ubuf->post; @@ -510,7 +535,8 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init) bool changed = false; for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) { UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post; - IMB_rect_size_set(ibuf, ubuf->image_dims); + ubuf_ensure_compat_ibuf(ubuf, ibuf); + int i = 0; for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) { uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS; diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 1abf1a64263..938e7f09881 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -597,13 +597,19 @@ void NLA_OT_select_leftright(wmOperatorType *ot) /* ******************** Mouse-Click Select Operator *********************** */ /* select strip directly under mouse */ -static void mouse_nla_strips( - bContext *C, bAnimContext *ac, const int mval[2], short select_mode, const bool deselect_all) +static int mouse_nla_strips(bContext *C, + bAnimContext *ac, + const int mval[2], + short select_mode, + const bool deselect_all, + bool wait_to_deselect_others) { Scene *scene = ac->scene; bAnimListElem *ale = NULL; NlaStrip *strip = NULL; + int ret_value = OPERATOR_FINISHED; + nlaedit_strip_at_region_position(ac, mval[0], mval[1], &ale, &strip); /* if currently in tweakmode, exit tweakmode before changing selection states @@ -613,6 +619,10 @@ static void mouse_nla_strips( WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL); } + if (select_mode != SELECT_REPLACE) { + wait_to_deselect_others = false; + } + /* For replacing selection, if we have something to select, we have to clear existing selection. * The same goes if we found nothing to select, and deselect_all is true * (deselect on nothing behavior). */ @@ -620,11 +630,16 @@ static void mouse_nla_strips( /* reset selection mode for next steps */ select_mode = SELECT_ADD; - /* deselect all strips */ - deselect_nla_strips(ac, 0, SELECT_SUBTRACT); + if (strip && wait_to_deselect_others && (strip->flag & DESELECT_STRIPS_CLEARACTIVE)) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else { + /* deselect all strips */ + deselect_nla_strips(ac, 0, SELECT_SUBTRACT); - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + } } /* only select strip if we clicked on a valid channel and hit something */ @@ -658,14 +673,17 @@ static void mouse_nla_strips( /* free this channel */ MEM_freeN(ale); } + + return ret_value; } /* ------------------- */ /* handle clicking */ -static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int nlaedit_clickselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + int ret_value; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) { @@ -675,15 +693,19 @@ static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent /* select mode is either replace (deselect all, then add) or add/extend */ const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE; const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); /* select strips based upon mouse position */ - mouse_nla_strips(C, &ac, event->mval, selectmode, deselect_all); + ret_value = mouse_nla_strips(C, &ac, mval, selectmode, deselect_all, wait_to_deselect_others); /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_SELECTED, NULL); /* for tweak grab to work */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_value | OPERATOR_PASS_THROUGH; } void NLA_OT_click_select(wmOperatorType *ot) @@ -695,14 +717,17 @@ void NLA_OT_click_select(wmOperatorType *ot) ot->idname = "NLA_OT_click_select"; ot->description = "Handle clicks to select NLA Strips"; - /* api callbacks - absolutely no exec() this yet... */ - ot->invoke = nlaedit_clickselect_invoke; + /* callbacks */ ot->poll = ED_operator_nla_active; + ot->exec = nlaedit_clickselect_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; /* flags */ ot->flag = OPTYPE_UNDO; /* properties */ + WM_operator_properties_generic_select(ot); prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 3beb12fbb2a..a5b18ff7589 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -47,7 +47,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_state.h" @@ -816,51 +816,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) { - PointerRNA imaptr = RNA_pointer_get(ptr, "image"); PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); - Image *ima = imaptr.data; - - uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, - C, - ptr, - "image", - "IMAGE_OT_new", - "IMAGE_OT_open", - NULL, - UI_TEMPLATE_ID_FILTER_ALL, - false); - - if (!ima) { - return; - } - - uiItemR(layout, &imaptr, "source", 0, IFACE_("Source"), ICON_NONE); - - if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) { - uiLayout *row = uiLayoutRow(layout, true); - const bool is_packed = BKE_image_has_packedfile(ima); - - if (is_packed) { - uiItemO(row, "", ICON_PACKAGE, "image.unpack"); - } - else { - uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack"); - } - - row = uiLayoutRow(row, true); - uiLayoutSetEnabled(row, !is_packed); - uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); - uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); - } - - /* multilayer? */ - if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { - uiTemplateImageLayers(layout, C, ima, iuserptr.data); - } - else if (ima->source != IMA_SRC_GENERATED) { - uiTemplateImageInfo(layout, C, ima, iuserptr.data); - } + uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0); uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); @@ -3890,9 +3847,7 @@ static void nodelink_batch_draw(SpaceNode *snode) void nodelink_batch_start(SpaceNode *UNUSED(snode)) { - /* TODO: partial workaround for NVIDIA driver bug on recent GTX/RTX cards, - * that breaks instancing when using indirect draw-call (see T70011). */ - g_batch_link.enabled = !GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY); + g_batch_link.enabled = true; } void nodelink_batch_end(SpaceNode *snode) diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 08ac84cbb2f..5d020ff5ab4 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -241,6 +241,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) node->flag |= NODE_SELECT; } + bNodeLink *glinks_first = ntree->links.last; + /* Add internal links to the ntree */ for (link = wgroup->links.first; link; link = linkn) { linkn = link->next; @@ -248,6 +250,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) BLI_addtail(&ntree->links, link); } + bNodeLink *glinks_last = ntree->links.last; + /* and copy across the animation, * note that the animation data's action can be NULL here */ if (wgroup->adt) { @@ -280,70 +284,64 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) BKE_id_free(bmain, wgroup); /* restore external links to and from the gnode */ - /* note: the nodes have been copied to intermediate wgroup first (so need to use new_node), - * then transferred to ntree (new_node pointers remain valid). - */ /* input links */ - for (link = ngroup->links.first; link; link = link->next) { - if (link->fromnode->type == NODE_GROUP_INPUT) { - const char *identifier = link->fromsock->identifier; - int num_external_links = 0; - - /* find external links to this input */ - for (tlink = ntree->links.first; tlink; tlink = tlink->next) { - if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { - nodeAddLink(ntree, - tlink->fromnode, - tlink->fromsock, - link->tonode->new_node, - link->tosock->new_sock); - num_external_links++; + if (glinks_first != NULL) { + for (link = glinks_first->next; link != glinks_last->next; link = link->next) { + if (link->fromnode->type == NODE_GROUP_INPUT) { + const char *identifier = link->fromsock->identifier; + int num_external_links = 0; + + /* find external links to this input */ + for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) { + if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { + nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock); + num_external_links++; + } } - } - /* if group output is not externally linked, - * convert the constant input value to ensure somewhat consistent behavior */ - if (num_external_links == 0) { - /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier); - BLI_assert(sock);*/ + /* if group output is not externally linked, + * convert the constant input value to ensure somewhat consistent behavior */ + if (num_external_links == 0) { + /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier); + BLI_assert(sock);*/ - /* XXX TODO - * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, - * ntree, sock, gnode);*/ + /* XXX TODO + * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, + * ntree, sock, gnode);*/ + } } } - } - /* output links */ - for (link = ntree->links.first; link; link = link->next) { - if (link->fromnode == gnode) { - const char *identifier = link->fromsock->identifier; - int num_internal_links = 0; - - /* find internal links to this output */ - for (tlink = ngroup->links.first; tlink; tlink = tlink->next) { - /* only use active output node */ - if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) { - if (STREQ(tlink->tosock->identifier, identifier)) { - nodeAddLink(ntree, - tlink->fromnode->new_node, - tlink->fromsock->new_sock, - link->tonode, - link->tosock); - num_internal_links++; + /* Also iterate over new links to cover passthrough links. */ + glinks_last = ntree->links.last; + + /* output links */ + for (link = ntree->links.first; link != glinks_first->next; link = link->next) { + if (link->fromnode == gnode) { + const char *identifier = link->fromsock->identifier; + int num_internal_links = 0; + + /* find internal links to this output */ + for (tlink = glinks_first->next; tlink != glinks_last->next; tlink = tlink->next) { + /* only use active output node */ + if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) { + if (STREQ(tlink->tosock->identifier, identifier)) { + nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock); + num_internal_links++; + } } } - } - /* if group output is not internally linked, - * convert the constant output value to ensure somewhat consistent behavior */ - if (num_internal_links == 0) { - /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier); - BLI_assert(sock);*/ + /* if group output is not internally linked, + * convert the constant output value to ensure somewhat consistent behavior */ + if (num_internal_links == 0) { + /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier); + BLI_assert(sock);*/ - /* XXX TODO - * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */ + /* XXX TODO + * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */ + } } } } @@ -893,7 +891,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, } } if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) { - skip = true; + skip = true; } if (skip) { continue; @@ -917,7 +915,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, } } if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) { - skip = true; + skip = true; } if (skip) { continue; diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index b66cd0d3069..e22ef389516 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -557,100 +557,40 @@ static int node_mouse_select(bContext *C, static int node_select_exec(bContext *C, wmOperator *op) { + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); + /* get settings from RNA properties for operator */ int mval[2]; mval[0] = RNA_int_get(op->ptr, "mouse_x"); mval[1] = RNA_int_get(op->ptr, "mouse_y"); /* perform the select */ - const int ret_value = node_mouse_select(C, op, mval, false); + const int ret_value = node_mouse_select(C, op, mval, wait_to_deselect_others); /* allow tweak event to work too */ return ret_value | OPERATOR_PASS_THROUGH; } -static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - const short init_event_type = (short)POINTER_AS_INT(op->customdata); - - /* get settings from RNA properties for operator */ - int mval[2]; - mval[0] = RNA_int_get(op->ptr, "mouse_x"); - mval[1] = RNA_int_get(op->ptr, "mouse_y"); - - if (init_event_type == 0) { - if (event->val == KM_PRESS) { - const int ret_value = node_mouse_select(C, op, mval, true); - - op->customdata = POINTER_FROM_INT((int)event->type); - if (ret_value & OPERATOR_RUNNING_MODAL) { - WM_event_add_modal_handler(C, op); - } - return ret_value | OPERATOR_PASS_THROUGH; - } - else { - /* If we are in init phase, and cannot validate init of modal operations, - * just fall back to basic exec. - */ - const int ret_value = node_mouse_select(C, op, mval, false); - return ret_value | OPERATOR_PASS_THROUGH; - } - } - else if (event->type == init_event_type && event->val == KM_RELEASE) { - const int ret_value = node_mouse_select(C, op, mval, false); - return ret_value | OPERATOR_PASS_THROUGH; - } - else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - const int drag_delta[2] = { - mval[0] - event->mval[0], - mval[1] - event->mval[1], - }; - /* If user moves mouse more than defined threshold, we consider select operator as - * finished. Otherwise, it is still running until we get an 'release' event. In any - * case, we pass through event, but select op is not finished yet. */ - if (WM_event_drag_test_with_delta(event, drag_delta)) { - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; - } - else { - /* Important not to return anything other than PASS_THROUGH here, - * otherwise it prevents underlying tweak detection code to work properly. */ - return OPERATOR_PASS_THROUGH; - } - } - - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; -} - -static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - RNA_int_set(op->ptr, "mouse_x", event->mval[0]); - RNA_int_set(op->ptr, "mouse_y", event->mval[1]); - - op->customdata = POINTER_FROM_INT(0); - - return node_select_modal(C, op, event); -} - void NODE_OT_select(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Select"; ot->idname = "NODE_OT_select"; ot->description = "Select the node under the cursor"; /* api callbacks */ - ot->invoke = node_select_invoke; ot->exec = node_select_exec; - ot->modal = node_select_modal; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; ot->poll = ED_operator_node_active; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - PropertyRNA *prop; - RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX); + WM_operator_properties_generic_select(ot); RNA_def_boolean(ot->srna, "extend", false, "Extend", ""); RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", ""); prop = RNA_def_boolean(ot->srna, diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 309446db83b..03606282fcd 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -965,7 +965,7 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); if (extend) { - BKE_layer_collection_isolate(scene, view_layer, layer_collection, true); + BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true); } else { PointerRNA ptr; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index a2ca3254b30..3b86e04308e 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2419,7 +2419,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case OB_GPENCIL: data.icon = ICON_OUTLINER_OB_GREASEPENCIL; break; - break; } } else { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index c81d292a859..c55140db46f 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -770,11 +770,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); BKE_copybuffer_save(bmain, str, op->reports); - BKE_reportf(op->reports, - RPT_INFO, - num_ids == 1 ? "Copied %d selected data-block" : - "Copied %d selected data-blocks", - num_ids); + BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids); return OPERATOR_FINISHED; } @@ -808,11 +804,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_WINDOW, NULL); - BKE_reportf(op->reports, - RPT_INFO, - num_pasted == 1 ? "%d data-block pasted" : - "%d data-blocks pasted", - num_pasted); + BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted); return OPERATOR_FINISHED; } @@ -2265,11 +2257,7 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op) BKE_id_multi_tagged_delete(bmain); - BKE_reportf(op->reports, - RPT_INFO, - num_tagged[INDEX_ID_NULL] == 1 ? "Deleted %d data-block" : - "Deleted %d data-blocks", - num_tagged[INDEX_ID_NULL]); + BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-block(s)", num_tagged[INDEX_ID_NULL]); /* XXX: tree management normally happens from draw_outliner(), but when * you're clicking to fast on Delete object from context menu in diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 44e67fa1508..f1e884adc3d 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -263,7 +263,8 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer, for (base = FIRSTBASE(view_layer); base; base = base->next) { Object *ob = base->object; - if ((((base->flag & BASE_VISIBLE) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) { + if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) && + BKE_object_is_child_recursive(ob_parent, ob))) { ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); } } @@ -1198,7 +1199,7 @@ static void do_outliner_item_activate_tree_element(bContext *C, Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); if ((ob != NULL) && (ob->data == tselem->id)) { Base *base = BKE_view_layer_base_find(view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE)) { + if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { do_outliner_activate_obdata(C, scene, view_layer, base, extend); } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index fd6a052b84d..7f7cfff12ef 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1365,7 +1365,7 @@ static void outliner_add_layer_collection_objects( TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0); te_object->directdata = base; - if (!(base->flag & BASE_VISIBLE)) { + if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) { te_object->flag |= TE_DISABLED; } } @@ -1398,7 +1398,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops, tselem->flag &= ~TSE_CLOSED; } - if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) { + if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER) == 0) { ten->flag |= TE_DISABLED; } } @@ -2085,12 +2085,12 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, } if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) { - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return false; } } else if (exclude_filter & SO_FILTER_OB_STATE_HIDDEN) { - if ((base->flag & BASE_VISIBLE) != 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) { return false; } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 9d7163cd6d9..865dfb45278 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1600,6 +1600,7 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op) if (success) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); return OPERATOR_FINISHED; } else { @@ -1693,6 +1694,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even if (sa) { ED_area_status_text(sa, NULL); } + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index affb6d3fd88..4c20fc1707a 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -319,7 +319,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int sequencer_select_exec(bContext *C, wmOperator *op) { View2D *v2d = UI_view2d_fromcontext(C); Scene *scene = CTX_data_scene(C); @@ -328,7 +328,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle"); const bool linked_time = RNA_boolean_get(op->ptr, "linked_time"); + bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); int left_right = RNA_enum_get(op->ptr, "left_right"); + int mval[2]; + int ret_value = OPERATOR_CANCELLED; + + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); Sequence *seq, *neighbor, *act_orig; int hand, sel_side; @@ -338,9 +344,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e return OPERATOR_CANCELLED; } + if (extend) { + wait_to_deselect_others = false; + } + marker = find_nearest_marker(SCE_MARKERS, 1); // XXX - dummy function for now - seq = find_nearest_seq(scene, v2d, &hand, event->mval); + seq = find_nearest_seq(scene, v2d, &hand, mval); // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) { @@ -364,6 +374,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e /* deselect_markers(0, 0); */ marker->flag |= SELECT; } + + ret_value = OPERATOR_FINISHED; } else if (left_right != SEQ_SELECT_LR_NONE) { /* use different logic for this */ @@ -374,7 +386,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e switch (left_right) { case SEQ_SELECT_LR_MOUSE: - x = UI_view2d_region_to_view_x(v2d, event->mval[0]); + x = UI_view2d_region_to_view_x(v2d, mval[0]); break; case SEQ_SELECT_LR_LEFT: x = CFRA - 1.0f; @@ -409,13 +421,27 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e } } } + + ret_value = OPERATOR_FINISHED; } else { act_orig = ed->act_seq; if (seq) { - if (!extend && !linked_handle) { + /* Are we trying to select a handle that's already selected? */ + const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) || + ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL)); + + if (wait_to_deselect_others && (seq->flag & SELECT) && + (hand == SEQ_SIDE_NONE || handle_selected)) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else if (!extend && !linked_handle) { ED_sequencer_deselect_all(scene); + ret_value = OPERATOR_FINISHED; + } + else { + ret_value = OPERATOR_FINISHED; } BKE_sequencer_active_set(scene, seq); @@ -509,6 +535,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp); } } + + ret_value = OPERATOR_FINISHED; } else { if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) { @@ -525,6 +553,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e seq->flag ^= SEQ_RIGHTSEL; break; } + ret_value = OPERATOR_FINISHED; } else { seq->flag |= SELECT; @@ -542,9 +571,12 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e if (linked_time) { select_linked_time(ed->seqbasep, seq); } + + BLI_assert((ret_value & OPERATOR_CANCELLED) == 0); } else if (deselect_all) { ED_sequencer_deselect_all(scene); + ret_value = OPERATOR_FINISHED; } } @@ -552,8 +584,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene); - /* allowing tweaks */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_value; } void SEQUENCER_OT_select(wmOperatorType *ot) @@ -565,6 +596,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot) {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"}, {0, NULL, 0, NULL, NULL}, }; + PropertyRNA *prop; /* identifiers */ ot->name = "Select"; @@ -572,14 +604,16 @@ void SEQUENCER_OT_select(wmOperatorType *ot) ot->description = "Select a strip (last selected becomes the \"active strip\")"; /* api callbacks */ - ot->invoke = sequencer_select_invoke; + ot->exec = sequencer_select_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; ot->poll = ED_operator_sequencer_active; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - PropertyRNA *prop; + WM_operator_properties_generic_select(ot); RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); prop = RNA_def_boolean(ot->srna, "deselect_all", diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c index 347d46a4234..935e288c7be 100644 --- a/source/blender/editors/space_text/text_format_lua.c +++ b/source/blender/editors/space_text/text_format_lua.c @@ -48,7 +48,7 @@ static int txtfmt_lua_find_keyword(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len; @@ -66,8 +66,7 @@ static int txtfmt_lua_find_keyword(const char *string) } else if (STR_LITERAL_STARTSWITH(string, "then", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "until", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len; - } else { i = 0; -} + } else { i = 0; } /* clang-format on */ @@ -96,7 +95,7 @@ static int txtfmt_lua_find_specialvar(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "collectgarbage", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "dofile", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "error", len)) { i = len; @@ -124,8 +123,7 @@ static int txtfmt_lua_find_specialvar(const char *string) } else if (STR_LITERAL_STARTSWITH(string, "unpack", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "_VERSION", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "xpcall", len)) { i = len; - } else { i = 0; -} + } else { i = 0; } /* clang-format on */ @@ -140,18 +138,13 @@ static int txtfmt_lua_find_bool(const char *string) { int i, len; - if (STR_LITERAL_STARTSWITH(string, "nil", len)) { - i = len; - } - else if (STR_LITERAL_STARTSWITH(string, "true", len)) { - i = len; - } - else if (STR_LITERAL_STARTSWITH(string, "false", len)) { - i = len; - } - else { - i = 0; - } + /* Keep aligned args for readability. */ + /* clang-format off */ + + if (STR_LITERAL_STARTSWITH(string, "nil", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; + } else { i = 0; } /* clang-format on */ @@ -169,10 +162,9 @@ static char txtfmt_lua_format_identifier(const char *str) /* Keep aligned args for readability. */ /* clang-format off */ - if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; + if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; } else if ((txtfmt_lua_find_keyword(str)) != -1) { fmt = FMT_TYPE_KEYWORD; - } else { fmt = FMT_TYPE_DEFAULT; -} + } else { fmt = FMT_TYPE_DEFAULT; } /* clang-format on */ diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c index fb9ddcb09cb..2da4488e901 100644 --- a/source/blender/editors/space_text/text_format_osl.c +++ b/source/blender/editors/space_text/text_format_osl.c @@ -40,7 +40,7 @@ static int txtfmt_osl_find_builtinfunc(const char *string) /* list is from * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf */ - if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "closure", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "color", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len; @@ -86,7 +86,7 @@ static int txtfmt_osl_find_reserved(const char *string) /* list is from... * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf */ - if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "catch", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "char", len)) { i = len; @@ -149,7 +149,7 @@ static int txtfmt_osl_find_specialvar(const char *string) /* clang-format off */ /* OSL shader types */ - if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "surface", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "volume", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) { i = len; @@ -189,7 +189,7 @@ static char txtfmt_osl_format_identifier(const char *str) /* Keep aligned args for readability. */ /* clang-format off */ - if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; + if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; } else if ((txtfmt_osl_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD; } else if ((txtfmt_osl_find_reserved(str)) != -1) { fmt = FMT_TYPE_RESERVED; } else if ((txtfmt_osl_find_preprocessor(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE; @@ -323,7 +323,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_ /* Special vars(v) or built-in keywords(b) */ /* keep in sync with 'txtfmt_osl_format_identifier()' */ - if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL; + if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL; } else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD; } else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED; } else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) { prev = FMT_TYPE_DIRECTIVE; diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c index a5e1a3845cf..21df7b5b76a 100644 --- a/source/blender/editors/space_text/text_format_pov.c +++ b/source/blender/editors/space_text/text_format_pov.c @@ -48,7 +48,7 @@ static int txtfmt_pov_find_keyword(const char *string) int i, len; /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "persistent", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "version", len)) { i = len; @@ -101,7 +101,7 @@ static int txtfmt_pov_find_reserved_keywords(const char *string) /* clang-format off */ /* Float Functions */ - if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) { i = len; @@ -261,7 +261,7 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) /* clang-format off */ /* Language Keywords */ - if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) { i = len; @@ -500,7 +500,7 @@ static int txtfmt_pov_find_specialvar(const char *string) { int i, len; /* Modifiers */ - if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) { i = len; @@ -710,7 +710,7 @@ static int txtfmt_pov_find_bool(const char *string) /* clang-format off */ /* Built-in Constants */ - if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len; diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c index 04f4b992cc6..b349b38e551 100644 --- a/source/blender/editors/space_text/text_format_pov_ini.c +++ b/source/blender/editors/space_text/text_format_pov_ini.c @@ -49,7 +49,7 @@ static int txtfmt_ini_find_keyword(const char *string) /* clang-format off */ /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "declare", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "default", len)) { i = len; @@ -111,7 +111,7 @@ static int txtfmt_ini_find_reserved(const char *string) * list is from... * http://www.povray.org/documentation/view/3.7.0/212/ */ - if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) { i = len; @@ -321,7 +321,7 @@ static int txtfmt_ini_find_bool(const char *string) /* clang-format off */ /* Built-in Constants */ - if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len; diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 98eeee61c3a..d84beb79be6 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -58,11 +58,11 @@ static int txtfmt_py_find_builtinfunc(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; - } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len; - } else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "del", len)) { i = len; @@ -114,7 +114,7 @@ static int txtfmt_py_find_specialvar(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "class", len)) { i = len; } else { i = 0; } @@ -155,7 +155,7 @@ static int txtfmt_py_find_bool(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "True", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "False", len)) { i = len; } else { i = 0; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fbb6dfb8f8f..8b02a52d7f9 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -341,6 +341,9 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) v3dn->runtime.properties_storage = NULL; } + v3dn->local_collections_uuid = 0; + v3dn->flag &= ~V3D_LOCAL_COLLECTIONS; + if (v3dn->shading.type == OB_RENDER) { v3dn->shading.type = OB_SOLID; } @@ -1096,6 +1099,9 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win), if (wmn->data & ND_GPENCIL_EDITMODE) { ED_region_tag_redraw(ar); } + else if (wmn->action == NA_EDITED) { + ED_region_tag_redraw(ar); + } break; case NC_BRUSH: ED_region_tag_redraw(ar); @@ -1460,7 +1466,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if (view_layer->basact) { Object *ob = view_layer->basact->object; /* if hidden but in edit mode, we still display, can happen with animation */ - if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT)) { + if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 || (ob->mode & OB_MODE_EDIT)) { CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact); } } @@ -1472,7 +1478,8 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if (view_layer->basact) { Object *ob = view_layer->basact->object; /* if hidden but in edit mode, we still display, can happen with animation */ - if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT) != 0) { + if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 || + (ob->mode & OB_MODE_EDIT) != 0) { CTX_data_id_pointer_set(result, &ob->id); } } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index aafd36a5bb8..3ee9755cb06 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1422,18 +1422,24 @@ static void draw_grid_unit_name( { if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) { const char *grid_unit = NULL; + int font_id = BLF_default(); ED_view3d_grid_view_scale(scene, v3d, rv3d, &grid_unit); if (grid_unit) { char numstr[32] = ""; - UI_FontThemeColor(BLF_default(), TH_TEXT_HI); + UI_FontThemeColor(font_id, TH_TEXT_HI); if (v3d->grid != 1.0f) { BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); } *yoffset -= U.widget_unit; + BLF_enable(font_id, BLF_SHADOW); + BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); + BLF_shadow_offset(font_id, 1, -1); BLF_draw_default_ascii( xoffset, *yoffset, 0.0f, numstr[0] ? numstr : grid_unit, sizeof(numstr)); + + BLF_disable(font_id, BLF_SHADOW); } } } diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index acc46935eb5..17b575cedae 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -179,7 +179,7 @@ static void validate_object_select_id( return; } - if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) { + if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) { Base *base = BKE_view_layer_base_find(view_layer, obact); DRW_select_buffer_context_create(&base, 1, -1); } @@ -226,7 +226,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc) ARegion *ar = vc->ar; Object *obact_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact); - if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) { + if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) { GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0); DRW_draw_depth_object(vc->ar, viewport, obact_eval); } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c index 615589347da..dbad06da5ec 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -25,6 +25,7 @@ #include "BKE_armature.h" #include "BKE_action.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c index 42931d5abb5..ba5ca5fbd15 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -24,6 +24,7 @@ #include "BKE_camera.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "DNA_object_types.h" #include "DNA_camera_types.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c index b37f1e41294..793aec42dcd 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_empty.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c @@ -22,6 +22,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "BKE_image.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c index 44ad1d14dba..90b1539c8a7 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c @@ -21,6 +21,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_light.c b/source/blender/editors/space_view3d/view3d_gizmo_light.c index 35677b2e4c2..890de0ae611 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_light.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_light.c @@ -22,6 +22,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 5625333d837..a5b7fac624d 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -407,6 +407,17 @@ static bool view3d_ruler_item_mousemove(RulerInfo *ruler_info, /** \name Ruler/Grease Pencil Conversion * \{ */ +/* Helper: Find the layer created as ruler. */ +static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd) +{ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->flag & GP_LAYER_IS_RULER) { + return gpl; + } + } + return NULL; +} + #define RULER_ID "RulerData3D" static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) { @@ -427,12 +438,12 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) } gpd = scene->gpd; - gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + gpl = view3d_ruler_layer_get(gpd); if (gpl == NULL) { gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false); copy_v4_v4(gpl->color, U.gpencil_new_layer_col); gpl->thickness = 1; - gpl->flag |= GP_LAYER_HIDE; + gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER; } gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); @@ -485,8 +496,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup) if (scene->gpd) { bGPDlayer *gpl; - const char *ruler_name = RULER_ID; - gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + gpl = view3d_ruler_layer_get(scene->gpd); if (gpl) { bGPDframe *gpf; gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 37eea6b03d7..cfdd3dcbb6f 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -79,11 +79,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); BKE_copybuffer_save(bmain, str, op->reports); - BKE_reportf(op->reports, - RPT_INFO, - num_copied == 1 ? "Copied %d selected object" : - "Copied %d selected objects", - num_copied); + BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied); return OPERATOR_FINISHED; } @@ -122,11 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_WINDOW, NULL); - BKE_reportf(op->reports, - RPT_INFO, - num_pasted == 1 ? "%d object pasted" : - "%d objects pasted", - num_pasted); + BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 198b5d05540..3eee76277e8 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1020,10 +1020,12 @@ static void do_lasso_select_armature__doSelectBone(void *userData, is_ignore_flag |= BONESEL_TIP; } - if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) || - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { - is_inside_flag |= BONESEL_BONE; + if (is_ignore_flag == 0) { + if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) || + BLI_lasso_is_edge_inside( + data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { + is_inside_flag |= BONESEL_BONE; + } } ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index dd8e2e07271..d7af307bc53 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1583,7 +1583,13 @@ static uint free_localcollection_bit(Main *bmain, static void local_collections_reset_uuid(LayerCollection *layer_collection, const unsigned short local_view_bit) { - layer_collection->local_collections_bits |= local_view_bit; + if (layer_collection->flag & LAYER_COLLECTION_HIDE) { + layer_collection->local_collections_bits &= ~local_view_bit; + } + else { + layer_collection->local_collections_bits |= local_view_bit; + } + LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) { local_collections_reset_uuid(child, local_view_bit); } diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index ac9ad30d719..a7402a622d5 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -204,6 +204,8 @@ typedef struct WalkInfo { * (this would need to un-key all previous frames). */ bool anim_playing; + bool need_rotation_keyframe; + bool need_translation_keyframe; /** Previous 2D mouse values. */ int prev_mval[2]; @@ -538,6 +540,8 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) #endif walk->anim_playing = ED_screen_animation_playing(wm); + walk->need_rotation_keyframe = false; + walk->need_translation_keyframe = false; walk->time_lastdraw = PIL_check_seconds_timer(); @@ -930,9 +934,12 @@ static void walkMoveCamera(bContext *C, /* we only consider autokeying on playback or if user confirmed walk on the same frame * otherwise we get a keyframe even if the user cancels. */ const bool use_autokey = is_confirm || walk->anim_playing; - ED_view3d_cameracontrol_update( walk->v3d_camera_control, use_autokey, C, do_rotate, do_translate); + if (use_autokey) { + walk->need_rotation_keyframe = false; + walk->need_translation_keyframe = false; + } } static float getFreeFallDistance(const float gravity, const float time) @@ -1280,9 +1287,10 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) add_v3_v3(rv3d->ofs, dvec_tmp); if (rv3d->persp == RV3D_CAMOB) { - const bool do_rotate = (moffset[0] || moffset[1]); - const bool do_translate = (walk->speed != 0.0f); - walkMoveCamera(C, walk, do_rotate, do_translate, is_confirm); + walk->need_rotation_keyframe |= (moffset[0] || moffset[1]); + walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON); + walkMoveCamera( + C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm); } } else { @@ -1322,7 +1330,10 @@ static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm) walk->redraw = true; if (walk->rv3d->persp == RV3D_CAMOB) { - walkMoveCamera(C, walk, has_rotate, has_translate, is_confirm); + walk->need_rotation_keyframe |= has_rotate; + walk->need_translation_keyframe |= has_translate; + walkMoveCamera( + C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm); } } } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 67ea0f255fc..b98c14150d5 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -2346,9 +2346,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } - Object *ob = CTX_data_active_object(C); - if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) { - options |= CTX_SCULPT; + if (CTX_wm_view3d(C) != NULL) { + Object *ob = CTX_data_active_object(C); + if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) { + options |= CTX_SCULPT; + } } t->options = options; diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 5862faaf667..64ad8b2091e 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -429,7 +429,7 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) bone->flag |= BONE_TRANSFORM_CHILD; } else { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; } bone_children_clear_transflag(mode, around, &bone->childbase); @@ -455,14 +455,14 @@ int count_set_pose_transflags(Object *ob, bone->flag |= BONE_TRANSFORM; } else { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; } bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM; bone->flag &= ~BONE_TRANSFORM_CHILD; } else { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; } } @@ -1542,8 +1542,8 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t } for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) { - + if ((pchan->bone->flag & BONE_TRANSFORM) || + ((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) { ListBase dsources = {NULL, NULL}; /* clear any 'unkeyed' flag it may have */ diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 7f9c4ee2fcc..f1928433491 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1451,7 +1451,7 @@ void createTransUVs(bContext *C, TransInfo *t) const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0; elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true); if (elementmap == NULL) { - return; + continue; } if (is_prop_connected) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 53e36f86a64..2e4f4344481 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -794,6 +794,12 @@ static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid) for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; pchan_orig = pchan_orig->next) { + /* Clear the MIRROR flag from previous runs */ + pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR; + } + + for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; + pchan_orig = pchan_orig->next) { /* no layer check, correct mirror is more important */ if (pchan_orig->bone->flag & BONE_TRANSFORM) { bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); @@ -1707,7 +1713,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } else { - if (ISMOUSE(t->launch_event) && (U.flag & USER_RELEASECONFIRM)) { + /* Release confirms preference should not affect node editor (T69288, T70504). */ + if (ISMOUSE(t->launch_event) && + ((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) { /* Global "release confirm" on mouse bindings */ t->flag |= T_RELEASE_CONFIRM; } @@ -1832,7 +1840,7 @@ static void freeTransCustomData(TransInfo *t, TransDataContainer *tc, TransCusto custom_data->data = NULL; } /* In case modes are switched in the same transform session. */ - custom_data->free_cb = false; + custom_data->free_cb = NULL; custom_data->use_free = false; } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 65fd9c6f5e9..157cf96a85e 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -516,9 +516,15 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags) } /* for pose mode */ -static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan) +static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, + const bPoseChannel *pchan, + short orientation_type) { - protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); + /* Protect-flags apply to local space in pose mode, so only let them influence axis + * visibility if we show the global orientation, otherwise it's confusing. */ + if (orientation_type == V3D_ORIENT_LOCAL) { + protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); + } } /* for editmode*/ @@ -742,7 +748,14 @@ int ED_transform_calc_gizmo_stats(const bContext *C, bGPdata *gpd = CTX_data_gpencil_data(C); const bool is_gp_edit = GPENCIL_ANY_MODE(gpd); int a, totsel = 0; + const int pivot_point = scene->toolsettings->transform_pivot_point; + const short orientation_type = params->orientation_type ? + (params->orientation_type - 1) : + scene->orientation_slots[SCE_ORIENT_DEFAULT].type; + const short orientation_index_custom = + params->orientation_type ? params->orientation_index_custom : + scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; /* transform widget matrix */ unit_m4(rv3d->twmat); @@ -756,12 +769,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* global, local or normal orientation? * if we could check 'totsel' now, this should be skipped with no selection. */ if (ob) { - const short orientation_type = params->orientation_type ? - (params->orientation_type - 1) : - scene->orientation_slots[SCE_ORIENT_DEFAULT].type; - const short orientation_index_custom = - params->orientation_type ? params->orientation_index_custom : - scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; float mat[3][3]; ED_transform_calc_orientation_from_type_ex( C, mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); @@ -888,7 +895,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, calc_tw_center_with_matrix(tbounds, ebo->head, use_mat_local, mat_local); totsel++; } - if (ebo->flag & BONE_SELECTED) { + if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) { protectflag_to_drawflags_ebone(rv3d, ebo); } } @@ -1038,7 +1045,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, Bone *bone = pchan->bone; if (bone && (bone->flag & BONE_TRANSFORM)) { calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local); - protectflag_to_drawflags_pchan(rv3d, pchan); + protectflag_to_drawflags_pchan(rv3d, pchan, orientation_type); } } totsel += totsel_iter; @@ -1122,7 +1129,12 @@ int ED_transform_calc_gizmo_stats(const bContext *C, calc_tw_center(tbounds, co); } } - protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); + + /* Protect-flags apply to world space in object mode, so only let them influence axis + * visibility if we show the global orientation, otherwise it's confusing. */ + if (orientation_type == V3D_ORIENT_GLOBAL) { + protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); + } totsel++; } @@ -1338,6 +1350,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, } WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_gz_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh); } void drawDial3d(const TransInfo *t) diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index cbe9505d3f2..3159464072e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -44,6 +44,7 @@ #include "BKE_curve.h" #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_workspace.h" diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 1601acb1c8f..f35a2808f22 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -47,6 +47,7 @@ #include "BKE_object.h" #include "BKE_anim.h" /* for duplis */ #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_tracking.h" #include "BKE_context.h" @@ -2367,6 +2368,7 @@ static short snapEditMesh(SnapObjectContext *sctx, if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { BM_mesh_elem_table_ensure(em->bm, BM_VERT); + BM_mesh_elem_index_ensure(em->bm, BM_VERT); BLI_bvhtree_find_nearest_projected(treedata_vert->tree, lpmat, snapdata->win_size, @@ -2382,6 +2384,7 @@ static short snapEditMesh(SnapObjectContext *sctx, int last_index = nearest.index; nearest.index = -1; BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT); + BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT); BLI_bvhtree_find_nearest_projected(treedata_edge->tree, lpmat, snapdata->win_size, diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h index f4fd2b132e8..263b5429161 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.h +++ b/source/blender/freestyle/intern/stroke/Stroke.h @@ -590,7 +590,8 @@ class Stroke : public Interface1D { /*! Resampling method. * Resamples the curve so that it eventually has iNPoints. That means it is going to add * iNPoints-vertices_size, if vertices_size is the number of points we already have. If - * vertices_size >= iNPoints, no resampling is done. \param iNPoints: The number of vertices we + * vertices_size >= iNPoints, no resampling is done. + * \param iNPoints: The number of vertices we * eventually want in our stroke. */ int Resample(int iNPoints); @@ -840,8 +841,10 @@ class Stroke : public Interface1D { vertex_iterator vertices_end(); /*! Returns a StrokeVertexIterator pointing on the first StrokeVertex of the Stroke. One can - * specify a sampling value to resample the Stroke on the fly if needed. \param t: The resampling - * value with which we want our Stroke to be resampled. If 0 is specified, no resampling is done. + * specify a sampling value to resample the Stroke on the fly if needed. + * + * \param t: The resampling value with which we want our Stroke to be resampled. + * If 0 is specified, no resampling is done. */ StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t = 0.0f); diff --git a/source/blender/freestyle/intern/view_map/Interface1D.h b/source/blender/freestyle/intern/view_map/Interface1D.h index 7a72a176902..ab489bff4c9 100644 --- a/source/blender/freestyle/intern/view_map/Interface1D.h +++ b/source/blender/freestyle/intern/view_map/Interface1D.h @@ -156,15 +156,17 @@ class Interface1D { /*! Returns an iterator over the Interface1D points, pointing to the first point. The difference * with verticesBegin() is that here we can iterate over points of the 1D element at a any given - * sampling. Indeed, for each iteration, a virtual point is created. \param t: The sampling with - * which we want to iterate over points of this 1D element. + * sampling. Indeed, for each iteration, a virtual point is created. + * + * \param t: The sampling with which we want to iterate over points of this 1D element. */ virtual Interface0DIterator pointsBegin(float t = 0.0f); /*! Returns an iterator over the Interface1D points, pointing after the last point. The * difference with verticesEnd() is that here we can iterate over points of the 1D element at a - * any given sampling. Indeed, for each iteration, a virtual point is created. \param t: The - * sampling with which we want to iterate over points of this 1D element. + * any given sampling. Indeed, for each iteration, a virtual point is created. + * + * \param t: The sampling with which we want to iterate over points of this 1D element. */ virtual Interface0DIterator pointsEnd(float t = 0.0f); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index 1f2f0554dd5..27c8175af3f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -203,5 +203,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Armature = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index c311497ffbb..bb70b548675 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -317,14 +317,6 @@ static void foreachObjectLink(GpencilModifierData *md, walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } -static int getDuplicationFactor(GpencilModifierData *md) -{ - ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md; - int t = mmd->count; - CLAMP_MIN(t, 1); - return t; -} - GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* name */ "Array", /* structName */ "ArrayGpencilModifierData", @@ -347,5 +339,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index d72ace7a191..e3e7168330d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -550,5 +550,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index cb429b874a2..cbe2d9a4c4f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -168,5 +168,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index 234b4deeceb..bc62d0d69bb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -357,5 +357,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 6b74f96ce31..9dbf7b35bc5 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -219,5 +219,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index e391adde829..ef06e14b3d7 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -203,21 +203,6 @@ static void foreachObjectLink(GpencilModifierData *md, walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } -static int getDuplicationFactor(GpencilModifierData *md) -{ - MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; - int factor = 1; - /* create a duplication for each axis */ - for (int xi = 0; xi < 3; xi++) { - if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) { - factor++; - } - } - CLAMP_MIN(factor, 1); - - return factor; -} - GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* name */ "Mirror", /* structName */ "MirrorGpencilModifierData", @@ -240,5 +225,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index b286b55829e..f34477aaab2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -274,5 +274,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 08f67eedc86..70d463fff76 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -148,5 +148,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index 22610771045..c0892a1d91a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -206,5 +206,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index 25a56c4385c..9594fc8581e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -144,5 +144,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index 5ec7fe4ff18..68060711681 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -155,5 +155,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index ce75ca59fe1..89d6565d0dd 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -67,7 +67,7 @@ static void deformStroke(GpencilModifierData *md, /* It makes sense when adding points to a straight line */ /* e.g. for creating thickness variation in later modifiers. */ - const int minimum_vert = (mmd->flag | GP_SUBDIV_SIMPLE) ? 2 : 3; + const int minimum_vert = (mmd->flag & GP_SUBDIV_SIMPLE) ? 2 : 3; if (!is_stroke_affected_by_modifier(ob, mmd->layername, @@ -103,14 +103,6 @@ static void bakeModifier(struct Main *UNUSED(bmain), } } -static int getDuplicationFactor(GpencilModifierData *md) -{ - SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md; - int t = (mmd->level + 1) * (mmd->level + 1); - CLAMP_MIN(t, 2); - return t; -} - GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* name */ "Subdivision", /* structName */ "SubdivGpencilModifierData", @@ -133,5 +125,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index e9e92f7a1e2..036464e718d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -210,5 +210,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c index 296e01d6d31..01bb0ae2b93 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c @@ -182,5 +182,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index f6ddcf89bcf..f03bc489521 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -174,5 +174,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index bc08da4b2cb..9320e849194 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -69,6 +69,7 @@ set(SRC intern/gpu_init_exit.c intern/gpu_material.c intern/gpu_matrix.c + intern/gpu_platform.c intern/gpu_primitive.c intern/gpu_select.c intern/gpu_select_pick.c @@ -101,6 +102,7 @@ set(SRC GPU_legacy_stubs.h GPU_material.h GPU_matrix.h + GPU_platform.h GPU_primitive.h GPU_select.h GPU_shader.h diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index 7d8c3347eb4..d7218e97bf0 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -193,8 +193,10 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff #endif /* future plans */ -/* GPUDrawList is an API to do lots of similar drawcalls very fast using multidrawindirect. - * There is a fallback if the feature is not supported. */ +/** + * #GPUDrawList is an API to do lots of similar draw-calls very fast using multi-draw-indirect. + * There is a fallback if the feature is not supported. + */ typedef struct GPUDrawList GPUDrawList; GPUDrawList *GPU_draw_list_create(int length); diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 552bad2b0d6..6d2b0ad3be3 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -31,6 +31,7 @@ struct CCGElem; struct CCGKey; struct DMFlagMat; struct GSet; +struct Mesh; struct MLoop; struct MLoopCol; struct MLoopTri; @@ -49,7 +50,8 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], const struct MLoopTri *looptri, const struct MVert *verts, const int *face_indices, - const int face_indices_len); + const int face_indices_len, + const struct Mesh *mesh); GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden); diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 023cbb804d9..245f7f47510 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -55,34 +55,6 @@ void GPU_mem_stats_get(int *totalmem, int *freemem); void GPU_code_generate_glsl_lib(void); -/* GPU Types */ - -typedef enum eGPUDeviceType { - GPU_DEVICE_NVIDIA = (1 << 0), - GPU_DEVICE_ATI = (1 << 1), - GPU_DEVICE_INTEL = (1 << 2), - GPU_DEVICE_INTEL_UHD = (1 << 3), - GPU_DEVICE_SOFTWARE = (1 << 4), - GPU_DEVICE_UNKNOWN = (1 << 5), - GPU_DEVICE_ANY = (0xff), -} eGPUDeviceType; - -typedef enum eGPUOSType { - GPU_OS_WIN = (1 << 8), - GPU_OS_MAC = (1 << 9), - GPU_OS_UNIX = (1 << 10), - GPU_OS_ANY = (0xff00), -} eGPUOSType; - -typedef enum eGPUDriverType { - GPU_DRIVER_OFFICIAL = (1 << 16), - GPU_DRIVER_OPENSOURCE = (1 << 17), - GPU_DRIVER_SOFTWARE = (1 << 18), - GPU_DRIVER_ANY = (0xff0000), -} eGPUDriverType; - -bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h new file mode 100644 index 00000000000..f199a748cb5 --- /dev/null +++ b/source/blender/gpu/GPU_platform.h @@ -0,0 +1,75 @@ +/* + * 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) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#ifndef __GPU_PLATFORM_H__ +#define __GPU_PLATFORM_H__ + +#include "BLI_sys_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* GPU platform support */ + +/* GPU Types */ +typedef enum eGPUDeviceType { + GPU_DEVICE_NVIDIA = (1 << 0), + GPU_DEVICE_ATI = (1 << 1), + GPU_DEVICE_INTEL = (1 << 2), + GPU_DEVICE_INTEL_UHD = (1 << 3), + GPU_DEVICE_SOFTWARE = (1 << 4), + GPU_DEVICE_UNKNOWN = (1 << 5), + GPU_DEVICE_ANY = (0xff), +} eGPUDeviceType; + +typedef enum eGPUOSType { + GPU_OS_WIN = (1 << 8), + GPU_OS_MAC = (1 << 9), + GPU_OS_UNIX = (1 << 10), + GPU_OS_ANY = (0xff00), +} eGPUOSType; + +typedef enum eGPUDriverType { + GPU_DRIVER_OFFICIAL = (1 << 16), + GPU_DRIVER_OPENSOURCE = (1 << 17), + GPU_DRIVER_SOFTWARE = (1 << 18), + GPU_DRIVER_ANY = (0xff0000), +} eGPUDriverType; + +typedef enum eGPUSupportLevel { + GPU_SUPPORT_LEVEL_SUPPORTED, + GPU_SUPPORT_LEVEL_LIMITED, + GPU_SUPPORT_LEVEL_UNSUPPORTED, +} eGPUSupportLevel; + +bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver); +eGPUSupportLevel GPU_platform_support_level(void); +const char *GPU_platform_support_level_key(void); +const char *GPU_platform_gpu_name(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_PLATFORM_H__ */ diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 2620ba49799..fc578b4466c 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -29,6 +29,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_matrix.h" #include "GPU_shader.h" @@ -718,8 +719,11 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count) #if 0 # define USE_MULTI_DRAW_INDIRECT 0 #else +/* TODO: partial workaround for NVIDIA driver bug on recent GTX/RTX cards, + * that breaks instancing when using indirect draw-call (see T70011). */ # define USE_MULTI_DRAW_INDIRECT \ - (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported()) + (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported() && \ + !GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) #endif typedef struct GPUDrawCommand { @@ -852,16 +856,19 @@ void GPU_draw_list_submit(GPUDrawList *list) uintptr_t offset = list->cmd_offset; uint cmd_len = list->cmd_len; size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed); - list->cmd_offset += bytes_used; list->cmd_len = 0; /* Avoid reuse. */ - if (USE_MULTI_DRAW_INDIRECT) { + /* Only do multi-draw indirect if doing more than 2 drawcall. + * This avoids the overhead of buffer mapping if scene is + * not very instance friendly. */ + if (USE_MULTI_DRAW_INDIRECT && cmd_len > 2) { GLenum prim = batch->gl_prim_type; glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id); glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used); glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); list->commands = NULL; /* Unmapped */ + list->cmd_offset += bytes_used; if (batch->elem) { glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0); @@ -875,6 +882,8 @@ void GPU_draw_list_submit(GPUDrawList *list) if (batch->elem) { GPUDrawCommandIndexed *cmd = list->commands_indexed; for (int i = 0; i < cmd_len; i++, cmd++) { + /* Index start was added by Draw manager. Avoid counting it twice. */ + cmd->v_first -= batch->elem->index_start; GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); } } diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c index 3a8b392ef1d..825f72e175b 100644 --- a/source/blender/gpu/intern/gpu_batch_utils.c +++ b/source/blender/gpu/intern/gpu_batch_utils.c @@ -164,7 +164,6 @@ GPUBatch *GPU_batch_wire_from_poly_2d_encoded(const uchar *polys_flat, BLI_assert(polys_step_len >= 2); for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) { union { - uint8_t as_u8[4]; uint16_t as_u16[2]; uint32_t as_u32; } data; diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index ed606ccb8c6..2c74afd2d8e 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -316,10 +316,12 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], const MLoopTri *looptri, const MVert *mvert, const int *face_indices, - const int face_indices_len) + const int face_indices_len, + const struct Mesh *mesh) { GPU_PBVH_Buffers *buffers; int i, tottri; + int tot_real_edges = 0; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); @@ -332,6 +334,13 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], for (i = 0, tottri = 0; i < face_indices_len; i++) { const MLoopTri *lt = &looptri[face_indices[i]]; if (!paint_is_face_hidden(lt, mvert, mloop)) { + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); + for (int j = 0; j < 3; j++) { + if (r_edges[j] != -1) { + tot_real_edges++; + } + } tottri++; } } @@ -355,7 +364,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], /* Fill the triangle and line buffers. */ GPUIndexBufBuilder elb, elb_lines; GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX); + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); for (i = 0; i < face_indices_len; i++) { const MLoopTri *lt = &looptri[face_indices[i]]; @@ -366,11 +375,18 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], } GPU_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i])); + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); - /* TODO skip "non-real" edges. */ - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]); - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]); - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]); + if (r_edges[0] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]); + } + if (r_edges[1] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]); + } + if (r_edges[2] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]); + } } buffers->index_buf = GPU_indexbuf_build(&elb); buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); @@ -378,7 +394,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], else { /* Fill the only the line buffer. */ GPUIndexBufBuilder elb_lines; - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX); + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); int vert_idx = 0; for (i = 0; i < face_indices_len; i++) { @@ -389,10 +405,18 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], continue; } - /* TODO skip "non-real" edges. */ - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); + if (r_edges[0] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); + } + if (r_edges[1] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); + } + if (r_edges[2] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); + } + vert_idx++; } buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); @@ -729,47 +753,36 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid /** \name BMesh PBVH * \{ */ -/* Output a BMVert into a VertexBufferFormat array - * - * The vertex is skipped if hidden, otherwise the output goes into - * index '*v_index' in the 'vert_data' array and '*v_index' is - * incremented. - */ -static void gpu_bmesh_vert_to_buffer_copy__gwn(BMVert *v, - GPUVertBuf *vert_buf, - int *v_index, - const float fno[3], - const float *fmask, - const int cd_vert_mask_offset, - const bool show_mask, - const bool show_vcol, - bool *empty_mask) +/* Output a BMVert into a VertexBufferFormat array at v_index. */ +static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, + GPUVertBuf *vert_buf, + int v_index, + const float fno[3], + const float *fmask, + const int cd_vert_mask_offset, + const bool show_mask, + const bool show_vcol, + bool *empty_mask) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - - /* Set coord, normal, and mask */ - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, *v_index, v->co); - - short no_short[3]; - normal_float_to_short_v3(no_short, fno ? fno : v->no); - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, *v_index, no_short); + /* Vertex should always be visible if it's used by a visible face. */ + BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN)); - if (show_mask) { - float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, *v_index, &effective_mask); - *empty_mask = *empty_mask && (effective_mask == 0.0f); - } + /* Set coord, normal, and mask */ + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co); - if (show_vcol) { - static char vcol[4] = {255, 255, 255, 255}; - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, *v_index, &vcol); - } + short no_short[3]; + normal_float_to_short_v3(no_short, fno ? fno : v->no); + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short); - /* Assign index for use in the triangle index buffer */ - /* note: caller must set: bm->elem_index_dirty |= BM_VERT; */ - BM_elem_index_set(v, (*v_index)); /* set_dirty! */ + if (show_mask) { + float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &effective_mask); + *empty_mask = *empty_mask && (effective_mask == 0.0f); + } - (*v_index)++; + if (show_vcol) { + static char vcol[4] = {255, 255, 255, 255}; + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol); } } @@ -839,7 +852,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, { const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; - int tottri, totvert, maxvert = 0; + int tottri, totvert; bool empty_mask = true; BMFace *f = NULL; @@ -869,135 +882,118 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); /* Fill vertex buffer */ - if (gpu_pbvh_vert_buf_data_set(buffers, totvert)) { - int v_index = 0; - - if (buffers->smooth) { - GSetIterator gs_iter; - - /* Vertices get an index assigned for use in the triangle - * index buffer */ - bm->elem_index_dirty |= BM_VERT; - - GSET_ITER (gs_iter, bm_unique_verts) { - gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter), - buffers->vert_buf, - &v_index, - NULL, - NULL, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); - } - - GSET_ITER (gs_iter, bm_other_verts) { - gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter), - buffers->vert_buf, - &v_index, - NULL, - NULL, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); - } + if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) { + /* Memory map failed */ + return; + } - maxvert = v_index; - } - else { - GSetIterator gs_iter; + int v_index = 0; - GPUIndexBufBuilder elb_lines; - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); + if (buffers->smooth) { + /* Fill the vertex and triangle buffer in one pass over faces. */ + GPUIndexBufBuilder elb, elb_lines; + GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert); + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); - GSET_ITER (gs_iter, bm_faces) { - f = BLI_gsetIterator_getKey(&gs_iter); + GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert); - BLI_assert(f->len == 3); + GSetIterator gs_iter; + GSET_ITER (gs_iter, bm_faces) { + f = BLI_gsetIterator_getKey(&gs_iter); - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - BMVert *v[3]; - float fmask = 0.0f; - int i; + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + BMVert *v[3]; + BM_face_as_array_vert_tri(f, v); - BM_face_as_array_vert_tri(f, v); + uint idx[3]; + for (int i = 0; i < 3; i++) { + void **idx_p; + if (!BLI_ghash_ensure_p(bm_vert_to_index, v[i], &idx_p)) { + /* Add vertex to the vertex buffer each time a new one is encountered */ + *idx_p = POINTER_FROM_UINT(v_index); - /* Average mask value */ - for (i = 0; i < 3; i++) { - fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset); + gpu_bmesh_vert_to_buffer_copy(v[i], + buffers->vert_buf, + v_index, + NULL, + NULL, + cd_vert_mask_offset, + show_mask, + show_vcol, + &empty_mask); + + idx[i] = v_index; + v_index++; } - fmask /= 3.0f; - - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1); - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2); - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0); - - for (i = 0; i < 3; i++) { - gpu_bmesh_vert_to_buffer_copy__gwn(v[i], - buffers->vert_buf, - &v_index, - f->no, - &fmask, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); + else { + /* Vertex already in the vertex buffer, just get the index. */ + idx[i] = POINTER_AS_UINT(*idx_p); } } - } - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); - buffers->tot_tri = tottri; + GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]); + + GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]); + GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]); + GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]); + } } - /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */ - bm->elem_index_dirty |= BM_VERT; + BLI_ghash_free(bm_vert_to_index, NULL, NULL); + + buffers->tot_tri = tottri; + if (buffers->index_buf == NULL) { + buffers->index_buf = GPU_indexbuf_build(&elb); + } + else { + GPU_indexbuf_build_in_place(&elb, buffers->index_buf); + } + buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); } else { - /* Memory map failed */ - return; - } + GSetIterator gs_iter; - if (buffers->smooth) { - /* Fill the triangle buffer */ - GPUIndexBufBuilder elb, elb_lines; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, maxvert); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, maxvert); - - /* Fill triangle index buffer */ - { - GSetIterator gs_iter; + GPUIndexBufBuilder elb_lines; + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3); - GSET_ITER (gs_iter, bm_faces) { - f = BLI_gsetIterator_getKey(&gs_iter); + GSET_ITER (gs_iter, bm_faces) { + f = BLI_gsetIterator_getKey(&gs_iter); - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - BMVert *v[3]; + BLI_assert(f->len == 3); - BM_face_as_array_vert_tri(f, v); + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + BMVert *v[3]; + float fmask = 0.0f; + int i; - const uint idx[3] = { - BM_elem_index_get(v[0]), BM_elem_index_get(v[1]), BM_elem_index_get(v[2])}; - GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]); + BM_face_as_array_vert_tri(f, v); - GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]); - GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]); - GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]); + /* Average mask value */ + for (i = 0; i < 3; i++) { + fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset); + } + fmask /= 3.0f; + + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1); + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2); + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0); + + for (i = 0; i < 3; i++) { + gpu_bmesh_vert_to_buffer_copy(v[i], + buffers->vert_buf, + v_index++, + f->no, + &fmask, + cd_vert_mask_offset, + show_mask, + show_vcol, + &empty_mask); } } - - buffers->tot_tri = tottri; - - if (buffers->index_buf == NULL) { - buffers->index_buf = GPU_indexbuf_build(&elb); - } - else { - GPU_indexbuf_build_in_place(&elb, buffers->index_buf); - } - - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); } + + buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); + buffers->tot_tri = tottri; } /* Get material index from the last face we iterated on. */ @@ -1054,6 +1050,7 @@ void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) GPU_BATCH_DISCARD_SAFE(buffers->triangles); GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + buffers->clear_bmesh_on_flush = false; } /* Force flushing to the GPU. */ diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index c9ae6c60293..7fa2eb6424c 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -66,6 +66,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_glew.h" +#include "GPU_platform.h" #include "GPU_texture.h" #include "PIL_time.h" diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c index 166a6236893..518829d1c78 100644 --- a/source/blender/gpu/intern/gpu_element.c +++ b/source/blender/gpu/intern/gpu_element.c @@ -243,7 +243,7 @@ GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uin { GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); BLI_assert(elem_src && !elem_src->is_subrange); - BLI_assert(start + length <= elem_src->index_len); + BLI_assert((length == 0) || (start + length <= elem_src->index_len)); #if GPU_TRACK_INDEX_RANGE elem->index_type = elem_src->index_type; elem->gl_index_type = elem_src->gl_index_type; diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index c6425854ee4..33f918559f7 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -35,6 +35,7 @@ #include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_texture.h" +#include "GPU_platform.h" #include "intern/gpu_private.h" @@ -68,9 +69,6 @@ static struct GPUGlobal { GLint maxubosize; GLint maxubobinds; int samples_color_texture_max; - eGPUDeviceType device; - eGPUOSType os; - eGPUDriverType driver; float line_width_range[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers * calculate dfdy in shader differently when drawing to an offscreen buffer. First @@ -126,13 +124,6 @@ static void gpu_detect_mip_render_workaround(void) GPU_texture_free(tex); } -/* GPU Types */ - -bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) -{ - return (GG.device & device) && (GG.os & os) && (GG.driver & driver); -} - /* GPU Extensions */ int GPU_max_texture_size(void) @@ -266,11 +257,7 @@ void gpu_extensions_init(void) const char *renderer = (const char *)glGetString(GL_RENDERER); const char *version = (const char *)glGetString(GL_VERSION); - if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { - GG.device = GPU_DEVICE_ATI; - GG.driver = GPU_DRIVER_OFFICIAL; - -#ifdef _WIN32 + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL)) { if (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") || strstr(version, "4.5.13422")) { /* The renderers include: @@ -282,75 +269,14 @@ void gpu_extensions_init(void) GG.unused_fb_slot_workaround = true; } -#endif + } -#if defined(__APPLE__) + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) { if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") || strstr(renderer, "AMD Radeon RX")) { GG.depth_blitting_workaround = true; } -#endif - } - else if (strstr(vendor, "NVIDIA")) { - GG.device = GPU_DEVICE_NVIDIA; - GG.driver = GPU_DRIVER_OFFICIAL; - } - else if (strstr(vendor, "Intel") || - /* src/mesa/drivers/dri/intel/intel_context.c */ - strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) { - GG.device = GPU_DEVICE_INTEL; - GG.driver = GPU_DRIVER_OFFICIAL; - - if (strstr(renderer, "UHD Graphics") || - /* Not UHD but affected by the same bugs. */ - strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) { - GG.device |= GPU_DEVICE_INTEL_UHD; - } } - else if ((strstr(renderer, "Mesa DRI R")) || - (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) || - (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) || - (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || - (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) { - GG.device = GPU_DEVICE_ATI; - GG.driver = GPU_DRIVER_OPENSOURCE; - } - else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) { - GG.device = GPU_DEVICE_NVIDIA; - GG.driver = GPU_DRIVER_OPENSOURCE; - } - else if (strstr(vendor, "Mesa")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(vendor, "Microsoft")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(renderer, "Apple Software Renderer")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(renderer, "llvmpipe")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else { - printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); - printf("Detected OpenGL configuration:\n"); - printf("Vendor: %s\n", vendor); - printf("Renderer: %s\n", renderer); - GG.device = GPU_DEVICE_ANY; - GG.driver = GPU_DRIVER_ANY; - } - -#ifdef _WIN32 - GG.os = GPU_OS_WIN; -#elif defined(__APPLE__) - GG.os = GPU_OS_MAC; -#else - GG.os = GPU_OS_UNIX; -#endif GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance; gpu_detect_mip_render_workaround(); @@ -372,11 +298,12 @@ void gpu_extensions_init(void) GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = 1.0; - if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) { + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) && + strstr(version, "3.3.10750")) { GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = -1.0; } - else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN)) { + else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) { if (strstr(version, "4.0.0 - Build 10.18.10.3308") || strstr(version, "4.0.0 - Build 9.18.10.3186") || strstr(version, "4.0.0 - Build 9.18.10.3165") || @@ -401,8 +328,7 @@ void gpu_extensions_init(void) GG.context_local_shaders_workaround = true; } } - else if ((GG.device == GPU_DEVICE_ATI) && (GG.os == GPU_OS_UNIX) && - (GG.driver == GPU_DRIVER_OPENSOURCE)) { + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the * Mesa driver */ GG.unused_fb_slot_workaround = true; diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 0009e7d8c47..7b6016e11cb 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -46,7 +46,7 @@ void GPU_init(void) } initialized = true; - + gpu_platform_init(); gpu_extensions_init(); /* must come first */ gpu_codegen_init(); @@ -82,7 +82,8 @@ void GPU_exit(void) gpu_framebuffer_module_exit(); gpu_codegen_exit(); - gpu_extensions_exit(); /* must come last */ + gpu_extensions_exit(); + gpu_platform_exit(); /* must come last */ initialized = false; } diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.c new file mode 100644 index 00000000000..871052bb070 --- /dev/null +++ b/source/blender/gpu/intern/gpu_platform.c @@ -0,0 +1,229 @@ +/* + * 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) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Wrap OpenGL features such as textures, shaders and GLSL + * with checks for drivers and GPU support. + */ +#include "GPU_platform.h" +#include "GPU_glew.h" +#include "gpu_private.h" + +#include <string.h> + +#include "BLI_dynstr.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" + +static struct GPUPlatformGlobal { + bool initialized; + eGPUDeviceType device; + eGPUOSType os; + eGPUDriverType driver; + eGPUSupportLevel support_level; + char *support_key; + char *gpu_name; +} GPG = {false}; + +typedef struct GPUPlatformSupportTest { + eGPUSupportLevel support_level; + eGPUDeviceType device; + eGPUOSType os; + eGPUDriverType driver; + const char *vendor; + const char *renderer; + const char *version; +} GPUPlatformSupportTest; + +eGPUSupportLevel GPU_platform_support_level(void) +{ + return GPG.support_level; +} + +const char *GPU_platform_support_level_key(void) +{ + return GPG.support_key; +} + +const char *GPU_platform_gpu_name(void) +{ + return GPG.gpu_name; +} + +/* GPU Types */ +bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) +{ + return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver); +} + +static char *gpu_platform_create_key(eGPUSupportLevel support_level, + const char *vendor, + const char *renderer, + const char *version) +{ + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, "{"); + BLI_dynstr_append(ds, vendor); + BLI_dynstr_append(ds, "/"); + BLI_dynstr_append(ds, renderer); + BLI_dynstr_append(ds, "/"); + BLI_dynstr_append(ds, version); + BLI_dynstr_append(ds, "}"); + BLI_dynstr_append(ds, "="); + if (support_level == GPU_SUPPORT_LEVEL_SUPPORTED) { + BLI_dynstr_append(ds, "SUPPORTED"); + } + else if (support_level == GPU_SUPPORT_LEVEL_LIMITED) { + BLI_dynstr_append(ds, "LIMITED"); + } + else { + BLI_dynstr_append(ds, "UNSUPPORTED"); + } + + char *support_key = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + BLI_str_replace_char(support_key, '\n', ' '); + BLI_str_replace_char(support_key, '\r', ' '); + return support_key; +} + +static char *gpu_platform_create_gpu_name(const char *vendor, + const char *renderer, + const char *version) +{ + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, vendor); + BLI_dynstr_append(ds, " "); + BLI_dynstr_append(ds, renderer); + BLI_dynstr_append(ds, " "); + BLI_dynstr_append(ds, version); + + char *gpu_name = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + BLI_str_replace_char(gpu_name, '\n', ' '); + BLI_str_replace_char(gpu_name, '\r', ' '); + return gpu_name; +} + +void gpu_platform_init(void) +{ + if (GPG.initialized) { + return; + } + +#ifdef _WIN32 + GPG.os = GPU_OS_WIN; +#elif defined(__APPLE__) + GPG.os = GPU_OS_MAC; +#else + GPG.os = GPU_OS_UNIX; +#endif + + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *version = (const char *)glGetString(GL_VERSION); + + if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { + GPG.device = GPU_DEVICE_ATI; + GPG.driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "NVIDIA")) { + GPG.device = GPU_DEVICE_NVIDIA; + GPG.driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "Intel") || + /* src/mesa/drivers/dri/intel/intel_context.c */ + strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) { + GPG.device = GPU_DEVICE_INTEL; + GPG.driver = GPU_DRIVER_OFFICIAL; + + if (strstr(renderer, "UHD Graphics") || + /* Not UHD but affected by the same bugs. */ + strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) { + GPG.device |= GPU_DEVICE_INTEL_UHD; + } + } + else if ((strstr(renderer, "Mesa DRI R")) || + (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) || + (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) { + GPG.device = GPU_DEVICE_ATI; + GPG.driver = GPU_DRIVER_OPENSOURCE; + } + else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) { + GPG.device = GPU_DEVICE_NVIDIA; + GPG.driver = GPU_DRIVER_OPENSOURCE; + } + else if (strstr(vendor, "Mesa")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(vendor, "Microsoft")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(renderer, "Apple Software Renderer")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else { + printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); + printf("Detected OpenGL configuration:\n"); + printf("Vendor: %s\n", vendor); + printf("Renderer: %s\n", renderer); + GPG.device = GPU_DEVICE_ANY; + GPG.driver = GPU_DRIVER_ANY; + } + + /* Detect support level */ + if (!GLEW_VERSION_3_3) { + GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; + } + else { + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) { + /* Old Intel drivers with known bugs that cause material properties to crash. + * Version Build 10.18.14.5067 is the latest available and appears to be working + * ok with our workarounds, so excluded from this list. */ + if (strstr(version, "Build 7.14") || strstr(version, "Build 7.15") || + strstr(version, "Build 8.15") || strstr(version, "Build 9.17") || + strstr(version, "Build 9.18") || strstr(version, "Build 10.18.10.3") || + strstr(version, "Build 10.18.10.4") || strstr(version, "Build 10.18.10.5") || + strstr(version, "Build 10.18.14.4")) { + GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; + } + } + } + GPG.support_key = gpu_platform_create_key(GPG.support_level, vendor, renderer, version); + GPG.gpu_name = gpu_platform_create_gpu_name(vendor, renderer, version); + GPG.initialized = true; +} + +void gpu_platform_exit(void) +{ + MEM_SAFE_FREE(GPG.support_key); + MEM_SAFE_FREE(GPG.gpu_name); +} diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h index b9af8f1b38c..7846bff87f4 100644 --- a/source/blender/gpu/intern/gpu_private.h +++ b/source/blender/gpu/intern/gpu_private.h @@ -22,6 +22,10 @@ #define __GPU_PRIVATE_H__ /* call this before running any of the functions below */ +void gpu_platform_init(void); +void gpu_platform_exit(void); + +/* call this before running any of the functions below */ void gpu_extensions_init(void); void gpu_extensions_exit(void); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 015df078228..5df73d1a0c6 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -36,6 +36,7 @@ #include "DNA_space_types.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index a54d90f37f5..497fc13a2c8 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -38,6 +38,7 @@ #include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_framebuffer.h" +#include "GPU_platform.h" #include "GPU_texture.h" #include "gpu_context_private.h" diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl index abe6081489d..e089aec1d92 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl @@ -92,14 +92,14 @@ void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol) void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol.rgb = min(col1.rgb, col2.rgb * fac); + outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac); outcol.a = col1.a; } void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol.rgb = max(col1.rgb, col2.rgb * fac); + outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac); outcol.a = col1.a; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index 140213a9ed9..7af409dd410 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -113,14 +113,14 @@ void node_bsdf_principled(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec + out_refr; result.radiance += out_diff * out_sheen; /* Coarse approx. */ + result.radiance += emission.rgb; + result.radiance *= alpha; closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); mixed_ss_base_color *= alpha * (1.0 - transmission); closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); - result.radiance += emission.rgb; - result.radiance *= alpha; result.transmittance = vec3(1.0 - alpha); } @@ -169,9 +169,11 @@ void node_bsdf_principled_dielectric(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec + out_diff * (diffuse + out_sheen); - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + result.transmittance = vec3(1.0 - alpha); } @@ -213,9 +215,11 @@ void node_bsdf_principled_metallic(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + result.transmittance = vec3(1.0 - alpha); } @@ -267,9 +271,11 @@ void node_bsdf_principled_clearcoat(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + result.transmittance = vec3(1.0 - alpha); } @@ -333,14 +339,15 @@ void node_bsdf_principled_subsurface(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec; + result.radiance += out_diff * out_sheen; + result.radiance += emission.rgb; + result.radiance *= alpha; + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); mixed_ss_base_color *= alpha * (1.0 - transmission); closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); - result.radiance += out_diff * out_sheen; - result.radiance += emission.rgb; - result.radiance *= alpha; result.transmittance = vec3(1.0 - alpha); } @@ -402,9 +409,9 @@ void node_bsdf_principled_glass(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = mix(out_refr, out_spec, fresnel); - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.transmittance = vec3(1.0 - alpha); } #else diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 9e9c47194e1..173c8135f96 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -700,6 +700,8 @@ void imb_freemipmapImBuf(struct ImBuf *ibuf); bool imb_addtilesImBuf(struct ImBuf *ibuf); void imb_freetilesImBuf(struct ImBuf *ibuf); +void imb_freerectImbuf_all(struct ImBuf *ibuf); + /* threaded processors */ void IMB_processor_apply_threaded( int buffer_lines, diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 75db3fd3c73..381de9de610 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -197,6 +197,17 @@ void IMB_freezbuffloatImBuf(ImBuf *ibuf) ibuf->mall &= ~IB_zbuffloat; } +/** Free all pixel data (assosiated with image size). */ +void imb_freerectImbuf_all(ImBuf *ibuf) +{ + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + imb_freetilesImBuf(ibuf); + IMB_freezbufImBuf(ibuf); + IMB_freezbuffloatImBuf(ibuf); + freeencodedbufferImBuf(ibuf); +} + void IMB_freeImBuf(ImBuf *ibuf) { if (ibuf) { @@ -212,12 +223,7 @@ void IMB_freeImBuf(ImBuf *ibuf) BLI_spin_unlock(&refcounter_spin); if (needs_free) { - imb_freerectImBuf(ibuf); - imb_freerectfloatImBuf(ibuf); - imb_freetilesImBuf(ibuf); - IMB_freezbufImBuf(ibuf); - IMB_freezbuffloatImBuf(ibuf); - freeencodedbufferImBuf(ibuf); + imb_freerectImbuf_all(ibuf); IMB_metadata_free(ibuf->metadata); colormanage_cache_free(ibuf); diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index 49e9c4c54d2..ec03a0a07b8 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -401,11 +401,6 @@ typedef struct ScanlineGlobalData { int total_scanlines; } ScanlineGlobalData; -typedef struct ScanlineTask { - int start_scanline; - int num_scanlines; -} ScanlineTask; - static void processor_apply_scanline_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 3163a960892..7150e41841b 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -262,7 +262,7 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop) BLI_rcti_size_x(crop) + 1, BLI_rcti_size_y(crop) + 1, }; - BLI_assert(size_dst[0] > 0 && size_dst[0] > 0); + BLI_assert(size_dst[0] > 0 && size_dst[1] > 0); BLI_assert(crop->xmin >= 0 && crop->ymin >= 0); BLI_assert(crop->xmax < ibuf->x && crop->ymax < ibuf->y); @@ -304,7 +304,7 @@ static void rect_realloc_16bytes(void **buf_p, const uint size[2]) */ void IMB_rect_size_set(ImBuf *ibuf, const uint size[2]) { - BLI_assert(size[0] > 0 && size[0] > 0); + BLI_assert(size[0] > 0 && size[1] > 0); if ((size[0] == ibuf->x) && (size[1] == ibuf->y)) { return; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index a6212e09567..47bf49294b6 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -697,6 +697,13 @@ enum { FILTER_ID_LP = (1u << 31), }; +#define FILTER_ID_ALL \ + (FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD | \ + FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | \ + FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | \ + FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | \ + FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP) + /* IMPORTANT: this enum matches the order currently use in set_listbasepointers, * keep them in sync! */ enum { diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index aec28c0fe75..fc8763f1519 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -502,7 +502,8 @@ typedef enum eBrushUVSculptTool { SCULPT_TOOL_SCRAPE, \ SCULPT_TOOL_FLATTEN) -#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK) +#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) \ + ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ELASTIC_DEFORM) #define SCULPT_TOOL_HAS_RAKE(t) ELEM(t, SCULPT_TOOL_SNAKE_HOOK) diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 2dffdf82688..1435d0a64b4 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -401,6 +401,8 @@ typedef enum eGPDlayer_Flag { GP_LAYER_USE_MASK = (1 << 13), /* Flag used to display in Paint mode only layers with keyframe */ GP_LAYER_SOLO_MODE = (1 << 4), + /* Ruler Layer */ + GP_LAYER_IS_RULER = (1 << 14), } eGPDlayer_Flag; /* bGPDlayer->onion_flag */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 3af1da46f80..4de98e0b684 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -118,13 +118,13 @@ enum { BASE_HIDDEN = (1 << 8), /* Object is hidden for editing. */ /* Runtime evaluated flags. */ - BASE_VISIBLE = (1 << 1), /* Object is enabled and visible. */ - BASE_SELECTABLE = (1 << 2), /* Object can be selected. */ - BASE_FROM_DUPLI = (1 << 3), /* Object comes from duplicator. */ - /* BASE_DEPRECATED = (1 << 4), */ - BASE_FROM_SET = (1 << 5), /* Object comes from set. */ - BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */ - BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */ + BASE_VISIBLE_DEPSGRAPH = (1 << 1), /* Object is enabled and visible for the depsgraph. */ + BASE_SELECTABLE = (1 << 2), /* Object can be selected. */ + BASE_FROM_DUPLI = (1 << 3), /* Object comes from duplicator. */ + BASE_VISIBLE_VIEWLAYER = (1 << 4), /* Object is enabled and visible for the viewlayer. */ + BASE_FROM_SET = (1 << 5), /* Object comes from set. */ + BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */ + BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */ /* BASE_DEPRECATED = (1 << 9), */ BASE_HOLDOUT = (1 << 10), /* Object masked out from render */ BASE_INDIRECT_ONLY = (1 << 11), /* Object only contributes indirectly to render */ @@ -142,10 +142,13 @@ enum { LAYER_COLLECTION_HIDE = (1 << 7), }; -/* Layer Collection->runtime_flag */ +/* Layer Collection->runtime_flag + Keep it synced with base->flag based on g_base_collection_flags. */ enum { LAYER_COLLECTION_HAS_OBJECTS = (1 << 0), - LAYER_COLLECTION_VISIBLE = (1 << 1), + LAYER_COLLECTION_VISIBLE_DEPSGRAPH = (1 << 1), + LAYER_COLLECTION_RESTRICT_VIEWPORT = (1 << 2), + LAYER_COLLECTION_VISIBLE_VIEW_LAYER = (1 << 4), }; /* ViewLayer->flag */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ca572f1ddf1..8763f62b385 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1976,14 +1976,7 @@ extern const char *RE_engine_id_CYCLES; #define MINAFRAME -1048574 #define MINAFRAMEF -1048574.0f -#define BASE_VISIBLE(v3d, base) \ - (((v3d == NULL) || ((v3d)->localvd == NULL) || \ - ((v3d)->local_view_uuid & (base)->local_view_bits)) && \ - ((v3d == NULL) || (((v3d)->flag & V3D_LOCAL_COLLECTIONS) == 0) || \ - ((v3d)->local_collections_uuid & (base)->local_collections_bits)) && \ - ((v3d == NULL) || \ - (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \ - (((base)->flag & BASE_VISIBLE) != 0)) +#define BASE_VISIBLE(v3d, base) BKE_base_is_visible(v3d, base) #define BASE_SELECTABLE(v3d, base) \ (BASE_VISIBLE(v3d, base) && \ ((v3d == NULL) || (((1 << (base)->object->type) & (v3d)->object_type_exclude_select) == 0)) && \ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 126b4638ca1..b9f43c0e579 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -394,6 +394,8 @@ typedef struct ThemeSpace { /** NLA - warning color for duplicate instances of tweaking strip. */ unsigned char nla_tweakdupli[4]; + /** NLA "Track" */ + unsigned char nla_track[4]; /** NLA "Transition" strips. */ unsigned char nla_transition[4], nla_transition_sel[4]; /** NLA "Meta" strips. */ @@ -414,7 +416,6 @@ typedef struct ThemeSpace { unsigned char metadatabg[4]; unsigned char metadatatext[4]; - char _pad2[4]; } ThemeSpace; /* set of colors for use as a custom color set for Objects/Bones wire drawing */ @@ -606,7 +607,8 @@ typedef struct UserDef { /** #eUserPref_PrefFlag preferences for the preferences. */ char pref_flag; char savetime; - char _pad4[4]; + char mouse_emulate_3_button_modifier; + char _pad4[3]; /** FILE_MAXDIR length. */ char tempdir[768]; char fontdir[768]; @@ -726,11 +728,13 @@ typedef struct UserDef { short curssize; /** #eColorPicker_Types. */ short color_picker_type; + /** Curve smoothing type for newly added F-Curves. */ + char auto_smoothing_new; /** Interpolation mode for newly added F-Curves. */ char ipo_new; /** Handle types for newly added keyframes. */ char keyhandles_new; - char _pad11[3]; + char _pad11[2]; /** #eZoomFrame_Mode. */ char view_frame_type; @@ -1240,6 +1244,11 @@ typedef enum eUserpref_TempSpaceDisplayType { USER_TEMP_SPACE_DISPLAY_WINDOW, } eUserpref_TempSpaceDisplayType; +typedef enum eUserpref_EmulateMMBMod { + USER_EMU_MMB_MOD_ALT = 0, + USER_EMU_MMB_MOD_OSKEY = 1, +} eUserpref_EmulateMMBMod; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index e72a55b5a9e..458f031ceae 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -90,6 +90,7 @@ extern const EnumPropertyItem rna_enum_color_sets_items[]; extern const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[]; extern const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[]; extern const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]; +extern const EnumPropertyItem rna_enum_fcurve_auto_smoothing_items[]; extern const EnumPropertyItem rna_enum_keyframe_handle_type_items[]; extern const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[]; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 71a3be24810..aeb6d528cdb 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -393,7 +393,7 @@ bool RNA_struct_idprops_check(StructRNA *srna) return (srna && srna->idproperties); } -static IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name) +IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name) { IDProperty *group = RNA_struct_idprops(ptr, 0); diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index b061c72157e..18fbe7886e9 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -400,9 +400,39 @@ static bool rna_property_override_operation_store(Main *bmain, return changed; } - BLI_assert(prop_local->override_store == prop_reference->override_store && - (!ptr_storage || prop_local->override_store == prop_storage->override_store) && - prop_local->override_store != NULL); + RNAPropOverrideStore override_store = NULL; + /* Special case for IDProps, we use default callback then. */ + if (prop_local->magic != RNA_MAGIC) { + override_store = rna_property_override_store_default; + if (prop_reference->magic == RNA_MAGIC && prop_reference->override_store != override_store) { + override_store = NULL; + } + } + else if (prop_reference->magic != RNA_MAGIC) { + override_store = rna_property_override_store_default; + if (prop_local->override_store != override_store) { + override_store = NULL; + } + } + else if (prop_local->override_store == prop_reference->override_store) { + override_store = prop_local->override_store; + } + + if (ptr_storage != NULL && prop_storage->magic == RNA_MAGIC && + prop_storage->override_store != override_store) { + override_store = NULL; + } + + if (override_store == NULL) { +#ifndef NDEBUG + printf("'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d).\n", + op->rna_path, + prop_local->magic == RNA_MAGIC, + prop_reference->magic == RNA_MAGIC); +#endif + BLI_assert(0); + return changed; + } for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { /* Only needed for diff operations. */ @@ -413,17 +443,17 @@ static bool rna_property_override_operation_store(Main *bmain, continue; } - if (prop_local->override_store(bmain, - ptr_local, - ptr_reference, - ptr_storage, - prop_local, - prop_reference, - prop_storage, - len_local, - len_reference, - len_storage, - opop)) { + if (override_store(bmain, + ptr_local, + ptr_reference, + ptr_storage, + prop_local, + prop_reference, + prop_storage, + len_local, + len_reference, + len_storage, + opop)) { changed = true; } } @@ -595,6 +625,21 @@ bool RNA_struct_override_matches(Main *bmain, prop_local = rna_ensure_property_realdata(&prop_local, ptr_local); prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference); + /* IDProps (custom properties) are even more of a PITA here, we cannot use + * `rna_ensure_property_realdata()` to deal with them, we have to use the path generated from + * `prop_local` (which is valid) to access to the actual reference counterpart... */ + if (prop_local != NULL && prop_local->magic != RNA_MAGIC && prop_local == prop_reference) { + /* We could also use (lower in this code, after rna_path has been computed): + * RNA_path_resolve_property(ptr_reference, rna_path, &some_rna_ptr, &prop_reference); + * But that would be much more costly, and would also fail when ptr_reference + * is not an ID pointer itself, so we'd need to rebuild it from its owner_id, then check that + * generated some_rna_ptr and ptr_reference do point to the same data, etc. + * For now, let's try that simple access, it won't cover all cases but should handle fine + * most basic custom properties situations. */ + prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, + ((IDProperty *)prop_local)->name); + } + if (ELEM(NULL, prop_local, prop_reference)) { continue; } diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h index 28ec504e376..c7995746d08 100644 --- a/source/blender/makesrna/intern/rna_access_internal.h +++ b/source/blender/makesrna/intern/rna_access_internal.h @@ -30,5 +30,6 @@ struct IDProperty; PropertyRNA *rna_ensure_property(PropertyRNA *prop); void rna_idproperty_touch(struct IDProperty *idprop); +struct IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name); #endif /* __ACCESS_RNA_INTERNAL_H__ */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index d7bb941b266..57a3d889437 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1452,81 +1452,77 @@ static void rna_def_brush(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem prop_blend_items[] = { - {IMB_BLEND_MIX, "MIX", 0, "Mix", "Use mix blending mode while painting"}, + {IMB_BLEND_MIX, "MIX", 0, "Mix", "Use Mix blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use darken blending mode while painting"}, - {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use multiply blending mode while painting"}, + {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use Darken blending mode while painting"}, + {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use Multiply blending mode while painting"}, {IMB_BLEND_COLORBURN, "COLORBURN", 0, - "Color burn", - "Use color burn blending mode while painting"}, + "Color Burn", + "Use Color Burn blending mode while painting"}, {IMB_BLEND_LINEARBURN, "LINEARBURN", 0, - "Linear burn", - "Use linear burn blending mode while painting"}, + "Linear Burn", + "Use Linear Burn blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use lighten blending mode while painting"}, - {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use screen blending mode while painting"}, + {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use Lighten blending mode while painting"}, + {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use Screen blending mode while painting"}, {IMB_BLEND_COLORDODGE, "COLORDODGE", 0, - "Color dodge", - "Use color dodge blending mode while painting"}, - {IMB_BLEND_ADD, "ADD", 0, "Add", "Use add blending mode while painting"}, + "Color Dodge", + "Use Color Dodge blending mode while painting"}, + {IMB_BLEND_ADD, "ADD", 0, "Add", "Use Add blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"}, + {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use Overlay blending mode while painting"}, {IMB_BLEND_SOFTLIGHT, "SOFTLIGHT", 0, - "Soft light", - "Use softlight blending mode while painting"}, + "Soft Light", + "Use Soft Light blending mode while painting"}, {IMB_BLEND_HARDLIGHT, "HARDLIGHT", 0, - "Hard light", - "Use hard light blending mode while painting"}, + "Hard Light", + "Use Hard Light blending mode while painting"}, {IMB_BLEND_VIVIDLIGHT, "VIVIDLIGHT", 0, - "Vivid light", - "Use vividlight blending mode while painting"}, + "Vivid Light", + "Use Vivid Light blending mode while painting"}, {IMB_BLEND_LINEARLIGHT, "LINEARLIGHT", 0, - "Linear light", - "Use linearlight blending mode while painting"}, + "Linear Light", + "Use Linear Light blending mode while painting"}, {IMB_BLEND_PINLIGHT, "PINLIGHT", 0, - "Pin light", - "Use pinlight blending mode while painting"}, + "Pin Light", + "Use Pin Light blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, {IMB_BLEND_DIFFERENCE, "DIFFERENCE", 0, "Difference", - "Use difference blending mode while painting"}, + "Use Difference blending mode while painting"}, {IMB_BLEND_EXCLUSION, "EXCLUSION", 0, "Exclusion", - "Use exclusion blending mode while painting"}, - {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use subtract blending mode while painting"}, + "Use Exclusion blending mode while painting"}, + {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use Subtract blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use hue blending mode while painting"}, + {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use Hue blending mode while painting"}, {IMB_BLEND_SATURATION, "SATURATION", 0, "Saturation", - "Use saturation blending mode while painting"}, - {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use color blending mode while painting"}, - {IMB_BLEND_LUMINOSITY, - "LUMINOSITY", - 0, - "Luminosity", - "Use luminosity blending mode while painting"}, + "Use Saturation blending mode while painting"}, + {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use Color blending mode while painting"}, + {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Value", "Use Value blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, {IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"}, {IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"}, @@ -1610,15 +1606,11 @@ static void rna_def_brush(BlenderRNA *brna) }; static const EnumPropertyItem brush_elastic_deform_type_items[] = { - {BRUSH_ELASTIC_DEFORM_GRAB, "ELASTIC_DEFORM_GRAB", 0, "Grab", ""}, - {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "ELASTIC_DEFORM_GRAB_BISCALE", 0, "Bi-scale Grab", ""}, - {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE, - "ELASTIC_DEFORM_GRAB_TRISCALE", - 0, - "Tri-scale Grab", - ""}, - {BRUSH_ELASTIC_DEFORM_SCALE, "ELASTIC_DEFORM_SCALE", 0, "Scale", ""}, - {BRUSH_ELASTIC_DEFORM_TWIST, "ELASTIC_DEFORM_TWIST", 0, "Twist", ""}, + {BRUSH_ELASTIC_DEFORM_GRAB, "GRAB", 0, "Grab", ""}, + {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "GRAB_BISCALE", 0, "Bi-scale Grab", ""}, + {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE, "GRAB_TRISCALE", 0, "Tri-scale Grab", ""}, + {BRUSH_ELASTIC_DEFORM_SCALE, "SCALE", 0, "Scale", ""}, + {BRUSH_ELASTIC_DEFORM_TWIST, "TWIST", 0, "Twist", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1893,8 +1885,8 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "normal_radius_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "normal_radius_factor"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_range(prop, 0.0f, 2.0f, 0.001, 3); RNA_def_property_ui_text(prop, "Normal Radius", "Ratio between the brush radius and the radius that is going to be " @@ -1967,7 +1959,7 @@ static void rna_def_brush(BlenderRNA *brna) /* flag */ /* This is an enum but its unlikely we add other shapes, so expose as a boolean. */ prop = RNA_def_property(srna, "use_projected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", BRUSH_AIRBRUSH); + RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", PAINT_FALLOFF_SHAPE_TUBE); RNA_def_property_ui_text( prop, "2D Falloff", "Apply brush influence in 2D circle instead of a sphere"); RNA_def_property_update(prop, 0, "rna_Brush_update"); @@ -2419,7 +2411,7 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna) prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_flag(prop, PROP_IDPROPERTY); RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_text(prop, "Brush Size", "Brush Size in screen space"); + RNA_def_property_ui_text(prop, "Brush Size", "Brush size in screen space"); prop = RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_IDPROPERTY); diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index ebd9bd8e925..2072b07ecb3 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -261,8 +261,13 @@ static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result) outer); } -static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain) +static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain, ReportList *reports) { + if (DEG_is_evaluating(depsgraph)) { + BKE_report(reports, RPT_ERROR, "Dependency graph update requested during evaluation"); + return; + } + # ifdef WITH_PYTHON /* Allow drivers to be evaluated */ BPy_BEGIN_ALLOW_THREADS; @@ -654,7 +659,7 @@ static void rna_def_depsgraph(BlenderRNA *brna) func, "Re-evaluate any modified data-blocks, for example for animation or modifiers. " "This invalidates all references to evaluated data-blocks from this dependency graph."); - RNA_def_function_flag(func, FUNC_USE_MAIN); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); /* Queries for original datablockls (the ones depsgraph is built for). */ diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 254f3bc3710..424bb4a492f 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -76,6 +76,22 @@ const EnumPropertyItem rna_enum_fmodifier_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_fcurve_auto_smoothing_items[] = { + {FCURVE_SMOOTH_NONE, + "NONE", + 0, + "None", + "Automatic handles only take immediately adjacent keys into account"}, + {FCURVE_SMOOTH_CONT_ACCEL, + "CONT_ACCEL", + 0, + "Continuous Acceleration", + "Automatic handles are adjusted to avoid jumps in acceleration, resulting " + "in smoother curves. However, key changes may affect interpolation over a " + "larger stretch of the curve"}, + {0, NULL, 0, NULL, NULL}, +}; + const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = { {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", @@ -2258,19 +2274,6 @@ static void rna_def_fcurve(BlenderRNA *brna) "Use custom hand-picked color for F-Curve"}, {0, NULL, 0, NULL, NULL}, }; - static EnumPropertyItem prop_mode_smoothing_items[] = { - {FCURVE_SMOOTH_NONE, - "NONE", - 0, - "None", - "Auto handles only take adjacent keys into account (legacy mode)"}, - {FCURVE_SMOOTH_CONT_ACCEL, - "CONT_ACCEL", - 0, - "Continuous Acceleration", - "Auto handles are placed to avoid jumps in acceleration"}, - {0, NULL, 0, NULL, NULL}, - }; srna = RNA_def_struct(brna, "FCurve", NULL); RNA_def_struct_ui_text(srna, "F-Curve", "F-Curve defining values of a period of time"); @@ -2350,7 +2353,7 @@ static void rna_def_fcurve(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); prop = RNA_def_property(srna, "auto_smoothing", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, prop_mode_smoothing_items); + RNA_def_property_enum_items(prop, rna_enum_fcurve_auto_smoothing_items); RNA_def_property_ui_text( prop, "Auto Handle Smoothing", "Algorithm used to compute automatic handles"); RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FCurve_update_data"); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 3ad18fcc7a3..2601600c6ee 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1457,6 +1457,12 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) prop, "Solo Mode", "In Paint mode display only layers with keyframe in current frame"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Layer is used as Ruler. */ + prop = RNA_def_property(srna, "is_ruler", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_IS_RULER); + RNA_def_property_ui_text(prop, "Ruler", "This is a special ruler layer"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* exposed as layers.active */ # if 0 prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index bab7375f01b..40c6229f9b1 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -123,18 +123,13 @@ static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create) static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C) { View3D *v3d = CTX_wm_view3d(C); - const bool runtime_visible = (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE) != 0; - if (v3d == NULL) { - return runtime_visible; - } - - if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) { - return runtime_visible; + if ((v3d == NULL) || ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0)) { + return (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER) != 0; } if (v3d->local_collections_uuid & layer_collection->local_collections_bits) { - return true; + return (layer_collection->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) == 0; } return false; @@ -192,15 +187,24 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po iter, &view_layer->object_bases, rna_ViewLayer_objects_selected_skip); } -static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main *bmain) +static void rna_ViewLayer_update_tagged(ID *id_ptr, + ViewLayer *view_layer, + Main *bmain, + ReportList *reports) { + Scene *scene = (Scene *)id_ptr; + Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); + + if (DEG_is_evaluating(depsgraph)) { + BKE_report(reports, RPT_ERROR, "Dependency graph update requested during evaluation"); + return; + } + # ifdef WITH_PYTHON /* Allow drivers to be evaluated */ BPy_BEGIN_ALLOW_THREADS; # endif - Scene *scene = (Scene *)id_ptr; - Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); /* NOTE: This is similar to CTX_data_depsgraph_pointer(). Ideally such access would be * de-duplicated across all possible cases, but for now this is safest and easiest way to go. * @@ -415,12 +419,12 @@ static void rna_def_layer_collection(BlenderRNA *brna) /* Run-time flags. */ prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE); + RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE_VIEW_LAYER); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text( - prop, - "Visible", - "Whether this collection is visible, take into account the collection parent"); + RNA_def_property_ui_text(prop, + "Visible", + "Whether this collection is visible for the viewlayer, take into " + "account the collection parent"); func = RNA_def_function(srna, "has_objects", "rna_LayerCollection_has_objects"); RNA_def_function_ui_description(func, ""); @@ -573,7 +577,7 @@ void RNA_def_view_layer(BlenderRNA *brna) /* debug update routine */ func = RNA_def_function(srna, "update", "rna_ViewLayer_update_tagged"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); RNA_def_function_ui_description( func, "Update data tagged to be updated from previous access to data or operators"); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index fec991e16da..2c42dba9131 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -461,8 +461,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, "Cannot read '%s': %s", filepath, errno ? strerror(errno) : TIP_("unsupported font format")); - - id_us_min((ID *)font); } return font; } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 9da17c5f0b1..a29031900ac 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -41,7 +41,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { {0, "", ICON_NONE, NULL, NULL}, {MA_RAMP_LIGHT, "LIGHTEN", 0, "Lighten", ""}, {MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""}, - {MA_RAMP_DODGE, "DODGE", 0, "Dodge", ""}, + {MA_RAMP_DODGE, "DODGE", 0, "Color Dodge", ""}, {MA_RAMP_ADD, "ADD", 0, "Add", ""}, {0, "", ICON_NONE, NULL, NULL}, {MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""}, diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 48562cf2684..287c7502c41 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3986,7 +3986,7 @@ static void def_mix_rgb(StructRNA *srna) prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items); - RNA_def_property_ui_text(prop, "Blend Type", ""); + RNA_def_property_ui_text(prop, "Blending Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 56d25f5bebf..babf388bfc7 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -70,6 +70,7 @@ static const EnumPropertyItem space_items[] = { # include "BKE_customdata.h" # include "BKE_font.h" # include "BKE_global.h" +# include "BKE_layer.h" # include "BKE_main.h" # include "BKE_mesh.h" # include "BKE_mball.h" @@ -283,6 +284,11 @@ static void rna_Object_local_view_set(Object *ob, } } +static bool rna_Object_visible_in_viewport_get(Object *ob, View3D *v3d) +{ + return BKE_object_is_visible_in_viewport(v3d, ob); +} + /* Convert a given matrix from a space to another (using the object and/or a bone as * reference). */ static void rna_Object_mat_convert_space(Object *ob, @@ -825,6 +831,15 @@ void RNA_api_object(StructRNA *srna) parm = RNA_def_boolean(func, "state", 0, "", "Local view state to define"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* Viewport */ + func = RNA_def_function(srna, "visible_in_viewport_get", "rna_Object_visible_in_viewport_get"); + RNA_def_function_ui_description( + func, "Check for local view and local collections for this viewport and object"); + parm = RNA_def_pointer(func, "viewport", "SpaceView3D", "", "Viewport in local collections"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, "result", 0, "", "Object viewport visibility"); + RNA_def_function_return(func, parm); + /* Matrix space conversion */ func = RNA_def_function(srna, "convert_space", "rna_Object_mat_convert_space"); RNA_def_function_ui_description( diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 0f8f8d39c41..8c4b7dd52d9 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -648,7 +648,7 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain), /* Remember that insertion operations are defined and stored in correct order, which means that * even if we insert several items in a row, we always insert first one, then second one, etc. - * So we should always find 'anchor' constraint in both _src *and* _dst> */ + * So we should always find 'anchor' constraint in both _src *and* _dst */ bConstraint *con_anchor = NULL; if (opop->subitem_local_name && opop->subitem_local_name[0]) { con_anchor = BLI_findstring( @@ -669,7 +669,11 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain), } con_src = con_src ? con_src->next : pchan_src->constraints.first; - BLI_assert(con_src != NULL); + if (con_src == NULL) { + printf("%s: Could not find constraint to insert, doing nothing...\n", __func__); + BLI_assert(0); + return false; + } bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 26c8df4c7bb..4db702b215f 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1157,20 +1157,21 @@ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *prop *r_is_id = *r_is_null = *r_is_type_diff = false; /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */ - if (propptr_a->type == NULL) { - if (propptr_b == NULL || propptr_b->type == NULL) { + if (ELEM(NULL, propptr_a->type, propptr_a->data)) { + if (ELEM(NULL, propptr_b, propptr_b->type, propptr_b->data)) { *r_is_null = true; } else { *r_is_id = RNA_struct_is_ID(propptr_b->type); *r_is_null = true; - *r_is_type_diff = true; + *r_is_type_diff = propptr_a->type != propptr_b->type; } is_valid_for_diffing = false; } else { *r_is_id = RNA_struct_is_ID(propptr_a->type); - *r_is_null = *r_is_type_diff = (ELEM(NULL, propptr_b, propptr_b->type)); + *r_is_null = (ELEM(NULL, propptr_b, propptr_b->type, propptr_b->data)); + *r_is_type_diff = (propptr_b == NULL || propptr_b->type != propptr_a->type); is_valid_for_diffing = !(*r_is_id || *r_is_null); } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 1f967df7232..ef97b184491 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5683,7 +5683,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "frs_sec_base"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 1e-5f, 1e6f); - RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, -1); + /* Important to show at least 3 decimal points because multiple presets set this to 1.001. */ + RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, 3); RNA_def_property_ui_text(prop, "FPS Base", "Framerate base"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 2b1b23a40f4..8a06d594c1f 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -88,7 +88,11 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf BPy_END_ALLOW_THREADS; # endif - BKE_scene_camera_switch_update(scene); + if (BKE_scene_camera_switch_update(scene)) { + for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) { + BKE_screen_view3d_scene_sync(sc, scene); + } + } /* don't do notifier when we're rendering, avoid some viewport crashes * redrawing while the data is being modified for render */ diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 728ef3fb706..1637f8cfed5 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -272,7 +272,7 @@ static void rna_Area_ui_type_update(bContext *C, PointerRNA *ptr) sa->butspacetype_subtype = 0; } -static void rna_View2D_region_to_view(struct View2D *v2d, int x, int y, float result[2]) +static void rna_View2D_region_to_view(struct View2D *v2d, float x, float y, float result[2]) { UI_view2d_region_to_view(v2d, x, y, &result[0], &result[1]); } @@ -406,9 +406,9 @@ static void rna_def_view2d_api(StructRNA *srna) func = RNA_def_function(srna, "region_to_view", "rna_View2D_region_to_view"); RNA_def_function_ui_description(func, "Transform region coordinates to 2D view"); - parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000); + parm = RNA_def_float(func, "x", 0, -FLT_MAX, FLT_MAX, "x", "Region x coordinate", -10000, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000); + parm = RNA_def_float(func, "y", 0, -FLT_MAX, FLT_MAX, "y", "Region y coordinate", -10000, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float_array(func, "result", diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index dc0cc0482aa..31ead989f25 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1462,7 +1462,7 @@ static const EnumPropertyItem blend_mode_items[] = { {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, - {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""}, + {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""}, {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, @@ -1723,7 +1723,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "blend_mode"); RNA_def_property_enum_items(prop, blend_mode_items); RNA_def_property_ui_text( - prop, "Blend Mode", "Method for controlling how the strip combines with other strips"); + prop, "Blending Mode", "Method for controlling how the strip combines with other strips"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); @@ -2225,7 +2225,7 @@ static void rna_def_scene(BlenderRNA *brna) RNA_def_struct_sdna(srna, "Sequence"); prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); RNA_def_property_ui_text(prop, "Scene", "Scene that this sequence uses"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); @@ -2785,27 +2785,31 @@ static void rna_def_text(StructRNA *srna) static void rna_def_color_mix(StructRNA *srna) { static EnumPropertyItem blend_color_items[] = { - {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, - {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""}, + {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""}, {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""}, + {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""}, + {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, + {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, - {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""}, {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, + {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""}, + {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, + {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, - {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""}, - {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""}, - {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""}, {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""}, - {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, - {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""}, - {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, + {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, + {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, + {0, "", ICON_NONE, NULL, NULL}, + {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, + {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, + {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""}, + {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""}, {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""}, + {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, {SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""}, - {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, - {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2817,7 +2821,7 @@ static void rna_def_color_mix(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "blend_effect"); RNA_def_property_enum_items(prop, blend_color_items); RNA_def_property_ui_text( - prop, "Blend Effect", "Method for controlling how the strip combines with other strips"); + prop, "Blending Mode", "Method for controlling how the strip combines with other strips"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 56ba6403596..1b2adfd28c6 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -589,7 +589,7 @@ static void rna_Space_bool_from_region_flag_set_by_type(PointerRNA *ptr, { ScrArea *sa = rna_area_from_space(ptr); ARegion *ar = BKE_area_find_region_type(sa, region_type); - if (ar) { + if (ar && (ar->alignment != RGN_ALIGN_NONE)) { SET_FLAG_FROM_TEST(ar->flag, value, region_flag); } ED_region_tag_redraw(ar); @@ -787,13 +787,18 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain), static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { + bool changed = false; /* need set all caches as dirty to recalculate onion skinning */ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { if (ob->type == OB_GPENCIL) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + bGPdata *gpd = (bGPdata *)ob->data; + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); + changed = true; } } - WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); + if (changed) { + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); + } } /* Space 3D View */ @@ -1105,7 +1110,7 @@ static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUS } else { /* Solid mode, or lookdev mode for workbench engine. */ - r_free = false; + *r_free = false; return rna_enum_shading_color_type_items; } } diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index 64a23dfa985..778e817c73e 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -87,8 +87,60 @@ static int rna_Text_current_line_index_get(PointerRNA *ptr) static void rna_Text_current_line_index_set(PointerRNA *ptr, int value) { - Text *text = (Text *)ptr->data; - txt_move_toline(text, value, 0); + Text *text = ptr->data; + TextLine *line = BLI_findlink(&text->lines, value); + if (line == NULL) { + line = text->lines.last; + } + text->curl = line; + text->curc = 0; +} + +static int rna_Text_select_end_line_index_get(PointerRNA *ptr) +{ + Text *text = ptr->data; + return BLI_findindex(&text->lines, text->sell); +} + +static void rna_Text_select_end_line_index_set(PointerRNA *ptr, int value) +{ + Text *text = ptr->data; + TextLine *line = BLI_findlink(&text->lines, value); + if (line == NULL) { + line = text->lines.last; + } + text->sell = line; + text->selc = 0; +} + +static int rna_Text_current_character_get(PointerRNA *ptr) +{ + Text *text = ptr->data; + return BLI_str_utf8_offset_to_index(text->curl->line, text->curc); +} + +static void rna_Text_current_character_set(PointerRNA *ptr, int index) +{ + Text *text = ptr->data; + TextLine *line = text->curl; + const int len_utf8 = BLI_strlen_utf8(line->line); + CLAMP_MAX(index, len_utf8); + text->curc = BLI_str_utf8_offset_from_index(line->line, index); +} + +static int rna_Text_select_end_character_get(PointerRNA *ptr) +{ + Text *text = ptr->data; + return BLI_str_utf8_offset_to_index(text->sell->line, text->selc); +} + +static void rna_Text_select_end_character_set(PointerRNA *ptr, int index) +{ + Text *text = ptr->data; + TextLine *line = text->sell; + const int len_utf8 = BLI_strlen_utf8(line->line); + CLAMP_MAX(index, len_utf8); + text->selc = BLI_str_utf8_offset_from_index(line->line, index); } static void rna_TextLine_body_get(PointerRNA *ptr, char *value) @@ -209,12 +261,14 @@ static void rna_def_text(BlenderRNA *brna) prop, "Current Line", "Current line, and start line of selection if one exists"); prop = RNA_def_property(srna, "current_character", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "curc"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "Current Character", "Index of current character in current line, and also start index of " "character in selection if one exists"); + RNA_def_property_int_funcs( + prop, "rna_Text_current_character_get", "rna_Text_current_character_set", NULL); + RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL); prop = RNA_def_property(srna, "current_line_index", PROP_INT, PROP_NONE); RNA_def_property_int_funcs( @@ -230,12 +284,20 @@ static void rna_def_text(BlenderRNA *brna) RNA_def_property_struct_type(prop, "TextLine"); RNA_def_property_ui_text(prop, "Selection End Line", "End line of selection"); + prop = RNA_def_property(srna, "select_end_line_index", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs( + prop, "rna_Text_select_end_line_index_get", "rna_Text_select_end_line_index_set", NULL); + RNA_def_property_ui_text(prop, "Select End Line Index", "Index of last TextLine in selection"); + RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL); + prop = RNA_def_property(srna, "select_end_character", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "selc"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "Selection End Character", "Index of character after end of selection in the selection end line"); + RNA_def_property_int_funcs( + prop, "rna_Text_select_end_character_get", "rna_Text_select_end_character_set", NULL); + RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL); RNA_api_text(srna); } diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c index 524dcfa9ad7..000076eccec 100644 --- a/source/blender/makesrna/intern/rna_text_api.c +++ b/source/blender/makesrna/intern/rna_text_api.c @@ -46,6 +46,18 @@ static void rna_Text_write(Text *text, const char *str) WM_main_add_notifier(NC_TEXT | NA_EDITED, text); } +static void rna_Text_select_set(Text *text, int startl, int startc, int endl, int endc) +{ + txt_sel_set(text, startl, startc, endl, endc); + WM_main_add_notifier(NC_TEXT | NA_EDITED, text); +} + +static void rna_Text_cursor_set(Text *text, int line, int ch, bool select) +{ + txt_move_to(text, line, ch, select); + WM_main_add_notifier(NC_TEXT | NA_EDITED, text); +} + #else void RNA_api_text(StructRNA *srna) @@ -69,6 +81,25 @@ void RNA_api_text(StructRNA *srna) RNA_def_function_ui_description(func, "Returns True if the editor supports syntax highlighting " "for the current text datablock"); + + func = RNA_def_function(srna, "select_set", "rna_Text_select_set"); + RNA_def_function_ui_description(func, "Set selection range by line and character index"); + parm = RNA_def_int(func, "line_start", 0, INT_MIN, INT_MAX, "Start Line", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int( + func, "char_start", 0, INT_MIN, INT_MAX, "Start Character", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "line_end", 0, INT_MIN, INT_MAX, "End Line", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "char_end", 0, INT_MIN, INT_MAX, "End Character", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "cursor_set", "rna_Text_cursor_set"); + RNA_def_function_ui_description(func, "Set cursor by line and (optionally) character index"); + parm = RNA_def_int(func, "line", 0, 0, INT_MAX, "Line", "", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "character", 0, 0, INT_MAX, "Character", "", 0, INT_MAX); + RNA_def_boolean(func, "select", false, "", "Select when moving the cursor"); } #endif diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index c9b6f46ab04..07ce07710b1 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -424,6 +424,17 @@ static void rna_userdef_timecode_style_set(PointerRNA *ptr, int value) } } +static int rna_UserDef_mouse_emulate_3_button_modifier_get(PointerRNA *ptr) +{ +# if !defined(WIN32) + UserDef *userdef = ptr->data; + return userdef->mouse_emulate_3_button_modifier; +# else + UNUSED_VARS(ptr); + return USER_EMU_MMB_MOD_ALT; +# endif +} + static PointerRNA rna_UserDef_view_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_PreferencesView, ptr->data); @@ -3190,6 +3201,18 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna) RNA_def_property_ui_text(prop, "View Sliders", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "dopesheet_channel", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "ds_channel"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Channel", "Nonlinear Animation Channel"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "nla_track", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "nla_track"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Track", "Nonlinear Animation Track"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "active_action", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "anim_active"); RNA_def_property_array(prop, 4); @@ -4634,6 +4657,13 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "Color for newly added transformation F-Curves (Location, Rotation, Scale) " "and also Color is based on the transform axis"); + prop = RNA_def_property(srna, "fcurve_new_auto_smoothing", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_fcurve_auto_smoothing_items); + RNA_def_property_enum_sdna(prop, NULL, "auto_smoothing_new"); + RNA_def_property_ui_text(prop, + "New Curve Smoothing Mode", + "Auto Handle Smoothing mode used for newly added F-Curves"); + prop = RNA_def_property(srna, "keyframe_new_interpolation_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_mode_items); RNA_def_property_enum_sdna(prop, NULL, "ipo_new"); @@ -5487,6 +5517,21 @@ static void rna_def_userdef_input(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, 0, "rna_userdef_keyconfig_reload_update"); + static const EnumPropertyItem mouse_emulate_3_button_modifier[] = { + {USER_EMU_MMB_MOD_ALT, "ALT", 0, "Alt", ""}, + {USER_EMU_MMB_MOD_OSKEY, "OSKEY", 0, "OS-Key", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + prop = RNA_def_property(srna, "mouse_emulate_3_button_modifier", PROP_ENUM, PROP_NONE); + /* Only needed because of WIN32 inability to support the option. */ + RNA_def_property_enum_funcs(prop, "rna_UserDef_mouse_emulate_3_button_modifier_get", NULL, NULL); + RNA_def_property_enum_items(prop, mouse_emulate_3_button_modifier); + RNA_def_property_ui_text( + prop, "Emulate 3 Button Modifier", "Hold this modifier to emulate the middle mouse button"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, 0, "rna_userdef_keyconfig_reload_update"); + prop = RNA_def_property(srna, "use_emulate_numpad", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_NONUMPAD); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c index b8c6a25ace8..f22c86b3ff2 100644 --- a/source/blender/makesrna/intern/rna_workspace_api.c +++ b/source/blender/makesrna/intern/rna_workspace_api.c @@ -110,7 +110,7 @@ void RNA_api_workspace(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - func = RNA_def_function(srna, "status_text_set", "ED_workspace_status_text"); + func = RNA_def_function(srna, "status_text_set_internal", "ED_workspace_status_text"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); RNA_def_function_ui_description( func, "Set the status bar text, typically key shortcuts for modal operators"); diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 53bb579128a..883c17aa1e1 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -228,16 +228,22 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes return result; } -static void deformVerts(ModifierData *md, - const ModifierEvalContext *UNUSED(ctx), - Mesh *mesh, - float (*vertex_cos)[3], - int num_verts) +static void deformMatrices(ModifierData *md, + const ModifierEvalContext *UNUSED(ctx), + Mesh *mesh, + float (*vertex_cos)[3], + float (*deform_matrices)[3][3], + int num_verts) + { #if !defined(WITH_OPENSUBDIV) modifier_setError(md, "Disabled, built without OpenSubdiv"); return; #endif + + /* Subsurf does not require extra space mapping, keep matrices as is. */ + (void)deform_matrices; + MultiresModifierData *mmd = (MultiresModifierData *)md; SubdivSettings subdiv_settings; BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); @@ -268,8 +274,8 @@ ModifierTypeInfo modifierType_Multires = { /* copyData */ copyData, - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, + /* deformVerts */ NULL, + /* deformMatrices */ deformMatrices, /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 55df1b5ddda..4a5887c3122 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -241,16 +241,21 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes return result; } -static void deformVerts(ModifierData *md, - const ModifierEvalContext *UNUSED(ctx), - Mesh *mesh, - float (*vertex_cos)[3], - int num_verts) +static void deformMatrices(ModifierData *md, + const ModifierEvalContext *UNUSED(ctx), + Mesh *mesh, + float (*vertex_cos)[3], + float (*deform_matrices)[3][3], + int num_verts) { #if !defined(WITH_OPENSUBDIV) modifier_setError(md, "Disabled, built without OpenSubdiv"); return; #endif + + /* Subsurf does not require extra space mapping, keep matrices as is. */ + (void)deform_matrices; + SubsurfModifierData *smd = (SubsurfModifierData *)md; SubdivSettings subdiv_settings; subdiv_settings_init(&subdiv_settings, smd); @@ -281,8 +286,8 @@ ModifierTypeInfo modifierType_Subsurf = { /* copyData */ copyData, - /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, + /* deformVerts */ NULL, + /* deformMatrices */ deformMatrices, /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 92266600612..4bcd77496c1 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -412,7 +412,8 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode) BLI_remlink(&ngroup->nodes, node); BLI_addtail(&ntree->nodes, node); /* ensure unique node name in the node tree */ - nodeUniqueName(ntree, node); + /* This is very slow and it has no use for GPU nodetree. (see T70609) */ + // nodeUniqueName(ntree, node); } /* Save first and last link to iterate over flattened group links. */ @@ -441,6 +442,8 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode) } } } + /* Also iterate over the new links to cover passthrough links. */ + glinks_last = ntree->links.last; /* output links */ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) { if (tlink->fromnode == gnode) { @@ -626,7 +629,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, /* Count and tag all nodes inside the displacement branch of the tree. */ start_node->tmp_flag = 0; int node_count = 1; - nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count); + nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1); /* Make a full copy of the branch */ bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -760,13 +763,13 @@ static void node_tag_branch_as_derivative(bNode *node, int dx) } } -static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode), bNode *tonode, void *userdata) +static bool ntree_shader_bump_branches(bNode *fromnode, bNode *UNUSED(tonode), void *userdata) { bNodeTree *ntree = (bNodeTree *)userdata; - if (tonode->type == SH_NODE_BUMP) { + if (fromnode->type == SH_NODE_BUMP) { bNodeSocket *height_dx_sock, *height_dy_sock, *bump_socket, *bump_dx_socket, *bump_dy_socket; - bNode *bump = tonode; + bNode *bump = fromnode; bump_socket = ntree_shader_node_find_input(bump, "Height"); bump_dx_socket = ntree_shader_node_find_input(bump, "Height_dx"); bump_dy_socket = ntree_shader_node_find_input(bump, "Height_dy"); @@ -829,7 +832,7 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag /* Make sure sockets links pointers are correct. */ ntreeUpdateTree(G.main, ntree); - nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags); + nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0); } /* This one needs to work on a local tree. */ @@ -858,7 +861,7 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, /* Duplicate bump height branches for manual derivatives. */ - nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree); + nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0); /* TODO(fclem): consider moving this to the gpu shader tree evaluation. */ nTreeTags tags = { diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c index d94141c3699..3798cfbbfac 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.c +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c @@ -47,17 +47,32 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, /* Opti: don't request orco if not needed. */ GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) : GPU_attribute(CD_ORCO, ""); - return GPU_stack_link(mat, - node, - "node_geometry", - in, - out, - GPU_builtin(GPU_VIEW_POSITION), - GPU_builtin(GPU_WORLD_NORMAL), - orco_link, - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - bary_link); + const bool success = GPU_stack_link(mat, + node, + "node_geometry", + in, + out, + GPU_builtin(GPU_VIEW_POSITION), + GPU_builtin(GPU_WORLD_NORMAL), + orco_link, + GPU_builtin(GPU_OBJECT_MATRIX), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), + bary_link); + + /* for each output */ + for (int i = 0; sh_node_geometry_out[i].type != -1; i++) { + node_shader_gpu_bump_tex_coord(mat, node, &out[i].link); + /* Normalize some vectors after dFdx/dFdy offsets. + * This is the case for interpolated, non linear functions. + * The resulting vector can still be a bit wrong but not as much. + * (see T70644) */ + if (node->branch_tag != 0 && ELEM(i, 1, 2, 4)) { + GPU_link( + mat, "vector_math_normalize", out[i].link, out[i].link, out[i].link, &out[i].link, NULL); + } + } + + return success; } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c index 068458b7e1f..8bb17acc4d3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c @@ -63,6 +63,14 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, /* for each output. */ for (int i = 0; sh_node_tex_coord_out[i].type != -1; i++) { node_shader_gpu_bump_tex_coord(mat, node, &out[i].link); + /* Normalize some vectors after dFdx/dFdy offsets. + * This is the case for interpolated, non linear functions. + * The resulting vector can still be a bit wrong but not as much. + * (see T70644) */ + if (node->branch_tag != 0 && ELEM(i, 1, 6)) { + GPU_link( + mat, "vector_math_normalize", out[i].link, out[i].link, out[i].link, &out[i].link, NULL); + } } return 1; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c index daf4053f182..56e102a118d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c @@ -136,8 +136,8 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL && tex->musgrave_type != SHD_MUSGRAVE_FBM); nodeSetSocketAvailability(inGainSock, - tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL && - tex->musgrave_type != SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); + tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL || + tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); } void register_node_type_sh_tex_musgrave(void) diff --git a/source/blender/python/bmesh/bmesh_py_ops.c b/source/blender/python/bmesh/bmesh_py_ops.c index fd37c8521c1..b6ba119f695 100644 --- a/source/blender/python/bmesh/bmesh_py_ops.c +++ b/source/blender/python/bmesh/bmesh_py_ops.c @@ -166,10 +166,10 @@ static PyTypeObject bmesh_op_Type = { sizeof(BPy_BMeshOpFunc), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ (reprfunc)bpy_bmesh_op_repr, /* tp_repr */ @@ -282,10 +282,10 @@ static PyTypeObject bmesh_ops_fakemod_Type = { 0, /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ NULL, /* tp_repr */ diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index b90483e89b9..62f5a568ee1 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -20,6 +20,9 @@ * This file defines the 'bgl' module, used for drawing text in OpenGL. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include "blf_py_api.h" @@ -176,7 +179,7 @@ PyDoc_STRVAR(py_blf_draw_doc, static PyObject *py_blf_draw(PyObject *UNUSED(self), PyObject *args) { const char *text; - int text_length; + Py_ssize_t text_length; int fontid; if (!PyArg_ParseTuple(args, "is#:blf.draw", &fontid, &text, &text_length)) { diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 335dea0a2b6..1ea7795a0e3 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -1172,7 +1172,7 @@ PyTypeObject BPy_IDGroup_Type = { /* Methods to implement standard operations */ NULL, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ @@ -1577,7 +1577,7 @@ PyTypeObject BPy_IDArray_Type = { /* Methods to implement standard operations */ NULL, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ @@ -1692,7 +1692,7 @@ PyTypeObject BPy_IDGroup_Iter_Type = { /* Methods to implement standard operations */ NULL, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c index 6a7f899488b..d35fc027f43 100644 --- a/source/blender/python/generic/imbuf_py_api.c +++ b/source/blender/python/generic/imbuf_py_api.c @@ -348,7 +348,7 @@ PyTypeObject Py_ImBuf_Type = { /* Methods to implement standard operations */ (destructor)py_imbuf_dealloc, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index a6983c38f0e..c85a1d9ba05 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -25,9 +25,18 @@ * BLI_string_utf8() for unicode conversion. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include <frameobject.h> +/* Needed for 'PyInterpreterState', we should remove this dependency. */ +#if PY_VERSION_HEX >= 0x03080000 +# define Py_BUILD_CORE +# include <internal/pycore_pystate.h> +#endif + #include "BLI_utildefines.h" /* for bool */ #include "py_capi_utils.h" @@ -867,7 +876,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) va_list vargs; - int *sizes = PyMem_MALLOC(sizeof(int) * (n / 2)); + Py_ssize_t *sizes = PyMem_MALLOC(sizeof(*sizes) * (n / 2)); int i; PyObject *py_dict = PyC_DefaultNameSpace(filepath); diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 70f76896898..6505e59624b 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -183,7 +183,7 @@ static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyDoc_STRVAR( bpygpu_offscreen_draw_view3d_doc, - ".. method:: draw_view3d(scene, view3d, region, view_matrix, projection_matrix)\n" + ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix)\n" "\n" " Draw the 3d viewport in the offscreen object.\n" "\n" diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c index 3c1dbfba72e..fffa43c1dcd 100644 --- a/source/blender/python/intern/bpy_app_translations.c +++ b/source/blender/python/intern/bpy_app_translations.c @@ -780,10 +780,10 @@ static PyTypeObject BlenderAppTranslationsType = { 0, /* tp_itemsize */ /* methods */ /* No destructor, this is a singleton! */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ NULL, /* tp_repr */ diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 5ea16c8c197..b797624f23c 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -92,7 +92,7 @@ static PyTypeObject bpy_lib_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)bpy_lib_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 6b63d1ef2c3..4fd81a707fb 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -22,6 +22,9 @@ * existing blender types. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include "RNA_types.h" @@ -2101,7 +2104,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; bool def = false; PropertyRNA *prop; PyObject *pyopts = NULL; @@ -2204,7 +2207,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; bool def[PYRNA_STACK_ARRAY] = {0}; int size = 3; PropertyRNA *prop; @@ -2336,7 +2339,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1, def = 0; PropertyRNA *prop; PyObject *pyopts = NULL; @@ -2456,7 +2459,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1; int def[PYRNA_STACK_ARRAY] = {0}; int size = 3; @@ -2599,7 +2602,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3, def = 0.0f; int precision = 2; @@ -2735,7 +2738,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3; float def[PYRNA_STACK_ARRAY] = {0.0f}; int precision = 2, size = 3; @@ -2869,7 +2872,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw if (srna) { const char *id = NULL, *name = NULL, *description = "", *def = ""; - int id_len; + Py_ssize_t id_len; int maxlen = 0; PropertyRNA *prop; PyObject *pyopts = NULL; @@ -3015,7 +3018,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; PyObject *def = NULL; - int id_len; + Py_ssize_t id_len; int defvalue = 0; PyObject *items, *items_fast; const EnumPropertyItem *eitems; @@ -3191,7 +3194,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; PropertyRNA *prop; StructRNA *ptype; PyObject *type = Py_None; @@ -3286,7 +3289,7 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(CollectionProperty); if (srna) { - int id_len; + Py_ssize_t id_len; const char *id = NULL, *name = NULL, *description = ""; PropertyRNA *prop; StructRNA *ptype; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 45a7d2dacd1..570c5012ed8 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -70,6 +70,8 @@ /* Only for types. */ #include "BKE_node.h" +#include "DEG_depsgraph_query.h" + #include "../generic/idprop_py_api.h" /* For IDprop lookups. */ #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" @@ -918,7 +920,10 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self) tmp_str = PyUnicode_FromString(id->name + 2); - if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) { + if (DEG_get_original_id(id) != id) { + ret = PyUnicode_FromFormat("Evaluated %s %R", BKE_idcode_to_name(GS(id->name)), tmp_str); + } + else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) { ret = PyUnicode_FromFormat( "bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str); } @@ -926,14 +931,25 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self) const char *path; ID *real_id = NULL; path = RNA_path_from_real_ID_to_struct(G_MAIN, &self->ptr, &real_id); - if (path) { - if (real_id != id) { + if (path != NULL) { + /* 'real_id' may be NULL in some cases, although the only valid one is evaluated data, + * which should have already been caught above. + * So assert, but handle it without crashing for release builds. */ + BLI_assert(real_id != NULL); + + if (real_id != NULL) { Py_DECREF(tmp_str); tmp_str = PyUnicode_FromString(real_id->name + 2); + ret = PyUnicode_FromFormat( + "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path); + } + else { + /* Can't find the path, print something useful as a fallback. */ + ret = PyUnicode_FromFormat("bpy.data.%s[%R]...%s", + BKE_idcode_to_name_plural(GS(id->name)), + tmp_str, + RNA_struct_identifier(self->ptr.type)); } - ret = PyUnicode_FromFormat( - "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path); - MEM_freeN((void *)path); } else { @@ -6221,10 +6237,10 @@ PyTypeObject pyrna_struct_meta_idprop_Type = { 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* deprecated in Python 3.0! */ NULL, /* tp_repr */ @@ -6303,7 +6319,7 @@ PyTypeObject pyrna_struct_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_struct_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6392,7 +6408,7 @@ PyTypeObject pyrna_prop_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6476,7 +6492,7 @@ PyTypeObject pyrna_prop_array_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_array_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6559,7 +6575,7 @@ PyTypeObject pyrna_prop_collection_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6645,7 +6661,7 @@ static PyTypeObject pyrna_prop_collection_idprop_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6730,10 +6746,10 @@ PyTypeObject pyrna_func_Type = { sizeof(BPy_FunctionRNA), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in Python 3.0! */ (reprfunc)pyrna_func_repr, /* tp_repr */ @@ -6827,7 +6843,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_collection_iter_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c index 4e21a8e0389..b587738c8d7 100644 --- a/source/blender/python/mathutils/mathutils_Color.c +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -921,7 +921,7 @@ PyTypeObject color_Type = { sizeof(ColorObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)BaseMathObject_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index 56662465b52..3fd9bf666e2 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -750,7 +750,7 @@ PyTypeObject euler_Type = { sizeof(EulerObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)BaseMathObject_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 6fd0fab2cdd..c6e6d395b6b 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -3141,7 +3141,7 @@ PyTypeObject matrix_Type = { sizeof(MatrixObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)BaseMathObject_dealloc, /*tp_dealloc*/ - NULL, /*tp_print*/ + (printfunc)NULL, /*tp_print*/ NULL, /*tp_getattr*/ NULL, /*tp_setattr*/ NULL, /*tp_compare*/ @@ -3532,7 +3532,7 @@ PyTypeObject matrix_access_Type = { sizeof(MatrixAccessObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)MatrixAccess_dealloc, /*tp_dealloc*/ - NULL, /*tp_print*/ + (printfunc)NULL, /*tp_print*/ NULL, /*tp_getattr*/ NULL, /*tp_setattr*/ NULL, /*tp_compare*/ diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 2b3aa29a366..0de1ffb9879 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -1527,7 +1527,7 @@ PyTypeObject quaternion_Type = { sizeof(QuaternionObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)BaseMathObject_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 0555c707ed3..387e560d946 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -3055,7 +3055,7 @@ PyTypeObject vector_Type = { /* Methods to implement standard operations */ (destructor)BaseMathObject_dealloc, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 254177b14fe..d28b9a0de8f 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -1267,7 +1267,7 @@ PyTypeObject PyBVHTree_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)py_bvhtree__tp_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 13d36e5af91..9a519abd49f 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -1201,8 +1201,8 @@ static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject PyDoc_STRVAR(M_Geometry_tessellate_polygon_doc, ".. function:: tessellate_polygon(veclist_list)\n" "\n" - " Takes a list of polylines (each point a vector) and returns the point indices " - "for a polyline filled with triangles.\n" + " Takes a list of polylines (each point a pair or triplet of numbers) and returns " + "the point indices for a polyline filled with triangles.\n" "\n" " :arg veclist_list: list of polylines\n" " :rtype: list\n"); @@ -1211,13 +1211,15 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject { PyObject *tri_list; /*return this list of tri's */ PyObject *polyLine, *polyVec; - int i, len_polylines, len_polypoints, ls_error = 0; + int i, len_polylines, len_polypoints; + bool list_parse_error = false; + bool is_2d = true; /* Display #ListBase. */ ListBase dispbase = {NULL, NULL}; DispList *dl; float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ - int index, *dl_face, totpoints = 0; + int totpoints = 0; if (!PySequence_Check(polyLineSeq)) { PyErr_SetString(PyExc_TypeError, "expected a sequence of poly lines"); @@ -1238,15 +1240,6 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject len_polypoints = PySequence_Size(polyLine); if (len_polypoints > 0) { /* don't bother adding edges as polylines */ -# if 0 - if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) { - freedisplist(&dispbase); - Py_DECREF(polyLine); - PyErr_SetString(PyExc_TypeError, - "A point in one of the polylines is not a mathutils.Vector type"); - return NULL; - } -# endif dl = MEM_callocN(sizeof(DispList), "poly disp"); BLI_addtail(&dispbase, dl); dl->type = DL_INDEX3; @@ -1254,49 +1247,38 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject dl->type = DL_POLY; dl->parts = 1; /* no faces, 1 edge loop */ dl->col = 0; /* no material */ - dl->verts = fp = MEM_callocN(sizeof(float) * 3 * len_polypoints, "dl verts"); - dl->index = MEM_callocN(sizeof(int) * 3 * len_polypoints, "dl index"); + dl->verts = fp = MEM_mallocN(sizeof(float[3]) * len_polypoints, "dl verts"); + dl->index = MEM_callocN(sizeof(int[3]) * len_polypoints, "dl index"); - for (index = 0; index < len_polypoints; index++, fp += 3) { + for (int index = 0; index < len_polypoints; index++, fp += 3) { polyVec = PySequence_GetItem(polyLine, index); - if (VectorObject_Check(polyVec)) { - - if (BaseMath_ReadCallback((VectorObject *)polyVec) == -1) { - ls_error = 1; - } + const int polyVec_len = mathutils_array_parse( + fp, 2, 3 | MU_ARRAY_SPILL, polyVec, "tessellate_polygon: parse coord"); + Py_DECREF(polyVec); - fp[0] = ((VectorObject *)polyVec)->vec[0]; - fp[1] = ((VectorObject *)polyVec)->vec[1]; - if (((VectorObject *)polyVec)->size > 2) { - fp[2] = ((VectorObject *)polyVec)->vec[2]; - } - else { - /* if its a 2d vector then set the z to be zero */ - fp[2] = 0.0f; - } + if (UNLIKELY(polyVec_len == -1)) { + list_parse_error = true; } - else { - ls_error = 1; + else if (polyVec_len == 2) { + fp[2] = 0.0f; + } + else if (polyVec_len == 3) { + is_2d = false; } totpoints++; - Py_DECREF(polyVec); } } Py_DECREF(polyLine); } - if (ls_error) { + if (list_parse_error) { BKE_displist_free(&dispbase); /* possible some dl was allocated */ - PyErr_SetString(PyExc_TypeError, - "A point in one of the polylines " - "is not a mathutils.Vector type"); return NULL; } else if (totpoints) { /* now make the list to return */ - /* TODO, add normal arg */ - BKE_displist_fill(&dispbase, &dispbase, NULL, false); + BKE_displist_fill(&dispbase, &dispbase, is_2d ? ((const float[3]){0, 0, -1}) : NULL, false); /* The faces are stored in a new DisplayList * that's added to the head of the #ListBase. */ @@ -1309,12 +1291,10 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject return NULL; } - index = 0; - dl_face = dl->index; - while (index < dl->parts) { + int *dl_face = dl->index; + for (int index = 0; index < dl->parts; index++) { PyList_SET_ITEM(tri_list, index, PyC_Tuple_Pack_I32(dl_face[0], dl_face[1], dl_face[2])); dl_face += 3; - index++; } BKE_displist_free(&dispbase); } diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c index b8a7f4d8708..65eac901df5 100644 --- a/source/blender/python/mathutils/mathutils_kdtree.c +++ b/source/blender/python/mathutils/mathutils_kdtree.c @@ -393,7 +393,7 @@ PyTypeObject PyKDTree_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)PyKDTree__tp_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index ddd0ddb46da..59f99a9ff88 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC intern/wm_operator_type.c intern/wm_operators.c intern/wm_panel_type.c + intern/wm_platform_support.c intern/wm_playanim.c intern/wm_splash_screen.c intern/wm_stereo.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 2d9fa9e5ab6..f8b6b5171da 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -156,8 +156,14 @@ void WM_opengl_context_activate(void *context); void WM_opengl_context_release(void *context); struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect); -struct wmWindow *WM_window_open_temp( - struct bContext *C, const char *title, int x, int y, int sizex, int sizey, int space_type); +struct wmWindow *WM_window_open_temp(struct bContext *C, + const char *title, + int x, + int y, + int sizex, + int sizey, + int space_type, + bool dialog); void WM_window_set_dpi(wmWindow *win); bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test); @@ -329,6 +335,12 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, /* operator api, default callbacks */ /* invoke callback, uses enum property named "type" */ +int WM_generic_select_modal(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event); +int WM_generic_select_invoke(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event); void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); int WM_operator_smooth_viewtx_get(const struct wmOperator *op); int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext); @@ -468,6 +480,7 @@ void WM_operator_properties_select_random(struct wmOperatorType *ot); int WM_operator_properties_select_random_seed_increment_get(wmOperator *op); void WM_operator_properties_select_operation(struct wmOperatorType *ot); void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot); +void WM_operator_properties_generic_select(struct wmOperatorType *ot); struct CheckerIntervalParams { int nth; /* bypass when set to zero */ int skip; diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 4b1abeceebb..8e796a7981a 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -192,6 +192,15 @@ void WM_cursor_set(wmWindow *win, int curs) GHOST_TStandardCursor ghost_cursor = convert_to_ghost_standard_cursor(curs); +#if !defined(_WIN32) && !defined(__APPLE__) + /* Workaround crosshair cursors with bad visibility in some cursor themes. + * Better solution would be to always use custom cursors and support DPI + * properly so that the cursors look as good as the native ones. */ + if (U.curssize && ghost_cursor == GHOST_kStandardCursorCrosshair) { + ghost_cursor = GHOST_kStandardCursorCustom; + } +#endif + if (ghost_cursor != GHOST_kStandardCursorCustom && GHOST_HasCursorShape(win->ghostwin, ghost_cursor)) { /* Use native GHOST cursor when available. */ @@ -695,38 +704,40 @@ void wm_init_cursor_data(void) /****************** Normal Cross Cursor ************************/ BEGIN_CURSOR_BLOCK; static char cross_sbm[] = { - 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, - 0x01, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, 0x00, 0x00, 0x80, 0x01, - 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x00, 0x00, 0x3e, 0x7c, 0x3e, 0x7c, 0x00, 0x00, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, + }; static char cross_smsk[] = { 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, - 0x03, 0x7f, 0xfe, 0x3f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfe, 0xc0, 0x03, + 0x03, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0xff, 0xff, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, }; static char cross_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x78, 0x1e, 0x00, - 0xfc, 0x1f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf8, 0x3f, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x40, 0x02, - 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x3f, 0xfc, 0x7f, 0xfe, 0x3f, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static char cross_lmsk[] = { - 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, - 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, - 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, - 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, + 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, + 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, + 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xc0, 0x03, + 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, + 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, + 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, }; static BCursor CrossCursor = { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 6b4327d5f44..a744cfb8c28 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2352,7 +2352,8 @@ static int wm_handler_fileselect_do(bContext *C, U.file_space_data.temp_win_sizex * UI_DPI_FAC, U.file_space_data.temp_win_sizey * UI_DPI_FAC, SPACE_FILE, - U.filebrowser_display_type))) { + U.filebrowser_display_type, + true))) { ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER); BLI_assert(area->spacetype == SPACE_FILE); @@ -2737,7 +2738,10 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers /* Clear the tool-tip whenever a key binding is handled, without this tool-tips * are kept when a modal operators starts (annoying but otherwise harmless). */ if (action & WM_HANDLER_BREAK) { - WM_tooltip_clear(C, CTX_wm_window(C)); + /* Window may be gone after file read. */ + if (CTX_wm_window(C) != NULL) { + WM_tooltip_clear(C, CTX_wm_window(C)); + } } } else if (handler_base->type == WM_HANDLER_TYPE_UI) { @@ -4210,19 +4214,31 @@ static void wm_eventemulation(wmEvent *event, bool test_only) if (U.flag & USER_TWOBUTTONMOUSE) { if (event->type == LEFTMOUSE) { - if (event->val == KM_PRESS && event->alt) { - event->type = MIDDLEMOUSE; - event->alt = 0; + short *mod = ( +#if !defined(WIN32) + (U.mouse_emulate_3_button_modifier == USER_EMU_MMB_MOD_OSKEY) ? &event->oskey : + &event->alt +#else + /* Disable for WIN32 for now because it accesses the start menu. */ + &event->alt +#endif + ); - if (!test_only) { - emulating_event = MIDDLEMOUSE; + if (event->val == KM_PRESS) { + if (*mod) { + *mod = 0; + event->type = MIDDLEMOUSE; + + if (!test_only) { + emulating_event = MIDDLEMOUSE; + } } } else if (event->val == KM_RELEASE) { /* only send middle-mouse release if emulated */ if (emulating_event == MIDDLEMOUSE) { event->type = MIDDLEMOUSE; - event->alt = 0; + *mod = 0; } if (!test_only) { diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 70d83153840..c8c35ba1bfc 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -99,6 +99,7 @@ #include "wm.h" #include "wm_files.h" #include "wm_window.h" +#include "wm_platform_support.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -314,6 +315,10 @@ void WM_init(bContext *C, int argc, const char **argv) #endif WM_init_opengl(G_MAIN); + if (!WM_platform_support_perform_checks()) { + exit(-1); + } + UI_init(); } diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index a8feb22cbf8..21636153904 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -396,6 +396,16 @@ void WM_operator_properties_select_operation_simple(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +void WM_operator_properties_generic_select(wmOperatorType *ot) +{ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "wait_to_deselect_others", false, "Wait to Deselect Others", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX); +} + void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot) { WM_operator_properties_border(ot); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 285379e90c6..292e27c3cbf 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -700,6 +700,82 @@ void WM_operator_properties_free(PointerRNA *ptr) /** \name Default Operator Callbacks * \{ */ +int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr, + "wait_to_deselect_others"); + const short init_event_type = (short)POINTER_AS_INT(op->customdata); + int ret_value = 0; + + /* get settings from RNA properties for operator */ + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + + if (init_event_type == 0) { + if (event->val == KM_PRESS) { + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, true); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + op->customdata = POINTER_FROM_INT((int)event->type); + if (ret_value & OPERATOR_RUNNING_MODAL) { + WM_event_add_modal_handler(C, op); + } + return ret_value | OPERATOR_PASS_THROUGH; + } + else { + /* If we are in init phase, and cannot validate init of modal operations, + * just fall back to basic exec. + */ + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + return ret_value | OPERATOR_PASS_THROUGH; + } + } + else if (event->type == init_event_type && event->val == KM_RELEASE) { + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + return ret_value | OPERATOR_PASS_THROUGH; + } + else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + const int drag_delta[2] = { + mval[0] - event->mval[0], + mval[1] - event->mval[1], + }; + /* If user moves mouse more than defined threshold, we consider select operator as + * finished. Otherwise, it is still running until we get an 'release' event. In any + * case, we pass through event, but select op is not finished yet. */ + if (WM_event_drag_test_with_delta(event, drag_delta)) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + else { + /* Important not to return anything other than PASS_THROUGH here, + * otherwise it prevents underlying tweak detection code to work properly. */ + return OPERATOR_PASS_THROUGH; + } + } + + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; +} + +int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + RNA_int_set(op->ptr, "mouse_x", event->mval[0]); + RNA_int_set(op->ptr, "mouse_y", event->mval[1]); + + op->customdata = POINTER_FROM_INT(0); + + return op->type->modal(C, op, event); +} + void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op) { if (op->flag & OP_IS_INVOKE) { @@ -2621,38 +2697,38 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even } else { delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; - delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + delta[1] = 0.0f; if (rc->zoom_prop) { RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); delta[0] /= zoom[0]; - delta[1] /= zoom[1]; } dist = len_v2(delta); delta[0] = event->x - rc->slow_mouse[0]; - delta[1] = event->y - rc->slow_mouse[1]; if (rc->zoom_prop) { delta[0] /= zoom[0]; - delta[1] /= zoom[1]; } - dist = dist + 0.1f * (delta[0] + delta[1]); + dist = dist + 0.1f * (delta[0]); } } else { delta[0] = rc->initial_mouse[0] - event->x; delta[1] = rc->initial_mouse[1] - event->y; - if (rc->zoom_prop) { RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); delta[0] /= zoom[0]; delta[1] /= zoom[1]; } - - dist = len_v2(delta); + if (rc->subtype == PROP_ANGLE) { + dist = len_v2(delta); + } + else { + dist = clamp_f(-delta[0], 0.0f, FLT_MAX); + } } /* calculate new value and apply snapping */ diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c new file mode 100644 index 00000000000..94eceafc59b --- /dev/null +++ b/source/blender/windowmanager/intern/wm_platform_support.c @@ -0,0 +1,219 @@ +/* + * 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) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#include "wm_platform_support.h" +#include "wm_window_private.h" + +#include <string.h> + +#include "BLI_sys_types.h" +#include "BLI_dynstr.h" +#include "BLI_path_util.h" +#include "BLI_fileops.h" +#include "BLI_string.h" +#include "BLI_linklist.h" + +#include "BLT_translation.h" + +#include "BKE_appdir.h" +#include "BKE_global.h" + +#include "GPU_platform.h" + +#include "GHOST_C-api.h" + +#define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024 + +/* Check if user has already approved the given platform_support_key. */ +static bool wm_platform_support_check_approval(const char *platform_support_key, bool update) +{ + const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); + bool result = false; + + if (G.factory_startup) { + return result; + } + + if (cfgdir) { + char filepath[FILE_MAX]; + BLI_make_file_string("/", filepath, cfgdir, BLENDER_PLATFORM_SUPPORT_FILE); + LinkNode *lines = BLI_file_read_as_lines(filepath); + for (LinkNode *line_node = lines; line_node; line_node = line_node->next) { + char *line = line_node->link; + if (STREQ(line, platform_support_key)) { + result = true; + break; + } + } + + if (!result && update) { + FILE *fp = BLI_fopen(filepath, "a"); + if (fp) { + fprintf(fp, "%s\n", platform_support_key); + fclose(fp); + } + } + + BLI_file_free_lines(lines); + } + return result; +} + +static void wm_platform_support_create_link(char *link) +{ + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, "https://docs.blender.org/manual/en/dev/troubleshooting/gpu/"); +#if defined(_WIN32) + BLI_dynstr_append(ds, "windows/"); +#elif defined(__APPLE__) + BLI_dynstr_append(ds, "apple/"); +#else /* UNIX */ + BLI_dynstr_append(ds, "linux/"); +#endif + + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "intel.html"); + } + else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "nvidia.html"); + } + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "amd.html"); + } + else { + BLI_dynstr_append(ds, "unknown.html"); + } + + BLI_assert(BLI_dynstr_get_len(ds) < WM_PLATFORM_SUPPORT_TEXT_SIZE); + BLI_dynstr_get_cstring_ex(ds, link); + BLI_dynstr_free(ds); +} + +bool WM_platform_support_perform_checks() +{ + char title[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + char message[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + char link[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + + bool result = true; + + eGPUSupportLevel support_level = GPU_platform_support_level(); + const char *platform_key = GPU_platform_support_level_key(); + + /* check if previous check matches the current check. Don't update the approval when running in + * `background`. this could have been triggered by installing addons via installers. */ + if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup && + wm_platform_support_check_approval(platform_key, !G.background)) { + /* if it matches the user has confirmed and whishes to use it */ + return result; + } + + /* update the message and link based on the found support level */ + GHOST_DialogOptions dialog_options = 0; + + switch (support_level) { + default: + case GPU_SUPPORT_LEVEL_SUPPORTED: + break; + + case GPU_SUPPORT_LEVEL_LIMITED: { + size_t slen = 0; + STR_CONCAT(title, slen, "Blender - "); + STR_CONCAT( + title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Limited Platform Support")); + slen = 0; + STR_CONCAT( + message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Your graphics card or driver has limited support. It may work, but with " + "issues.")); + + /* TODO: Extra space is needed for the split function in GHOST_SystemX11. We should change + * the behavior in GHOST_SystemX11. */ + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT( + message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Newer graphics drivers may be available to improve Blender support.")); + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n")); + STR_CONCAT(message, slen, GPU_platform_gpu_name()); + + dialog_options = GHOST_DialogWarning; + break; + } + + case GPU_SUPPORT_LEVEL_UNSUPPORTED: { + size_t slen = 0; + STR_CONCAT(title, slen, "Blender - "); + STR_CONCAT( + title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Platform Unsupported")); + slen = 0; + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Your graphics card or driver is not supported.")); + + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT( + message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Newer graphics drivers may be available to improve Blender support.")); + + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n")); + STR_CONCAT(message, slen, GPU_platform_gpu_name()); + STR_CONCAT(message, slen, "\n \n"); + + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "The program will now close.")); + dialog_options = GHOST_DialogError; + result = false; + break; + } + } + wm_platform_support_create_link(link); + + bool show_message = ELEM( + support_level, GPU_SUPPORT_LEVEL_LIMITED, GPU_SUPPORT_LEVEL_UNSUPPORTED); + + /* We are running in the background print the message in the console. */ + if ((G.background || G.debug & G_DEBUG) && show_message) { + printf("%s\n\n%s\n%s\n", title, message, link); + } + if (G.background) { + /* Don't show the message-box when running in background mode. + * Printing to console is enough. */ + result = true; + } + else if (show_message) { + WM_ghost_show_message_box( + title, message, "Find Latest Drivers", "Continue Anyway", link, dialog_options); + } + + return result; +} diff --git a/source/blender/windowmanager/intern/wm_platform_support.h b/source/blender/windowmanager/intern/wm_platform_support.h new file mode 100644 index 00000000000..a8e20f6bcdf --- /dev/null +++ b/source/blender/windowmanager/intern/wm_platform_support.h @@ -0,0 +1,30 @@ +/* + * 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) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#ifndef __WM_PLATFORM_SUPPORT_H__ +#define __WM_PLATFORM_SUPPORT_H__ + +#include "BLI_sys_types.h" + +bool WM_platform_support_perform_checks(void); + +#endif diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index d3f7661a008..662238b4ae1 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -178,68 +178,79 @@ static void wm_block_splash_add_labels(uiBlock *block, int x, int y) #endif /* WITH_BUILDINFO */ } -static ImBuf *wm_block_splash_image(void) +static ImBuf *wm_block_splash_image(int r_unit_size[2]) { #ifndef WITH_HEADLESS extern char datatoc_splash_png[]; extern int datatoc_splash_png_size; extern char datatoc_splash_2x_png[]; extern int datatoc_splash_2x_png_size; + const bool is_2x = U.dpi_fac > 1.0; + const int imb_scale = is_2x ? 2 : 1; - ImBuf *ibuf = NULL; + /* We could allow this to be variable, + * for now don't since allowing it might create layout issues. + * + * Only check width because splashes sometimes change height + * and we don't want to break app-templates. */ + const int x_expect = 501 * imb_scale; - if (U.dpi_fac > 1.0) { - ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_2x_png, - datatoc_splash_2x_png_size, - IB_rect, - NULL, - "<splash screen>"); - } - else { - ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_png, - datatoc_splash_png_size, - IB_rect, - NULL, - "<splash screen>"); - } + ImBuf *ibuf = NULL; - /* overwrite splash with template image */ if (U.app_template[0] != '\0') { - ImBuf *ibuf_template = NULL; char splash_filepath[FILE_MAX]; char template_directory[FILE_MAX]; - if (BKE_appdir_app_template_id_search( U.app_template, template_directory, sizeof(template_directory))) { BLI_join_dirfile(splash_filepath, sizeof(splash_filepath), template_directory, - (U.dpi_fac > 1.0) ? "splash_2x.png" : "splash.png"); - ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL); - if (ibuf_template) { - const int x_expect = ibuf->x; - const int y_expect = 250 * (int)U.dpi_fac; - /* don't cover the header text */ - if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) { - memcpy(ibuf->rect, - ibuf_template->rect, - ibuf_template->x * ibuf_template->y * sizeof(char[4])); - } - else { - CLOG_ERROR(WM_LOG_OPERATORS, - "Splash expected %dx%d found %dx%d, ignoring: %s\n", - x_expect, - y_expect, - ibuf_template->x, - ibuf_template->y, - splash_filepath); - } - IMB_freeImBuf(ibuf_template); + is_2x ? "splash_2x.png" : "splash.png"); + ibuf = IMB_loadiffname(splash_filepath, IB_rect, NULL); + + /* We could skip this check, see comment about 'x_expect' above. */ + if (ibuf->x != x_expect) { + CLOG_ERROR(WM_LOG_OPERATORS, + "Splash expected %d width found %d, ignoring: %s\n", + x_expect, + ibuf->x, + splash_filepath); + IMB_freeImBuf(ibuf); + ibuf = NULL; } } } + + if (ibuf == NULL) { + const uchar *splash_data; + size_t splash_data_size; + + if (is_2x) { + splash_data = (const uchar *)datatoc_splash_2x_png; + splash_data_size = datatoc_splash_2x_png_size; + } + else { + splash_data = (const uchar *)datatoc_splash_png; + splash_data_size = datatoc_splash_png_size; + } + + ibuf = IMB_ibImageFromMemory(splash_data, splash_data_size, IB_rect, NULL, "<splash screen>"); + + BLI_assert(ibuf->x == x_expect); + } + + if (is_2x) { + r_unit_size[0] = ibuf->x / 2; + r_unit_size[1] = ibuf->y / 2; + } + else { + r_unit_size[0] = ibuf->x; + r_unit_size[1] = ibuf->y; + } + return ibuf; #else + UNUSED_VARS(r_unit_size); return NULL; #endif } @@ -258,15 +269,17 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - ImBuf *ibuf = wm_block_splash_image(); + /* Size before dpi scaling (halved for hi-dpi image). */ + int ibuf_unit_size[2]; + ImBuf *ibuf = wm_block_splash_image(ibuf_unit_size); but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, - U.dpi_fac * 501, - U.dpi_fac * 250, + U.dpi_fac * ibuf_unit_size[0], + U.dpi_fac * ibuf_unit_size[1], /* Button owns the imbuf now. */ ibuf, 0.0, @@ -277,17 +290,18 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar UI_but_func_set(but, wm_block_splash_close, block, NULL); UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); - int x = U.dpi_fac * 502; - int y = U.dpi_fac * 237; + int x = U.dpi_fac * (ibuf_unit_size[0] + 1); + int y = U.dpi_fac * (ibuf_unit_size[1] - 13); wm_block_splash_add_labels(block, x, y); + const int layout_margin_x = U.dpi_fac * 26; uiLayout *layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, - U.dpi_fac * 26, + layout_margin_x, 0, - U.dpi_fac * 450, + (U.dpi_fac * ibuf_unit_size[0]) - (layout_margin_x * 2), U.dpi_fac * 110, 0, style); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2c26a15dce0..fa2320585d7 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -61,7 +61,9 @@ #include "wm.h" #include "wm_draw.h" #include "wm_files.h" +#include "wm_platform_support.h" #include "wm_window.h" +#include "wm_window_private.h" #include "wm_event_system.h" #include "ED_anim_api.h" @@ -78,7 +80,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_draw.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_framebuffer.h" #include "GPU_init_exit.h" #include "GPU_immediate.h" @@ -409,8 +411,10 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) /* this is event from ghost, or exit-blender op */ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { - /* First check if there is another main window remaining. */ wmWindow *win_other; + const bool is_dialog = GHOST_IsDialogWindow(win->ghostwin); + + /* First check if there is another main window remaining. */ for (win_other = wm->windows.first; win_other; win_other = win_other->next) { if (win_other != win && win_other->parent == NULL && !WM_window_is_temp_screen(win_other)) { break; @@ -422,10 +426,15 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) return; } - /* close child windows */ - for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) { - if (win_child->parent == win) { - wm_window_close(C, wm, win_child); + /* Close child windows and bring windows back to front that dialogs have pushed behind the main + * window. */ + for (wmWindow *iter_win = wm->windows.first; iter_win; iter_win = iter_win->next) { + if (iter_win->parent == win) { + wm_window_close(C, wm, iter_win); + } + else if (is_dialog && iter_win != win && iter_win->parent && + (GHOST_GetWindowState(iter_win->ghostwin) != GHOST_kWindowStateMinimized)) { + wm_window_raise(iter_win); } } @@ -547,7 +556,10 @@ static void wm_window_ensure_eventstate(wmWindow *win) } /* belongs to below */ -static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win) +static void wm_window_ghostwindow_add(wmWindowManager *wm, + const char *title, + wmWindow *win, + bool is_dialog) { GHOST_WindowHandle ghostwin; GHOST_GLSettings glSettings = {0}; @@ -569,15 +581,29 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm wmWindow *prev_windrawable = wm->windrawable; wm_window_clear_drawable(wm); - ghostwin = GHOST_CreateWindow(g_system, - title, - win->posx, - posy, - win->sizex, - win->sizey, - (GHOST_TWindowState)win->windowstate, - GHOST_kDrawingContextTypeOpenGL, - glSettings); + if (is_dialog && win->parent) { + ghostwin = GHOST_CreateDialogWindow(g_system, + win->parent->ghostwin, + title, + win->posx, + posy, + win->sizex, + win->sizey, + (GHOST_TWindowState)win->windowstate, + GHOST_kDrawingContextTypeOpenGL, + glSettings); + } + else { + ghostwin = GHOST_CreateWindow(g_system, + title, + win->posx, + posy, + win->sizex, + win->sizey, + (GHOST_TWindowState)win->windowstate, + GHOST_kDrawingContextTypeOpenGL, + glSettings); + } if (ghostwin) { GHOST_RectangleHandle bounds; @@ -635,6 +661,68 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm } } +static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, bool is_dialog) +{ + wmKeyMap *keymap; + + if (win->ghostwin == NULL) { + if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) { + win->posx = wm_init_state.start_x; + win->posy = wm_init_state.start_y; + win->sizex = wm_init_state.size_x; + win->sizey = wm_init_state.size_y; + + if (wm_init_state.override_flag & WIN_OVERRIDE_GEOM) { + win->windowstate = GHOST_kWindowStateNormal; + wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM; + } + else { + win->windowstate = GHOST_WINDOW_STATE_DEFAULT; + } + } + + if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) { + win->windowstate = wm_init_state.windowstate; + wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE; + } + + /* without this, cursor restore may fail, T45456 */ + if (win->cursor == 0) { + win->cursor = WM_CURSOR_DEFAULT; + } + + wm_window_ghostwindow_add(wm, "Blender", win, is_dialog); + } + + if (win->ghostwin != NULL) { + /* If we have no ghostwin this is a buggy window that should be removed. + * However we still need to initialize it correctly so the screen doesn't hang. */ + + /* happens after fileread */ + wm_window_ensure_eventstate(win); + } + + /* add keymap handlers (1 handler for all keys in map!) */ + keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0); + WM_event_add_keymap_handler(&win->handlers, keymap); + + keymap = WM_keymap_ensure(wm->defaultconf, "Screen", 0, 0); + WM_event_add_keymap_handler(&win->handlers, keymap); + + keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", 0, 0); + WM_event_add_keymap_handler(&win->modalhandlers, keymap); + + /* add drop boxes */ + { + ListBase *lb = WM_dropboxmap_find("Window", 0, 0); + WM_event_add_dropbox_handler(&win->handlers, lb); + } + wm_window_title(wm, win); + + /* add topbar */ + ED_screen_global_areas_refresh(win); +} + /** * Initialize #wmWindow without ghostwin, open these and clear. * @@ -650,9 +738,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm */ void wm_window_ghostwindows_ensure(wmWindowManager *wm) { - wmKeyMap *keymap; - wmWindow *win; - BLI_assert(G.background == false); /* No command-line prefsize? then we set this. @@ -682,63 +767,8 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) #endif } - for (win = wm->windows.first; win; win = win->next) { - if (win->ghostwin == NULL) { - if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) { - win->posx = wm_init_state.start_x; - win->posy = wm_init_state.start_y; - win->sizex = wm_init_state.size_x; - win->sizey = wm_init_state.size_y; - - if (wm_init_state.override_flag & WIN_OVERRIDE_GEOM) { - win->windowstate = GHOST_kWindowStateNormal; - wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM; - } - else { - win->windowstate = GHOST_WINDOW_STATE_DEFAULT; - } - } - - if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) { - win->windowstate = wm_init_state.windowstate; - wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE; - } - - /* without this, cursor restore may fail, T45456 */ - if (win->cursor == 0) { - win->cursor = WM_CURSOR_DEFAULT; - } - - wm_window_ghostwindow_add(wm, "Blender", win); - } - - if (win->ghostwin != NULL) { - /* If we have no ghostwin this is a buggy window that should be removed. - * However we still need to initialize it correctly so the screen doesn't hang. */ - - /* happens after fileread */ - wm_window_ensure_eventstate(win); - } - - /* add keymap handlers (1 handler for all keys in map!) */ - keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0); - WM_event_add_keymap_handler(&win->handlers, keymap); - - keymap = WM_keymap_ensure(wm->defaultconf, "Screen", 0, 0); - WM_event_add_keymap_handler(&win->handlers, keymap); - - keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", 0, 0); - WM_event_add_keymap_handler(&win->modalhandlers, keymap); - - /* add drop boxes */ - { - ListBase *lb = WM_dropboxmap_find("Window", 0, 0); - WM_event_add_dropbox_handler(&win->handlers, lb); - } - wm_window_title(wm, win); - - /* add topbar */ - ED_screen_global_areas_refresh(win); + for (wmWindow *win = wm->windows.first; win; win = win->next) { + wm_window_ghostwindow_ensure(wm, win, false); } } @@ -795,10 +825,17 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type) * \return the window or NULL in case of failure. */ -wmWindow *WM_window_open_temp( - bContext *C, const char *title, int x, int y, int sizex, int sizey, int space_type) +wmWindow *WM_window_open_temp(bContext *C, + const char *title, + int x, + int y, + int sizex, + int sizey, + int space_type, + bool dialog) { Main *bmain = CTX_data_main(C); + wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win_prev = CTX_wm_window(C); wmWindow *win; bScreen *screen; @@ -823,9 +860,10 @@ wmWindow *WM_window_open_temp( /* changes rect to fit within desktop */ wm_window_check_position(&rect); - /* test if we have a temp screen already */ - for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) { - if (WM_window_is_temp_screen(win)) { + /* Reuse temporary or dialog window if one is open (but don't use a dialog for a regular + * temporary window, or vice versa). */ + for (win = wm->windows.first; win; win = win->next) { + if (WM_window_is_temp_screen(win) && (dialog == GHOST_IsDialogWindow(win->ghostwin))) { break; } } @@ -843,11 +881,6 @@ wmWindow *WM_window_open_temp( win->sizex = BLI_rcti_size_x(&rect); win->sizey = BLI_rcti_size_y(&rect); - if (win->ghostwin) { - wm_window_set_size(win, win->sizex, win->sizey); - wm_window_raise(win); - } - if (WM_window_get_active_workspace(win) == NULL) { WorkSpace *workspace = WM_window_get_active_workspace(win_prev); BKE_workspace_active_set(win->workspace_hook, workspace); @@ -872,6 +905,9 @@ wmWindow *WM_window_open_temp( /* make window active, and validate/resize */ CTX_wm_window_set(C, win); + if (!win->ghostwin) { + wm_window_ghostwindow_ensure(wm, win, dialog); + } WM_check(C); /* It's possible `win->ghostwin == NULL`. @@ -887,15 +923,18 @@ wmWindow *WM_window_open_temp( ED_area_newspace(C, sa, space_type, false); ED_screen_change(C, screen); - ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ + ED_screen_refresh(wm, win); /* test scale */ if (win->ghostwin) { + wm_window_set_size(win, win->sizex, win->sizey); + wm_window_raise(win); + GHOST_SetTitle(win->ghostwin, title); return win; } else { /* very unlikely! but opening a new window can fail */ - wm_window_close(C, CTX_wm_manager(C), win); + wm_window_close(C, wm, win); CTX_wm_window_set(C, win_prev); return NULL; @@ -2394,4 +2433,14 @@ void WM_opengl_context_release(void *context) GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context); } +void WM_ghost_show_message_box(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options) +{ + BLI_assert(g_system); + GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options); +} /** \} */ diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h new file mode 100644 index 00000000000..115539861d7 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_window_private.h @@ -0,0 +1,42 @@ +/* + * 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) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#ifndef __WM_WINDOW_PRIVATE_H__ +#define __WM_WINDOW_PRIVATE_H__ + +#include "BLI_sys_types.h" +#include "GHOST_Types.h" + +/* *************** Message box *************** */ +/* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is + * defined here as it was implemented to be used for showing + * a message to the user when the platform is not (fully) supported. + * + * In all other cases this message box should not be used. */ +void WM_ghost_show_message_box(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options); + +#endif diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 8fb4d2905f4..4da1d61a4f1 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -513,6 +513,16 @@ if(UNIX AND NOT APPLE) DESTINATION "." ) + if(EXISTS ${LIBDIR}/mesa) + install(DIRECTORY ${LIBDIR}/mesa/lib DESTINATION ".") + + install( + PROGRAMS + ${CMAKE_SOURCE_DIR}/release/bin/blender-softwaregl + DESTINATION "." + ) + endif() + set(BLENDER_TEXT_FILES_DESTINATION ".") else() # main blender binary @@ -674,6 +684,13 @@ elseif(WIN32) set(BLENDER_TEXT_FILES_DESTINATION ".") + if(WITH_OPENMP AND MSVC_CLANG) + install( + FILES ${CLANG_OPENMP_DLL} + DESTINATION "." + ) + endif() + if(WITH_PYTHON) string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) diff --git a/source/tools b/source/tools -Subproject 7b740545cd039ddcadbfb9bffcac842476eee27 +Subproject d8c4ae2c23a36d9609d47142dc72f243551258f diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7d8a1390628..94b6e49181c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,6 +4,7 @@ # # Getting the install path of the executable is somewhat involved, as there are # no direct CMake generator expressions to get the install paths of executables. +get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(GENERATOR_IS_MULTI_CONFIG) string(REPLACE "\${BUILD_TYPE}" "$<CONFIG>" TEST_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) else() diff --git a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc index 315e5804784..8b29128eb0d 100644 --- a/tests/gtests/blenlib/BLI_delaunay_2d_test.cc +++ b/tests/gtests/blenlib/BLI_delaunay_2d_test.cc @@ -667,6 +667,32 @@ TEST(delaunay, TriCutoff) BLI_delaunay_2d_cdt_free(out); } +TEST(delaunay, TriInTri) +{ + CDT_input in; + CDT_result *out; + float p[][2] = { + {-5.65685f, 0.0f}, + {1.41421f, -5.83095f}, + {0.0f, 0.0f}, + {-2.47487f, -1.45774f}, + {-0.707107f, -2.91548f}, + {-1.06066f, -1.45774f}, + }; + int f[] = {0, 1, 2, 3, 4, 5}; + int fstart[] = {0, 3}; + int flen[] = {3, 3}; + + fill_input_verts(&in, p, 6); + add_input_faces(&in, f, fstart, flen, 2); + out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH); + EXPECT_EQ(out->verts_len, 6); + EXPECT_EQ(out->edges_len, 8); + EXPECT_EQ(out->faces_len, 3); + BLI_delaunay_2d_cdt_free(out); +} + +#if 0 enum { RANDOM_PTS, RANDOM_SEGS, @@ -739,12 +765,12 @@ static void rand_delaunay_test(int test_kind, times[lg_size] += PIL_check_seconds_timer() - tstart; } } -#ifdef DO_TIMING +# ifdef DO_TIMING fprintf(stderr, "size,time\n"); for (lg_size = 0; lg_size <= max_lg_size; lg_size++) { fprintf(stderr, "%d,%f\n", 1 << lg_size, times[lg_size] / reps_per_size); } -#endif +# endif MEM_freeN(p); if (e) MEM_freeN(e); @@ -781,6 +807,7 @@ TEST(delaunay, randompoly_validbmesh) { rand_delaunay_test(RANDOM_POLY, 7, 1, CDT_CONSTRAINTS_VALID_BMESH); } +#endif #if 0 /* For debugging or timing large examples. diff --git a/tests/gtests/blenlib/BLI_memiter_test.cc b/tests/gtests/blenlib/BLI_memiter_test.cc index c1c07dc7540..d92daefff3b 100644 --- a/tests/gtests/blenlib/BLI_memiter_test.cc +++ b/tests/gtests/blenlib/BLI_memiter_test.cc @@ -17,7 +17,7 @@ TEST(memiter, Nop) BLI_memiter_destroy(mi); } -void memiter_empty_test(int num_elems, const int chunk_size) +static void memiter_empty_test(int num_elems, const int chunk_size) { BLI_memiter *mi = BLI_memiter_create(chunk_size); void *data; @@ -39,7 +39,7 @@ void memiter_empty_test(int num_elems, const int chunk_size) } #define MEMITER_NUMBER_TEST_FN(fn, number_type) \ - void fn(int num_elems, const int chunk_size) \ + static void fn(int num_elems, const int chunk_size) \ { \ BLI_memiter *mi = BLI_memiter_create(chunk_size); \ number_type *data; \ @@ -65,7 +65,7 @@ MEMITER_NUMBER_TEST_FN(memiter_short_test, short) MEMITER_NUMBER_TEST_FN(memiter_int_test, int) MEMITER_NUMBER_TEST_FN(memiter_long_test, int64_t) -void memiter_string_test(const char *strings[], const int chunk_size) +static void memiter_string_test(const char *strings[], const int chunk_size) { BLI_memiter *mi = BLI_memiter_create(chunk_size); char *data; @@ -95,7 +95,7 @@ void memiter_string_test(const char *strings[], const int chunk_size) BLI_memiter_destroy(mi); } -void memiter_words10k_test(const char split_char, const int chunk_size) +static void memiter_words10k_test(const char split_char, const int chunk_size) { const int words_len = sizeof(words10k) - 1; char *words = BLI_strdupn(words10k, words_len); |