diff options
761 files changed, 11927 insertions, 6194 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 408cf819ce8..7e89943714a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,11 +336,9 @@ if(APPLE) else() set(WITH_COREAUDIO OFF) endif() -if(NOT WIN32) +if(UNIX AND NOT APPLE) option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ON) - if(UNIX AND NOT APPLE) - option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF) - endif() + option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF) else() set(WITH_JACK OFF) endif() @@ -489,13 +487,12 @@ endif() if(NOT APPLE) option(WITH_CYCLES_DEVICE_ONEAPI "Enable Cycles oneAPI compute support" OFF) option(WITH_CYCLES_ONEAPI_BINARIES "Enable Ahead-Of-Time compilation for Cycles oneAPI device" OFF) - option(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED "Enable use of SYCL host (CPU) device execution by oneAPI implementation. This option is for debugging purposes and impacts GPU execution." OFF) # https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compilation/ahead-of-time-compilation.html - set(CYCLES_ONEAPI_SPIR64_GEN_DEVICES "dg2" CACHE STRING "oneAPI Intel GPU architectures to build binaries for") + # acm-g10 is the target for the first Intel Arc Alchemist GPUs. + set(CYCLES_ONEAPI_SPIR64_GEN_DEVICES "acm-g10" CACHE STRING "oneAPI Intel GPU architectures to build binaries for") set(CYCLES_ONEAPI_SYCL_TARGETS spir64 spir64_gen CACHE STRING "oneAPI targets to build AOT binaries for") - mark_as_advanced(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED) mark_as_advanced(CYCLES_ONEAPI_SPIR64_GEN_DEVICES) mark_as_advanced(CYCLES_ONEAPI_SYCL_TARGETS) endif() @@ -572,6 +569,12 @@ mark_as_advanced( WITH_GPU_BUILDTIME_SHADER_BUILDER ) +# Vulkan +option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF) +mark_as_advanced( + WITH_VULKAN_BACKEND +) + # Metal if(APPLE) @@ -780,6 +783,8 @@ endif() # ----------------------------------------------------------------------------- # Check for Conflicting/Unsupported Configurations +option(WITH_STRICT_BUILD_OPTIONS "When requirements for a build option are not met, error instead of disabling the option" OFF) + if(NOT WITH_BLENDER AND NOT WITH_CYCLES_STANDALONE AND NOT WITH_CYCLES_HYDRA_RENDER_DELEGATE) message(FATAL_ERROR "At least one of WITH_BLENDER or WITH_CYCLES_STANDALONE " @@ -895,10 +900,7 @@ endif() if(WITH_BUILDINFO) find_package(Git) - if(NOT GIT_FOUND) - message(WARNING "Git was not found, disabling WITH_BUILDINFO") - set(WITH_BUILDINFO OFF) - endif() + set_and_warn_library_found("Git" GIT_FOUND WITH_BUILDINFO) endif() if(WITH_AUDASPACE) @@ -938,9 +940,10 @@ if(WITH_INTERNATIONAL) WARNING "Translation path '${CMAKE_SOURCE_DIR}/release/datafiles/locale' is missing, " "This is a 'git submodule', which are known not to work with bridges to other version " - "control systems, disabling 'WITH_INTERNATIONAL'." + "control systems." ) - set(WITH_INTERNATIONAL OFF) + set(TRANSLATIONS_FOUND OFF) + set_and_warn_library_found("Translations" TRANSLATIONS_FOUND WITH_INTERNATIONAL) endif() endif() @@ -1226,6 +1229,13 @@ endif() # ----------------------------------------------------------------------------- +# Configure Vulkan. + +if(WITH_VULKAN_BACKEND) + add_definitions(-DWITH_VULKAN_BACKEND) +endif() + +# ----------------------------------------------------------------------------- # Configure Metal if(WITH_METAL_BACKEND) @@ -1245,6 +1255,8 @@ if(WITH_OPENMP) find_package(OpenMP) endif() + set_and_warn_library_found("OpenMP" OPENMP_FOUND WITH_OPENMP) + if(OPENMP_FOUND) if(NOT WITH_OPENMP_STATIC) string(APPEND CMAKE_C_FLAGS " ${OpenMP_C_FLAGS}") @@ -1260,9 +1272,6 @@ if(WITH_OPENMP) find_library_static(OpenMP_LIBRARIES gomp ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}) endif() - else() - message(STATUS "OpenMP not found, disabling WITH_OPENMP") - set(WITH_OPENMP OFF) endif() mark_as_advanced( @@ -1277,10 +1286,7 @@ endif() if(WITH_BULLET AND WITH_SYSTEM_BULLET) find_package(Bullet) - if(NOT BULLET_FOUND) - message(STATUS "Bullet not found, disabling WITH_BULLET") - set(WITH_BULLET OFF) - endif() + set_and_warn_library_found("Bullet" BULLET_FOUND WITH_BULLET) else() set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet2/src") # set(BULLET_LIBRARIES "") diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index 4f40f44ad18..023d113b551 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -97,6 +97,8 @@ include(cmake/embree.cmake) include(cmake/openpgl.cmake) include(cmake/fmt.cmake) include(cmake/robinmap.cmake) +include(cmake/xml2.cmake) + if(NOT APPLE) include(cmake/xr_openxr.cmake) if(NOT WIN32 OR BUILD_MODE STREQUAL Release) @@ -149,7 +151,6 @@ if(NOT WIN32 OR ENABLE_MINGW64) endif() if(UNIX) include(cmake/flac.cmake) - include(cmake/xml2.cmake) if(NOT APPLE) include(cmake/spnav.cmake) include(cmake/jemalloc.cmake) diff --git a/build_files/build_environment/cmake/aom.cmake b/build_files/build_environment/cmake/aom.cmake index 9f64439771f..11c81c3f6e4 100644 --- a/build_files/build_environment/cmake/aom.cmake +++ b/build_files/build_environment/cmake/aom.cmake @@ -8,11 +8,6 @@ if(WIN32) # building with mingw, it'll have an unhappy time with that and # we need to clear them out. set(AOM_CMAKE_FLAGS ) - # CMake will correctly identify phreads being available, however - # we do not want to use them, as that gains a dependency on - # libpthreadswin.dll which we do not want. when pthreads is not - # available oam will use a pthreads emulation layer using win32 threads - set(AOM_EXTRA_ARGS_WIN32 -DCMAKE_HAVE_PTHREAD_H=OFF) else() set(AOM_GENERATOR "Unix Makefiles") set(AOM_CMAKE_FLAGS ${DEFAULT_CMAKE_FLAGS}) @@ -36,6 +31,7 @@ ExternalProject_Add(external_aom DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${AOM_HASH_TYPE}=${AOM_HASH} PREFIX ${BUILD_DIR}/aom + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/aom/src/external_aom < ${PATCH_DIR}/aom.diff CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/aom/src/external_aom-build/ && ${CMAKE_COMMAND} -G "${AOM_GENERATOR}" -DCMAKE_INSTALL_PREFIX=${LIBDIR}/aom ${AOM_CMAKE_FLAGS} ${AOM_EXTRA_ARGS} ${BUILD_DIR}/aom/src/external_aom/ diff --git a/build_files/build_environment/cmake/cve_check.cmake b/build_files/build_environment/cmake/cve_check.cmake index dfb190bcffa..ac42444aef1 100644 --- a/build_files/build_environment/cmake/cve_check.cmake +++ b/build_files/build_environment/cmake/cve_check.cmake @@ -27,10 +27,12 @@ get_cmake_property(_variableNames VARIABLES) foreach (_variableName ${_variableNames}) if(_variableName MATCHES "CPE$") string(REPLACE ":" ";" CPE_LIST ${${_variableName}}) + string(REPLACE "_CPE" "_ID" CPE_DEPNAME ${_variableName}) list(GET CPE_LIST 3 CPE_VENDOR) list(GET CPE_LIST 4 CPE_NAME) list(GET CPE_LIST 5 CPE_VERSION) - set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}\n") + set(${CPE_DEPNAME} "${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}") + set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION},,,\n") endif() endforeach() configure_file(${CMAKE_SOURCE_DIR}/cmake/cve_check.csv.in ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv @ONLY) diff --git a/build_files/build_environment/cmake/cve_check.csv.in b/build_files/build_environment/cmake/cve_check.csv.in index 6e7e8db5609..946dda5ab17 100644 --- a/build_files/build_environment/cmake/cve_check.csv.in +++ b/build_files/build_environment/cmake/cve_check.csv.in @@ -1,2 +1,29 @@ -vendor,product,version +vendor,product,version,cve_number,remarks,comment +@OPENJPEG_ID@,CVE-2016-9675,Ignored,issue in convert command line tool not used by blender +@PYTHON_ID@,CVE-2009-2940,Ignored,issue in pygresql not used by blender +@PYTHON_ID@,CVE-2020-29396,Ignored,issue in odoo not used by blender +@PYTHON_ID@,CVE-2021-32052,Ignored,issue in django not used by blender +@PYTHON_ID@,CVE-2009-3720,Ignored,already fixed in libexpat version used +@SSL_ID@,CVE-2009-1390,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3765,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3766,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3767,Ignored,issue in ldap not used by blender +@SSL_ID@,CVE-2019-0190,Ignored,issue in apache not used by blender +@TIFF_ID@,CVE-2022-2056,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2057,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2058,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2519,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2520,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2521,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2953,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-34526,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3570,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3597,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3598,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3599,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3626,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3627,Ignored,issue in tiff command line tool not used by blender +@XML2_ID@,CVE-2016-3709,Ignored,not affecting blender and not considered a security issue upstream +@GMP_ID@,CVE-2021-43618,Mitigated,patched using upstream commit 561a9c25298e +@SQLITE_ID@,CVE-2022-35737,Ignored,only affects SQLITE_ENABLE_STAT4 compile option not used by blender or python @SBOMCONTENTS@ diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake index 35bc028a1e3..8d75f0ff0ed 100644 --- a/build_files/build_environment/cmake/download.cmake +++ b/build_files/build_environment/cmake/download.cmake @@ -62,7 +62,7 @@ function(download_source dep) # since the actual build of the dep will notify the # platform maintainer if there is a problem with the # source package and refuse to build. - if(NOT PACKAGE_USE_UPSTREAM_SOURCES) + if(NOT PACKAGE_USE_UPSTREAM_SOURCES OR FORCE_CHECK_HASH) file(${TARGET_HASH_TYPE} ${TARGET_FILE} LOCAL_HASH) if(NOT ${TARGET_HASH} STREQUAL ${LOCAL_HASH}) message(FATAL_ERROR "${TARGET_FILE} ${TARGET_HASH_TYPE} mismatch\nExpected\t: ${TARGET_HASH}\nActual\t: ${LOCAL_HASH}") @@ -114,7 +114,6 @@ download_source(WEBP) download_source(SPNAV) download_source(JEMALLOC) download_source(XML2) -download_source(TINYXML) download_source(YAMLCPP) download_source(EXPAT) download_source(PUGIXML) diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake index 7730607c514..e2b60e161f2 100644 --- a/build_files/build_environment/cmake/ffmpeg.cmake +++ b/build_files/build_environment/cmake/ffmpeg.cmake @@ -16,12 +16,6 @@ if(WIN32) --enable-libopenjpeg --disable-mediafoundation ) - if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") - set(FFMPEG_EXTRA_FLAGS - ${FFMPEG_EXTRA_FLAGS} - --x86asmexe=yasm - ) - endif() else() set(FFMPEG_EXTRA_FLAGS ${FFMPEG_EXTRA_FLAGS} diff --git a/build_files/build_environment/cmake/freetype.cmake b/build_files/build_environment/cmake/freetype.cmake index b6f53ede2db..842e5c42e25 100644 --- a/build_files/build_environment/cmake/freetype.cmake +++ b/build_files/build_environment/cmake/freetype.cmake @@ -7,8 +7,11 @@ set(FREETYPE_EXTRA_ARGS -DFT_DISABLE_HARFBUZZ=ON -DFT_DISABLE_PNG=ON -DFT_REQUIRE_BROTLI=ON + -DFT_REQUIRE_ZLIB=ON -DPC_BROTLIDEC_INCLUDEDIR=${LIBDIR}/brotli/include -DPC_BROTLIDEC_LIBDIR=${LIBDIR}/brotli/lib + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include ) ExternalProject_Add(external_freetype @@ -23,6 +26,7 @@ ExternalProject_Add(external_freetype add_dependencies( external_freetype external_brotli + external_zlib ) if(BUILD_MODE STREQUAL Release AND WIN32) diff --git a/build_files/build_environment/cmake/gmp.cmake b/build_files/build_environment/cmake/gmp.cmake index e624778869e..ddfdba6662d 100644 --- a/build_files/build_environment/cmake/gmp.cmake +++ b/build_files/build_environment/cmake/gmp.cmake @@ -27,6 +27,7 @@ ExternalProject_Add(external_gmp DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${GMP_HASH_TYPE}=${GMP_HASH} PREFIX ${BUILD_DIR}/gmp + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/gmp/src/external_gmp < ${PATCH_DIR}/gmp.diff CONFIGURE_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/gmp ${GMP_OPTIONS} ${GMP_EXTRA_ARGS} BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make install diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake index e4ddc7db846..11f6bf7c218 100644 --- a/build_files/build_environment/cmake/llvm.cmake +++ b/build_files/build_environment/cmake/llvm.cmake @@ -9,6 +9,7 @@ endif() if(APPLE) set(LLVM_XML2_ARGS -DLIBXML2_LIBRARY=${LIBDIR}/xml2/lib/libxml2.a + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 ) set(LLVM_BUILD_CLANG_TOOLS_EXTRA ^^clang-tools-extra) set(BUILD_CLANG_TOOLS ON) diff --git a/build_files/build_environment/cmake/opencollada.cmake b/build_files/build_environment/cmake/opencollada.cmake index b2ae1a1a351..b1a3028debd 100644 --- a/build_files/build_environment/cmake/opencollada.cmake +++ b/build_files/build_environment/cmake/opencollada.cmake @@ -4,6 +4,29 @@ if(UNIX) set(OPENCOLLADA_EXTRA_ARGS -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2.a) + + # WARNING: the patch contains mixed UNIX and DOS line endings + # as does the OPENCOLLADA package, if this can be corrected upstream that would be better. + # For now use `sed` to force UNIX line endings so the patch applies. + # Needed as neither ignoring white-space or applying as a binary resolve this problem. + set(PATCH_MAYBE_DOS2UNIX_CMD + sed -i "s/\\r//" + ${PATCH_DIR}/opencollada.diff + ${BUILD_DIR}/opencollada/src/external_opencollada/CMakeLists.txt + ${BUILD_DIR}/opencollada/src/external_opencollada/Externals/LibXML/CMakeLists.txt && + ) + +else() + set(OPENCOLLADA_EXTRA_ARGS + -DCMAKE_DEBUG_POSTFIX=_d + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 + ) + if(BUILD_MODE STREQUAL Release) + list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2s.lib) + else() + list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2sd.lib) + endif() + set(PATCH_MAYBE_DOS2UNIX_CMD) endif() ExternalProject_Add(external_opencollada @@ -11,17 +34,19 @@ ExternalProject_Add(external_opencollada DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${OPENCOLLADA_HASH_TYPE}=${OPENCOLLADA_HASH} PREFIX ${BUILD_DIR}/opencollada - PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/opencollada/src/external_opencollada < ${PATCH_DIR}/opencollada.diff + PATCH_COMMAND + ${PATCH_MAYBE_DOS2UNIX_CMD} + ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/opencollada/src/external_opencollada < ${PATCH_DIR}/opencollada.diff CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencollada ${DEFAULT_CMAKE_FLAGS} ${OPENCOLLADA_EXTRA_ARGS} INSTALL_DIR ${LIBDIR}/opencollada ) -if(UNIX) - add_dependencies( - external_opencollada - external_xml2 - ) -endif() +unset(PATCH_MAYBE_DOS2UNIX_CMD) + +add_dependencies( + external_opencollada + external_xml2 +) if(WIN32) if(BUILD_MODE STREQUAL Release) @@ -32,17 +57,7 @@ if(WIN32) endif() if(BUILD_MODE STREQUAL Debug) ExternalProject_Add_Step(external_opencollada after_install - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/buffer.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/buffer_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/ftoa.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/ftoa_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/GeneratedSaxParser.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/GeneratedSaxParser_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/MathMLSolver.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/MathMLSolver_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADABaseUtils.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADABaseUtils_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAFramework.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAFramework_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADASaxFrameworkLoader_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/OpenCOLLADAStreamWriter_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/pcre.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/pcre_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/UTF.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/UTF_d.lib - COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencollada/lib/opencollada/xml.lib ${HARVEST_TARGET}/opencollada/lib/opencollada/xml_d.lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencollada/lib ${HARVEST_TARGET}/opencollada/lib DEPENDEES install ) endif() diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake index 6e5f9df20b4..13e7fb58be2 100644 --- a/build_files/build_environment/cmake/options.cmake +++ b/build_files/build_environment/cmake/options.cmake @@ -3,6 +3,7 @@ if(WIN32) option(ENABLE_MINGW64 "Enable building of ffmpeg/iconv/libsndfile/fftw3 by installing mingw64" ON) endif() +option(FORCE_CHECK_HASH "Force a check of all hashses during CMake the configure phase" OFF) option(WITH_BOOST_PYTHON "Enable building of boost with python support" OFF) cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_LOGICAL_CORES) set(MAKE_THREADS ${NUM_CORES} CACHE STRING "Number of threads to run make with") @@ -20,8 +21,8 @@ else() endif() set(DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/downloads" CACHE STRING "Path for downloaded files") -# This path must be hard-coded like this, so that the GNUmakefile knows where it is and can pass it to make_source_archive.py: -set(PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/packages") + +set(PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/packages" CACHE PATH "default path for downloaded packages") option(PACKAGE_USE_UPSTREAM_SOURCES "Use sources upstream to download the package sources, when OFF the blender mirror will be used" ON) file(TO_CMAKE_PATH ${DOWNLOAD_DIR} DOWNLOAD_DIR) diff --git a/build_files/build_environment/cmake/osl.cmake b/build_files/build_environment/cmake/osl.cmake index 9719de94d47..a5d000e4f44 100644 --- a/build_files/build_environment/cmake/osl.cmake +++ b/build_files/build_environment/cmake/osl.cmake @@ -32,6 +32,8 @@ set(OSL_EXTRA_ARGS -DUSE_Qt5=OFF -DINSTALL_DOCS=OFF -Dpugixml_ROOT=${LIBDIR}/pugixml + -DTIFF_ROOT=${LIBDIR}/tiff + -DJPEG_ROOT=${LIBDIR}/jpeg -DUSE_PYTHON=OFF -DCMAKE_CXX_STANDARD=14 -DImath_ROOT=${LIBDIR}/imath @@ -81,6 +83,7 @@ if(WIN32) COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslcomp.lib ${HARVEST_TARGET}/osl/lib/oslcomp_d.lib COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslexec.lib ${HARVEST_TARGET}/osl/lib/oslexec_d.lib COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslquery.lib ${HARVEST_TARGET}/osl/lib/oslquery_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslnoise.lib ${HARVEST_TARGET}/osl/lib/oslnoise_d.lib DEPENDEES install ) endif() diff --git a/build_files/build_environment/cmake/png.cmake b/build_files/build_environment/cmake/png.cmake index 890be673cb8..371f2608e2a 100644 --- a/build_files/build_environment/cmake/png.cmake +++ b/build_files/build_environment/cmake/png.cmake @@ -24,6 +24,14 @@ add_dependencies( external_zlib ) +if(WIN32 AND BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_png after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/png/include/ ${HARVEST_TARGET}/png/include/ + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_static${LIBEXT} ${HARVEST_TARGET}/png/lib/libpng${LIBEXT} + DEPENDEES install + ) +endif() + if(WIN32 AND BUILD_MODE STREQUAL Debug) ExternalProject_Add_Step(external_png after_install COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_staticd${LIBEXT} ${LIBDIR}/png/lib/libpng16${LIBEXT} diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake index 8fed10e9d72..72ae27ddfdb 100644 --- a/build_files/build_environment/cmake/python.cmake +++ b/build_files/build_environment/cmake/python.cmake @@ -15,9 +15,11 @@ if(WIN32) endmacro() set(PYTHON_EXTERNALS_FOLDER ${BUILD_DIR}/python/src/external_python/externals) + set(ZLIB_SOURCE_FOLDER ${BUILD_DIR}/zlib/src/external_zlib) set(DOWNLOADS_EXTERNALS_FOLDER ${DOWNLOAD_DIR}/externals) cmake_to_dos_path(${PYTHON_EXTERNALS_FOLDER} PYTHON_EXTERNALS_FOLDER_DOS) + cmake_to_dos_path(${ZLIB_SOURCE_FOLDER} ZLIB_SOURCE_FOLDER_DOS) cmake_to_dos_path(${DOWNLOADS_EXTERNALS_FOLDER} DOWNLOADS_EXTERNALS_FOLDER_DOS) ExternalProject_Add(external_python @@ -25,12 +27,21 @@ if(WIN32) DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${PYTHON_HASH_TYPE}=${PYTHON_HASH} PREFIX ${BUILD_DIR}/python - CONFIGURE_COMMAND "" + # Python will download its own deps and there's very little we can do about + # that beyond placing some code in their externals dir before it tries. + # the foldernames *HAVE* to match the ones inside pythons get_externals.cmd. + # python 3.10.8 still ships zlib 1.2.12, replace it with our 1.2.13 + # copy until they update. + CONFIGURE_COMMAND mkdir ${PYTHON_EXTERNALS_FOLDER_DOS} && + mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\zlib-1.2.12 ${ZLIB_SOURCE_FOLDER_DOS} && + ${CMAKE_COMMAND} -E copy ${ZLIB_SOURCE_FOLDER}/../external_zlib-build/zconf.h ${PYTHON_EXTERNALS_FOLDER}/zlib-1.2.12/zconf.h BUILD_COMMAND cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && call build.bat -e -p x64 -c ${BUILD_MODE} - PATCH_COMMAND ${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_windows.diff INSTALL_COMMAND ${PYTHON_BINARY_INTERNAL} ${PYTHON_SRC}/PC/layout/main.py -b ${PYTHON_SRC}/PCbuild/amd64 -s ${PYTHON_SRC} -t ${PYTHON_SRC}/tmp/ --include-stable --include-pip --include-dev --include-launchers --include-venv --include-symbols ${PYTHON_EXTRA_INSTLAL_FLAGS} --copy ${LIBDIR}/python ) - + add_dependencies( + external_python + external_zlib + ) else() if(APPLE) # Disable functions that can be in 10.13 sdk but aren't available on 10.9 target. diff --git a/build_files/build_environment/cmake/sndfile.cmake b/build_files/build_environment/cmake/sndfile.cmake index 192c25f5ed1..a2ac2a33779 100644 --- a/build_files/build_environment/cmake/sndfile.cmake +++ b/build_files/build_environment/cmake/sndfile.cmake @@ -11,18 +11,11 @@ else() set(SNDFILE_OPTIONS --enable-static --disable-shared ) endif() -if(UNIX) - set(SNDFILE_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/sndfile/src/external_sndfile < ${PATCH_DIR}/sndfile.diff) -else() - set(SNDFILE_PATCH_CMD) -endif() - ExternalProject_Add(external_sndfile URL file://${PACKAGE_DIR}/${SNDFILE_FILE} DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${SNDFILE_HASH_TYPE}=${SNDFILE_HASH} PREFIX ${BUILD_DIR}/sndfile - PATCH_COMMAND ${SNDFILE_PATCH_CMD} CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && ${SNDFILE_ENV} ${CONFIGURE_COMMAND} ${SNDFILE_OPTIONS} --prefix=${mingw_LIBDIR}/sndfile BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make install diff --git a/build_files/build_environment/cmake/sqlite.cmake b/build_files/build_environment/cmake/sqlite.cmake index c82d832574a..c151a495ff1 100644 --- a/build_files/build_environment/cmake/sqlite.cmake +++ b/build_files/build_environment/cmake/sqlite.cmake @@ -48,7 +48,6 @@ ExternalProject_Add(external_sqlite DOWNLOAD_DIR ${DOWNLOAD_DIR} URL_HASH ${SQLITE_HASH_TYPE}=${SQLITE_HASH} PREFIX ${BUILD_DIR}/sqlite - PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/sqlite/src/external_sqlite < ${PATCH_DIR}/sqlite.diff CONFIGURE_COMMAND ${SQLITE_CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/sqlite ${SQLITE_CONFIGURATION_ARGS} BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make install diff --git a/build_files/build_environment/cmake/ssl.cmake b/build_files/build_environment/cmake/ssl.cmake index 21c4d2418c3..628187dc0ac 100644 --- a/build_files/build_environment/cmake/ssl.cmake +++ b/build_files/build_environment/cmake/ssl.cmake @@ -5,6 +5,7 @@ set(SSL_PATCH_CMD echo .) if(APPLE) set(SSL_OS_COMPILER "blender-darwin-${CMAKE_OSX_ARCHITECTURES}") + set(SSL_PATCH_CMD ${PATCH_CMD} --verbose -p 0 -d ${BUILD_DIR}/ssl/src/external_ssl < ${PATCH_DIR}/ssl.diff) else() if(BLENDER_PLATFORM_ARM) set(SSL_OS_COMPILER "blender-linux-aarch64") diff --git a/build_files/build_environment/cmake/tiff.cmake b/build_files/build_environment/cmake/tiff.cmake index 1f8e9442ae5..1ac2e4c6058 100644 --- a/build_files/build_environment/cmake/tiff.cmake +++ b/build_files/build_environment/cmake/tiff.cmake @@ -25,6 +25,7 @@ ExternalProject_Add(external_tiff add_dependencies( external_tiff external_zlib + external_jpeg ) if(WIN32) if(BUILD_MODE STREQUAL Release) diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index bfc6d27f74d..328f5b8efc3 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -8,9 +8,9 @@ # Not all of our dependencies are currently in the nvd database so not all # dependencies have one assigned. -set(ZLIB_VERSION 1.2.12) +set(ZLIB_VERSION 1.2.13) set(ZLIB_URI https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz) -set(ZLIB_HASH 5fc414a9726be31427b440b434d05f78) +set(ZLIB_HASH 9b8aa094c4e5765dabf4da391f00d15c) set(ZLIB_HASH_TYPE MD5) set(ZLIB_FILE zlib-${ZLIB_VERSION}.tar.gz) set(ZLIB_CPE "cpe:2.3:a:zlib:zlib:${ZLIB_VERSION}:*:*:*:*:*:*:*") @@ -88,9 +88,9 @@ else() set(OPENEXR_VERSION_POSTFIX) endif() -set(FREETYPE_VERSION 2.11.1) +set(FREETYPE_VERSION 2.12.1) set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz) -set(FREETYPE_HASH bd4e3b007474319909a6b79d50908e85) +set(FREETYPE_HASH 8bc5c9c9df7ac12c504f8918552a7cf2) set(FREETYPE_HASH_TYPE MD5) set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz) SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*") @@ -159,9 +159,9 @@ set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${ set(OPENMP_HASH_TYPE MD5) set(OPENMP_FILE openmp-${OPENMP_VERSION}.src.tar.xz) -set(OPENIMAGEIO_VERSION v2.3.13.0) +set(OPENIMAGEIO_VERSION v2.3.20.0) set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/refs/tags/${OPENIMAGEIO_VERSION}.tar.gz) -set(OPENIMAGEIO_HASH de45fb38501c4581062b522b53b6141c) +set(OPENIMAGEIO_HASH defb1fe7c8e64bac60eb3cacaf5c3736) set(OPENIMAGEIO_HASH_TYPE MD5) set(OPENIMAGEIO_FILE OpenImageIO-${OPENIMAGEIO_VERSION}.tar.gz) @@ -189,17 +189,17 @@ set(TIFF_HASH_TYPE MD5) set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz) set(TIFF_CPE "cpe:2.3:a:libtiff:libtiff:${TIFF_VERSION}:*:*:*:*:*:*:*") -set(OSL_VERSION 1.11.17.0) -set(OSL_URI https://github.com/imageworks/OpenShadingLanguage/archive/Release-${OSL_VERSION}.tar.gz) -set(OSL_HASH 63265472ce14548839ace2e21e401544) +set(OSL_VERSION 1.12.6.2) +set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/refs/tags/v${OSL_VERSION}.tar.gz) +set(OSL_HASH 6fef11548adfdd3e5b25c49d2dae96ee) set(OSL_HASH_TYPE MD5) set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz) -set(PYTHON_VERSION 3.10.2) +set(PYTHON_VERSION 3.10.8) set(PYTHON_SHORT_VERSION 3.10) set(PYTHON_SHORT_VERSION_NO_DOTS 310) set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz) -set(PYTHON_HASH 14e8c22458ed7779a1957b26cde01db9) +set(PYTHON_HASH e92356b012ed4d0e09675131d39b1bde) set(PYTHON_HASH_TYPE MD5) set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz) set(PYTHON_CPE "cpe:2.3:a:python:python:${PYTHON_VERSION}:-:*:*:*:*:*:*") @@ -298,17 +298,17 @@ set(XVIDCORE_HASH abbdcbd39555691dd1c9b4d08f0a031376a3b211652c0d8b3b8aa9be1303ce set(XVIDCORE_HASH_TYPE SHA256) set(XVIDCORE_FILE xvidcore-${XVIDCORE_VERSION}.tar.gz) -set(OPENJPEG_VERSION 2.4.0) -set(OPENJPEG_SHORT_VERSION 2.4) +set(OPENJPEG_VERSION 2.5.0) +set(OPENJPEG_SHORT_VERSION 2.5) set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz) -set(OPENJPEG_HASH 8702ba68b442657f11aaeb2b338443ca8d5fb95b0d845757968a7be31ef7f16d) +set(OPENJPEG_HASH 0333806d6adecc6f7a91243b2b839ff4d2053823634d4f6ed7a59bc87409122a) set(OPENJPEG_HASH_TYPE SHA256) set(OPENJPEG_FILE openjpeg-v${OPENJPEG_VERSION}.tar.gz) set(OPENJPEG_CPE "cpe:2.3:a:uclouvain:openjpeg:${OPENJPEG_VERSION}:*:*:*:*:*:*:*") -set(FFMPEG_VERSION 5.0) +set(FFMPEG_VERSION 5.1.2) set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2) -set(FFMPEG_HASH c0130b8db2c763430fd1c6905288d61bc44ee0548ad5fcd2dfd650b88432bed9) +set(FFMPEG_HASH 39a0bcc8d98549f16c570624678246a6ac736c066cebdb409f9502e915b22f2b) set(FFMPEG_HASH_TYPE SHA256) set(FFMPEG_FILE ffmpeg-${FFMPEG_VERSION}.tar.bz2) set(FFMPEG_CPE "cpe:2.3:a:ffmpeg:ffmpeg:${FFMPEG_VERSION}:*:*:*:*:*:*:*") @@ -325,9 +325,9 @@ set(ICONV_HASH 7d2a800b952942bb2880efb00cfd524c) set(ICONV_HASH_TYPE MD5) set(ICONV_FILE libiconv-${ICONV_VERSION}.tar.gz) -set(SNDFILE_VERSION 1.0.28) -set(SNDFILE_URI http://www.mega-nerd.com/libsndfile/files/libsndfile-${SNDFILE_VERSION}.tar.gz) -set(SNDFILE_HASH 646b5f98ce89ac60cdb060fcd398247c) +set(SNDFILE_VERSION 1.1.0) +set(SNDFILE_URI https://github.com/libsndfile/libsndfile/releases/download/1.1.0/libsndfile-${SNDFILE_VERSION}.tar.xz) +set(SNDFILE_HASH e63dead2b4f0aaf323687619d007ee6a) set(SNDFILE_HASH_TYPE MD5) set(SNDFILE_FILE libsndfile-${SNDFILE_VERSION}.tar.gz) set(SNDFILE_CPE "cpe:2.3:a:libsndfile_project:libsndfile:${SNDFILE_VERSION}:*:*:*:*:*:*:*") @@ -351,21 +351,13 @@ set(JEMALLOC_HASH 3d41fbf006e6ebffd489bdb304d009ae) set(JEMALLOC_HASH_TYPE MD5) set(JEMALLOC_FILE jemalloc-${JEMALLOC_VERSION}.tar.bz2) -set(XML2_VERSION 2.9.10) -set(XML2_URI http://xmlsoft.org/sources/libxml2-${XML2_VERSION}.tar.gz) -set(XML2_HASH 10942a1dc23137a8aa07f0639cbfece5) +set(XML2_VERSION 2.10.3) +set(XML2_URI https://download.gnome.org/sources/libxml2/2.10/libxml2-${XML2_VERSION}.tar.xz) +set(XML2_HASH f9edac7fac232b3657a003fd9a5bbe42) set(XML2_HASH_TYPE MD5) -set(XML2_FILE libxml2-${XML2_VERSION}.tar.gz) +set(XML2_FILE libxml2-${XML2_VERSION}.tar.xz) set(XML2_CPE "cpe:2.3:a:xmlsoft:libxml2:${XML2_VERSION}:*:*:*:*:*:*:*") -set(TINYXML_VERSION 2_6_2) -set(TINYXML_VERSION_DOTS 2.6.2) -set(TINYXML_URI https://nchc.dl.sourceforge.net/project/tinyxml/tinyxml/${TINYXML_VERSION_DOTS}/tinyxml_${TINYXML_VERSION}.tar.gz) -set(TINYXML_HASH c1b864c96804a10526540c664ade67f0) -set(TINYXML_HASH_TYPE MD5) -set(TINYXML_FILE tinyxml_${TINYXML_VERSION}.tar.gz) -set(TINYXML_CPE "cpe:2.3:a:tinyxml_project:tinyxml:${TINYXML_VERSION_DOTS}:*:*:*:*:*:*:*") - set(YAMLCPP_VERSION 0.6.3) set(YAMLCPP_URI https://codeload.github.com/jbeder/yaml-cpp/tar.gz/yaml-cpp-${YAMLCPP_VERSION}) set(YAMLCPP_HASH b45bf1089a382e81f6b661062c10d0c2) @@ -379,10 +371,10 @@ set(PYSTRING_HASH f2c68786b359f5e4e62bed53bc4fb86d) set(PYSTRING_HASH_TYPE MD5) set(PYSTRING_FILE pystring-${PYSTRING_VERSION}.tar.gz) -set(EXPAT_VERSION 2_4_4) -set(EXPAT_VERSION_DOTS 2.4.4) +set(EXPAT_VERSION 2_5_0) +set(EXPAT_VERSION_DOTS 2.5.0) set(EXPAT_URI https://github.com/libexpat/libexpat/archive/R_${EXPAT_VERSION}.tar.gz) -set(EXPAT_HASH 2d3e81dee94b452369dc6394ff0f8f98) +set(EXPAT_HASH d375fa3571c0abb945873f5061a8f2e2) set(EXPAT_HASH_TYPE MD5) set(EXPAT_FILE libexpat-${EXPAT_VERSION}.tar.gz) set(EXPAT_CPE "cpe:2.3:a:libexpat_project:libexpat:${EXPAT_VERSION_DOTS}:*:*:*:*:*:*:*") @@ -410,6 +402,10 @@ set(FLEX_FILE flex-${FLEX_VERSION}.tar.gz) # NOTE: bzip.org domain does no longer belong to BZip 2 project, so we download # sources from Debian packaging. +# +# NOTE 2: This will *HAVE* to match the version python ships on windows which +# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there +# can be no exceptions to this. set(BZIP2_VERSION 1.0.8) set(BZIP2_URI http://http.debian.net/debian/pool/main/b/bzip2/bzip2_${BZIP2_VERSION}.orig.tar.gz) set(BZIP2_HASH ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269) @@ -417,6 +413,9 @@ set(BZIP2_HASH_TYPE SHA256) set(BZIP2_FILE bzip2_${BZIP2_VERSION}.orig.tar.gz) set(BZIP2_CPE "cpe:2.3:a:bzip:bzip2:${BZIP2_VERSION}:*:*:*:*:*:*:*") +# NOTE: This will *HAVE* to match the version python ships on windows which +# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there +# can be no exceptions to this. set(FFI_VERSION 3.3) set(FFI_URI https://sourceware.org/pub/libffi/libffi-${FFI_VERSION}.tar.gz) set(FFI_HASH 72fba7922703ddfa7a028d513ac15a85c8d54c8d67f55fa5a4802885dc652056) @@ -430,27 +429,25 @@ set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df) set(LZMA_HASH_TYPE SHA256) set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2) -if(BLENDER_PLATFORM_ARM) - # Need at least 1.1.1i for aarch64 support (https://github.com/openssl/openssl/pull/13218) - set(SSL_VERSION 1.1.1i) - set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz) - set(SSL_HASH e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242) - set(SSL_HASH_TYPE SHA256) - set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) -else() - set(SSL_VERSION 1.1.1g) - set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz) - set(SSL_HASH ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46) - set(SSL_HASH_TYPE SHA256) - set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) -endif() +# NOTE: This will *HAVE* to match the version python ships on windows which +# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there +# can be no exceptions to this. +set(SSL_VERSION 1.1.1q) +set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz) +set(SSL_HASH d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca) +set(SSL_HASH_TYPE SHA256) +set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*") -set(SQLITE_VERSION 3.31.1) -set(SQLITE_URI https://www.sqlite.org/2018/sqlite-src-3240000.zip) -set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7) +# Note: This will *HAVE* to match the version python ships on windows which +# is hardcoded in pythons PCbuild/get_externals.bat for compliance reasons there +# can be no exceptions to this. +set(SQLITE_VERSION 3.37.2) +set(SQLLITE_LONG_VERSION 3370200) +set(SQLITE_URI https://www.sqlite.org/2022/sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz) +set(SQLITE_HASH e56faacadfb4154f8fbd0f2a3f827d13706b70a1) set(SQLITE_HASH_TYPE SHA1) -set(SQLITE_FILE sqlite-src-3240000.zip) +set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz) set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*") set(EMBREE_VERSION 3.13.4) @@ -561,22 +558,22 @@ set(BROTLI_HASH_TYPE SHA256) set(BROTLI_FILE brotli-v${BROTLI_VERSION}.tar.gz) set(BROTLI_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*") -set(OPENPGL_VERSION v0.4.0-beta) -set(OPENPGL_SHORT_VERSION 0.4.0) +set(OPENPGL_VERSION v0.4.1-beta) +set(OPENPGL_SHORT_VERSION 0.4.1) set(OPENPGL_URI https://github.com/OpenPathGuidingLibrary/openpgl/archive/refs/tags/${OPENPGL_VERSION}.tar.gz) -set(OPENPGL_HASH 58d5b65c533ce6cac3f7e1d51cf169a5411adf356abcd85f04049bbcaecc2e77) +set(OPENPGL_HASH db63f5dac5cfa8c110ede241f0c413f00db0c4748697381c4fa23e0f9e82a754) set(OPENPGL_HASH_TYPE SHA256) set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz) -set(LEVEL_ZERO_VERSION v1.7.15) +set(LEVEL_ZERO_VERSION v1.8.5) set(LEVEL_ZERO_URI https://github.com/oneapi-src/level-zero/archive/refs/tags/${LEVEL_ZERO_VERSION}.tar.gz) -set(LEVEL_ZERO_HASH c39bb05a8e5898aa6c444e1704105b93d3f1888b9c333f8e7e73825ffbfb2617) +set(LEVEL_ZERO_HASH b6e9663bbcc53c148d32376998298bec6f7c434ef2218c61fa708963e3a09394) set(LEVEL_ZERO_HASH_TYPE SHA256) set(LEVEL_ZERO_FILE level-zero-${LEVEL_ZERO_VERSION}.tar.gz) -set(DPCPP_VERSION 20220812) +set(DPCPP_VERSION 20221019) set(DPCPP_URI https://github.com/intel/llvm/archive/refs/tags/sycl-nightly/${DPCPP_VERSION}.tar.gz) -set(DPCPP_HASH 0e3c95346c295f5cf80f3a42d80b1c49481955898530242636ddc002627248d6) +set(DPCPP_HASH 2f533946e91ce3829431758ea17b0b834b960c1a796e9e4563c86e03eb9603a2) set(DPCPP_HASH_TYPE SHA256) set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz) @@ -589,9 +586,9 @@ set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz) # will take care of building them, unpack is being done in dpcpp_deps.cmake # Source llvm/lib/SYCLLowerIR/CMakeLists.txt -set(VCINTRINSICS_VERSION 984bb27baacce6ee5c716c2e64845f2a1928025b) +set(VCINTRINSICS_VERSION abce9184b7a3a7fe1b02289b9285610d9dc45465) set(VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/${VCINTRINSICS_VERSION}.tar.gz) -set(VCINTRINSICS_HASH abea415a15a0dd11fdc94dee8fb462910f2548311b787e02f42509789e1b0d7b) +set(VCINTRINSICS_HASH 3e9fd471246b87633b26f7e15e17ab7733d357458c53d5c5881c03929d6c551f) set(VCINTRINSICS_HASH_TYPE SHA256) set(VCINTRINSICS_FILE vc-intrinsics-${VCINTRINSICS_VERSION}.tar.gz) @@ -603,9 +600,9 @@ set(OPENCLHEADERS_HASH_TYPE SHA256) set(OPENCLHEADERS_FILE opencl_headers-${OPENCLHEADERS_VERSION}.tar.gz) # Source opencl/CMakeLists.txt -set(ICDLOADER_VERSION aec3952654832211636fc4af613710f80e203b0a) +set(ICDLOADER_VERSION 792682ad3d877ab38573b997808bab3b43902b70) set(ICDLOADER_URI https://github.com/KhronosGroup/OpenCL-ICD-Loader/archive/${ICDLOADER_VERSION}.tar.gz) -set(ICDLOADER_HASH e1880551d67bd8dc31d13de63b94bbfd6b1f315b6145dad1ffcd159b89bda93c) +set(ICDLOADER_HASH b33a0320d94bf300efa1da97931ded506d27813bd1148da6858fe79d412d1ea2) set(ICDLOADER_HASH_TYPE SHA256) set(ICDLOADER_FILE icdloader-${ICDLOADER_VERSION}.tar.gz) @@ -620,9 +617,9 @@ set(MP11_FILE mp11-${MP11_VERSION}.tar.gz) # Source llvm-spirv/CMakeLists.txt (repo) # Source llvm-spirv/spirv-headers-tag.conf (hash) -set(SPIRV_HEADERS_VERSION 36c0c1596225e728bd49abb7ef56a3953e7ed468) +set(SPIRV_HEADERS_VERSION 5a121866927a16ab9d49bed4788b532c7fcea766) set(SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/${SPIRV_HEADERS_VERSION}.tar.gz) -set(SPIRV_HEADERS_HASH 7a5c89633f8740456fe8adee052033e134476d267411d1336c0cb1e587a9229a) +set(SPIRV_HEADERS_HASH ec8ecb471a62672697846c436501638ab25447ae9d4a6761e0bfe8a9a839502a) set(SPIRV_HEADERS_HASH_TYPE SHA256) set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz) @@ -637,9 +634,9 @@ set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz) # compiler, the versions used are taken from the following location # https://github.com/intel/intel-graphics-compiler/releases -set(IGC_VERSION 1.0.11222) +set(IGC_VERSION 1.0.12149.1) set(IGC_URI https://github.com/intel/intel-graphics-compiler/archive/refs/tags/igc-${IGC_VERSION}.tar.gz) -set(IGC_HASH d92f0608dcbb52690855685f9447282e5c09c0ba98ae35fabf114fcf8b1e9fcf) +set(IGC_HASH 44f67f24e3bc5130f9f062533abf8154782a9d0a992bc19b498639a8521ae836) set(IGC_HASH_TYPE SHA256) set(IGC_FILE igc-${IGC_VERSION}.tar.gz) @@ -659,15 +656,15 @@ set(IGC_LLVM_FILE ${IGC_LLVM_VERSION}.tar.gz) # # WARNING WARNING WARNING -set(IGC_OPENCL_CLANG_VERSION bbdd1587f577397a105c900be114b56755d1f7dc) +set(IGC_OPENCL_CLANG_VERSION 363a5262d8c7cff3fb28f3bdb5d85c8d7e91c1bb) set(IGC_OPENCL_CLANG_URI https://github.com/intel/opencl-clang/archive/${IGC_OPENCL_CLANG_VERSION}.tar.gz) -set(IGC_OPENCL_CLANG_HASH d08315f1b0d8a6fef33de2b3e6aa7356534c324910634962c72523d970773efc) +set(IGC_OPENCL_CLANG_HASH aa8cf72bb239722ce8ce44f79413c6887ecc8ca18477dd520aa5c4809756da9a) set(IGC_OPENCL_CLANG_HASH_TYPE SHA256) set(IGC_OPENCL_CLANG_FILE opencl-clang-${IGC_OPENCL_CLANG_VERSION}.tar.gz) -set(IGC_VCINTRINSICS_VERSION v0.4.0) +set(IGC_VCINTRINSICS_VERSION v0.5.0) set(IGC_VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/refs/tags/${IGC_VCINTRINSICS_VERSION}.tar.gz) -set(IGC_VCINTRINSICS_HASH c8b92682ad5031cf9d5b82a40e7d5c0e763cd9278660adbcaa69aab988e4b589) +set(IGC_VCINTRINSICS_HASH 70bb47c5e32173cf61514941e83ae7c7eb4485e6d2fca60cfa1f50d4f42c41f2) set(IGC_VCINTRINSICS_HASH_TYPE SHA256) set(IGC_VCINTRINSICS_FILE vc-intrinsics-${IGC_VCINTRINSICS_VERSION}.tar.gz) @@ -683,9 +680,9 @@ set(IGC_SPIRV_TOOLS_HASH 6e19900e948944243024aedd0a201baf3854b377b9cc7a386553bc1 set(IGC_SPIRV_TOOLS_HASH_TYPE SHA256) set(IGC_SPIRV_TOOLS_FILE SPIR-V-Tools-${IGC_SPIRV_TOOLS_VERSION}.tar.gz) -set(IGC_SPIRV_TRANSLATOR_VERSION 99420daab98998a7e36858befac9c5ed109d4920) +set(IGC_SPIRV_TRANSLATOR_VERSION a31ffaeef77e23d500b3ea3d35e0c42ff5648ad9) set(IGC_SPIRV_TRANSLATOR_URI https://github.com/KhronosGroup/SPIRV-LLVM-Translator/archive/${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz) -set(IGC_SPIRV_TRANSLATOR_HASH 77dfb4ddb6bfb993535562c02ddea23f0a0d1c5a0258c1afe7e27c894ff783a8) +set(IGC_SPIRV_TRANSLATOR_HASH 9e26c96a45341b8f8af521bacea20e752623346340addd02af95d669f6e89252) set(IGC_SPIRV_TRANSLATOR_HASH_TYPE SHA256) set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz) @@ -693,15 +690,15 @@ set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}. ### Intel Graphics Compiler DEPS END ### ######################################## -set(GMMLIB_VERSION intel-gmmlib-22.1.2) +set(GMMLIB_VERSION intel-gmmlib-22.1.8) set(GMMLIB_URI https://github.com/intel/gmmlib/archive/refs/tags/${GMMLIB_VERSION}.tar.gz) -set(GMMLIB_HASH 3b9a6d5e7e3f5748b3d0a2fb0e980ae943907fece0980bd9c0508e71c838e334) +set(GMMLIB_HASH bf23e9a3742b4fb98c7666c9e9b29f3219e4b2fb4d831aaf4eed71f5e2d17368) set(GMMLIB_HASH_TYPE SHA256) set(GMMLIB_FILE ${GMMLIB_VERSION}.tar.gz) -set(OCLOC_VERSION 22.20.23198) +set(OCLOC_VERSION 22.38.24278) set(OCLOC_URI https://github.com/intel/compute-runtime/archive/refs/tags/${OCLOC_VERSION}.tar.gz) -set(OCLOC_HASH ab22b8bf2560a57fdd3def0e35a62ca75991406f959c0263abb00cd6cd9ae998) +set(OCLOC_HASH db0c542fccd651e6404b15a74d46027f1ce0eda8dc9e25a40cbb6c0faef257ee) set(OCLOC_HASH_TYPE SHA256) set(OCLOC_FILE ocloc-${OCLOC_VERSION}.tar.gz) diff --git a/build_files/build_environment/cmake/wayland.cmake b/build_files/build_environment/cmake/wayland.cmake index 799f2513da9..c73db1d10ff 100644 --- a/build_files/build_environment/cmake/wayland.cmake +++ b/build_files/build_environment/cmake/wayland.cmake @@ -7,10 +7,14 @@ ExternalProject_Add(external_wayland PREFIX ${BUILD_DIR}/wayland PATCH_COMMAND ${PATCH_CMD} -d ${BUILD_DIR}/wayland/src/external_wayland < ${PATCH_DIR}/wayland.diff # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT & LIBXML2. - # Note that passing link args "ffi/lib" should not be needed, but + # + # NOTE: passing link args "ffi/lib" should not be needed, but # `pkgconfig` would incorrectly look in "ffi/lib/../lib64" otherwise. + # + # NOTE: `-lm` is needed for `libxml2` which is a static library that uses `libm.so`, + # without this, math symbols such as `floor` aren't found. CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:${LIBDIR}/ffi/lib/pkgconfig:$PKG_CONFIG_PATH - meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -Dc_link_args=-L${LIBDIR}/ffi/lib . ../external_wayland + meson --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland BUILD_COMMAND ninja INSTALL_COMMAND ninja install ) diff --git a/build_files/build_environment/cmake/xml2.cmake b/build_files/build_environment/cmake/xml2.cmake index cd24fd836b0..3d31ec131bb 100644 --- a/build_files/build_environment/cmake/xml2.cmake +++ b/build_files/build_environment/cmake/xml2.cmake @@ -1,20 +1,48 @@ # SPDX-License-Identifier: GPL-2.0-or-later -ExternalProject_Add(external_xml2 - URL file://${PACKAGE_DIR}/${XML2_FILE} - DOWNLOAD_DIR ${DOWNLOAD_DIR} - URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} - PREFIX ${BUILD_DIR}/xml2 - CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND} - --prefix=${LIBDIR}/xml2 - --disable-shared - --enable-static - --with-pic - --with-python=no - --with-lzma=no - --with-zlib=no - --with-iconv=no - BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS} - INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install - INSTALL_DIR ${LIBDIR}/xml2 -) +if(WIN32) + set(XML2_EXTRA_ARGS + -DLIBXML2_WITH_ZLIB=OFF + -DLIBXML2_WITH_LZMA=OFF + -DLIBXML2_WITH_PYTHON=OFF + -DLIBXML2_WITH_ICONV=OFF + -DLIBXML2_WITH_TESTS=OFF + -DLIBXML2_WITH_PROGRAMS=OFF + -DBUILD_SHARED_LIBS=OFF + ) + ExternalProject_Add(external_xml2 + URL file://${PACKAGE_DIR}/${XML2_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/xml2 ${DEFAULT_CMAKE_FLAGS} ${XML2_EXTRA_ARGS} + PREFIX ${BUILD_DIR}/xml2 + INSTALL_DIR ${LIBDIR}/xml2 + ) +else() + ExternalProject_Add(external_xml2 + URL file://${PACKAGE_DIR}/${XML2_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} + PREFIX ${BUILD_DIR}/xml2 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND} + --prefix=${LIBDIR}/xml2 + --disable-shared + --enable-static + --with-pic + --with-python=no + --with-lzma=no + --with-zlib=no + --with-iconv=no + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install + INSTALL_DIR ${LIBDIR}/xml2 + ) +endif() + +if(WIN32 AND BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_xml2 after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/xml2/include ${HARVEST_TARGET}/xml2/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/xml2/lib/libxml2s.lib ${HARVEST_TARGET}/xml2/lib/libxml2s.lib + DEPENDEES install + ) +endif() diff --git a/build_files/build_environment/dependencies.dot b/build_files/build_environment/dependencies.dot index 7e8637fbced..bb42856c3ac 100644 --- a/build_files/build_environment/dependencies.dot +++ b/build_files/build_environment/dependencies.dot @@ -1,96 +1,114 @@ strict graph { -graph[autosize = false, size = "25.7,8.3!", resolution = 300, overlap = false, splines = false, outputorder=edgesfirst ]; - node [style=filled fillcolor=white]; - external_alembic -- external_boost; - external_alembic -- external_zlib; +graph[autosize = false, size = "25.7,8.3!", resolution = 300]; external_alembic -- external_openexr; + external_alembic -- external_imath; external_blosc -- external_zlib; external_blosc -- external_pthreads; - external_boost -- Make_Python_Environment; - external_clang -- ll; + external_boost -- external_python; + external_boost -- external_numpy; + external_dpcpp -- external_python; + external_dpcpp -- external_python_site_packages; + external_dpcpp -- external_vcintrinsics; + external_dpcpp -- external_openclheaders; + external_dpcpp -- external_icdloader; + external_dpcpp -- external_mp11; + external_dpcpp -- external_level_zero; + external_dpcpp -- external_spirvheaders; + external_embree -- external_tbb; external_ffmpeg -- external_zlib; - external_ffmpeg -- external_faad; external_ffmpeg -- external_openjpeg; external_ffmpeg -- external_xvidcore; external_ffmpeg -- external_x264; + external_ffmpeg -- external_opus; external_ffmpeg -- external_vpx; external_ffmpeg -- external_theora; external_ffmpeg -- external_vorbis; external_ffmpeg -- external_ogg; external_ffmpeg -- external_lame; + external_ffmpeg -- external_aom; external_ffmpeg -- external_zlib_mingw; - external_numpy -- Make_Python_Environment; + external_ffmpeg -- external_nasm; + external_freetype -- external_brotli; + external_freetype -- external_zlib; + external_gmpxx -- external_gmp; + external_igc_llvm -- external_igc_opencl_clang; + external_igc_spirv_translator -- external_igc_opencl_clang; + external_igc -- external_igc_vcintrinsics; + external_igc -- external_igc_llvm; + external_igc -- external_igc_opencl_clang; + external_igc -- external_igc_vcintrinsics; + external_igc -- external_igc_spirv_headers; + external_igc -- external_igc_spirv_tools; + external_igc -- external_igc_spirv_translator; + external_igc -- external_flex; + external_ispc -- ll; + external_ispc -- external_python; + external_ispc -- external_flexbison; + external_ispc -- external_flex; + ll -- external_xml2; + ll -- external_python; + external_mesa -- ll; + external_numpy -- external_python; + external_numpy -- external_python_site_packages; + external_ocloc -- external_igc; + external_ocloc -- external_gmmlib; external_opencollada -- external_xml2; - external_opencolorio -- external_boost; - external_opencolorio -- external_tinyxml; external_opencolorio -- external_yamlcpp; + external_opencolorio -- external_expat; + external_opencolorio -- external_imath; + external_opencolorio -- external_pystring; external_openexr -- external_zlib; + external_openimagedenoise -- external_tbb; + external_openimagedenoise -- external_ispc; + external_openimagedenoise -- external_python; external_openimageio -- external_png; external_openimageio -- external_zlib; external_openimageio -- external_openexr; - external_openimageio -- external_openexr; + external_openimageio -- external_imath; external_openimageio -- external_jpeg; external_openimageio -- external_boost; external_openimageio -- external_tiff; - external_openimageio -- external_opencolorio; + external_openimageio -- external_pugixml; + external_openimageio -- external_fmt; + external_openimageio -- external_robinmap; external_openimageio -- external_openjpeg; external_openimageio -- external_webp; - external_openimageio -- external_opencolorio_extra; - external_openmp -- external_clang; + external_openmp -- ll; + external_openpgl -- external_tbb; external_opensubdiv -- external_tbb; openvdb -- external_tbb; openvdb -- external_boost; - openvdb -- external_openexr; - openvdb -- external_openexr; openvdb -- external_zlib; openvdb -- external_blosc; external_osl -- external_boost; external_osl -- ll; - external_osl -- external_clang; - external_osl -- external_openexr; external_osl -- external_openexr; external_osl -- external_zlib; - external_osl -- external_flexbison; external_osl -- external_openimageio; external_osl -- external_pugixml; + external_osl -- external_flexbison; + external_osl -- external_flex; external_png -- external_zlib; - external_python_site_packages -- Make_Python_Environment; + external_python -- external_bzip2; + external_python -- external_ffi; + external_python -- external_lzma; + external_python -- external_ssl; + external_python -- external_sqlite; + external_python -- external_zlib; + external_python_site_packages -- external_python; external_sndfile -- external_ogg; external_sndfile -- external_vorbis; external_sndfile -- external_flac; external_theora -- external_vorbis; external_theora -- external_ogg; external_tiff -- external_zlib; + external_usd -- external_tbb; + external_usd -- external_boost; + external_usd -- external_opensubdiv; external_vorbis -- external_ogg; - blender-- external_ffmpeg; - blender-- external_alembic; - blender-- external_openjpeg; - blender-- external_opencolorio; - blender-- external_openexr; - blender-- external_opensubdiv; - blender-- openvdb; - blender-- external_osl; - blender-- external_boost; - blender-- external_jpeg; - blender-- external_png; - blender-- external_python; - blender-- external_sndfile; - blender-- external_iconv; - blender-- external_fftw3; - external_python-- external_python_site_packages; - external_python_site_packages-- requests; - external_python_site_packages-- idna; - external_python_site_packages-- chardet; - external_python_site_packages-- urllib3; - external_python_site_packages-- certifi; - external_python-- external_numpy; - external_usd-- external_boost; - external_usd-- external_tbb; - blender-- external_opencollada; - blender-- external_sdl; - blender-- external_freetype; - blender-- external_pthreads; - blender-- external_zlib; - blender-- external_openal; - blender-- external_usd; + external_wayland -- external_expat; + external_wayland -- external_xml2; + external_wayland -- external_ffi; + external_wayland_protocols -- external_wayland; + external_x264 -- external_nasm; } diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index f913ac5e73c..5a191f7669b 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -394,7 +394,7 @@ CLANG_FORMAT_VERSION="10.0" CLANG_FORMAT_VERSION_MIN="6.0" CLANG_FORMAT_VERSION_MEX="14.0" -PYTHON_VERSION="3.10.2" +PYTHON_VERSION="3.10.8" PYTHON_VERSION_SHORT="3.10" PYTHON_VERSION_MIN="3.10" PYTHON_VERSION_MEX="3.12" @@ -505,7 +505,7 @@ OPENEXR_FORCE_REBUILD=false OPENEXR_SKIP=false _with_built_openexr=false -OIIO_VERSION="2.3.13.0" +OIIO_VERSION="2.3.20.0" OIIO_VERSION_SHORT="2.3" OIIO_VERSION_MIN="2.1.12" OIIO_VERSION_MEX="2.4.0" @@ -523,8 +523,8 @@ LLVM_FORCE_REBUILD=false LLVM_SKIP=false # OSL needs to be compiled for now! -OSL_VERSION="1.11.17.0" -OSL_VERSION_SHORT="1.11" +OSL_VERSION="1.12.6.2" +OSL_VERSION_SHORT="1.12" OSL_VERSION_MIN="1.11" OSL_VERSION_MEX="2.0" OSL_FORCE_BUILD=false @@ -602,10 +602,10 @@ LEVEL_ZERO_FORCE_BUILD=false LEVEL_ZERO_FORCE_REBUILD=false LEVEL_ZERO_SKIP=false -OPENPGL_VERSION="0.3.1" -OPENPGL_VERSION_SHORT="0.3" +OPENPGL_VERSION="0.4.0" +OPENPGL_VERSION_SHORT="0.4" OPENPGL_VERSION_MIN="0.3.1" -OPENPGL_VERSION_MEX="0.3.2" +OPENPGL_VERSION_MEX="0.5" OPENPGL_FORCE_BUILD=false OPENPGL_FORCE_REBUILD=false OPENPGL_SKIP=false @@ -618,8 +618,8 @@ XR_OPENXR_FORCE_BUILD=false XR_OPENXR_FORCE_REBUILD=false XR_OPENXR_SKIP=false -FFMPEG_VERSION="5.0" -FFMPEG_VERSION_SHORT="5.0" +FFMPEG_VERSION="5.1.2" +FFMPEG_VERSION_SHORT="5.1" FFMPEG_VERSION_MIN="4.0" FFMPEG_VERSION_MEX="6.0" FFMPEG_FORCE_BUILD=false @@ -1139,7 +1139,7 @@ LLVM_SOURCE=( "$_LLVM_SOURCE_ROOT/llvm-$LLVM_VERSION.src.tar.xz" ) LLVM_CLANG_SOURCE=( "$_LLVM_SOURCE_ROOT/clang-$LLVM_VERSION.src.tar.xz" "$_LLVM_SOURCE_ROOT/cfe-$LLVM_VERSION.src.tar.xz" ) OSL_USE_REPO=false -OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/Release-$OSL_VERSION.tar.gz" ) +OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/v$OSL_VERSION.tar.gz" ) #~ OSL_SOURCE_REPO=( "https://github.com/imageworks/OpenShadingLanguage.git" ) #~ OSL_SOURCE_REPO_BRANCH="master" #~ OSL_SOURCE_REPO_UID="85179714e1bc69cd25ecb6bb711c1a156685d395" diff --git a/build_files/build_environment/patches/aom.diff b/build_files/build_environment/patches/aom.diff new file mode 100644 index 00000000000..1611cff5dca --- /dev/null +++ b/build_files/build_environment/patches/aom.diff @@ -0,0 +1,18 @@ +diff -Naur libaom-3.4.0/build/cmake/aom_configure.cmake external_aom/build/cmake/aom_configure.cmake +--- libaom-3.4.0/build/cmake/aom_configure.cmake 2022-06-17 11:46:18 -0600 ++++ external_aom/build/cmake/aom_configure.cmake 2022-10-16 15:35:54 -0600 +@@ -15,8 +15,12 @@ + + include(FindGit) + include(FindPerl) +-include(FindThreads) +- ++# Blender: This will drag in a dep on libwinpthreads which we prefer ++# not to have, aom will fallback on a native win32 thread wrapper ++# if pthreads are not found. ++if(NOT WIN32) ++ include(FindThreads) ++endif() + include("${AOM_ROOT}/build/cmake/aom_config_defaults.cmake") + include("${AOM_ROOT}/build/cmake/aom_experiment_deps.cmake") + include("${AOM_ROOT}/build/cmake/aom_optimization.cmake") diff --git a/build_files/build_environment/patches/ffmpeg.diff b/build_files/build_environment/patches/ffmpeg.diff index c255f7c37a3..ac104a20ffe 100644 --- a/build_files/build_environment/patches/ffmpeg.diff +++ b/build_files/build_environment/patches/ffmpeg.diff @@ -68,34 +68,18 @@ + return ret; } ---- a/libavcodec/rl.c -+++ b/libavcodec/rl.c -@@ -71,17 +71,19 @@ - av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size) - { - int i, q; -- VLC_TYPE table[1500][2] = {{0}}; -+ VLC_TYPE (*table)[2] = av_calloc(sizeof(VLC_TYPE), 1500 * 2); - VLC vlc = { .table = table, .table_allocated = static_size }; -- av_assert0(static_size <= FF_ARRAY_ELEMS(table)); -+ av_assert0(static_size < 1500); - init_vlc(&vlc, 9, rl->n + 1, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC); +diff --git a/libavcodec/x86/simple_idct.asm b/libavcodec/x86/simple_idct.asm +index dcf0da6df121..982b2f0bbba1 100644 +--- a/libavcodec/x86/simple_idct.asm ++++ b/libavcodec/x86/simple_idct.asm +@@ -25,9 +25,9 @@ - for (q = 0; q < 32; q++) { - int qmul = q * 2; - int qadd = (q - 1) | 1; + %include "libavutil/x86/x86util.asm" -- if (!rl->rl_vlc[q]) -+ if (!rl->rl_vlc[q]){ -+ av_free(table); - return; -+ } +-%if ARCH_X86_32 + SECTION_RODATA - if (q == 0) { - qmul = 1; -@@ -113,4 +115,5 @@ - rl->rl_vlc[q][i].run = run; - } - } -+ av_free(table); - } ++%if ARCH_X86_32 + cextern pb_80 + + wm1010: dw 0, 0xffff, 0, 0xffff diff --git a/build_files/build_environment/patches/gmp.diff b/build_files/build_environment/patches/gmp.diff new file mode 100644 index 00000000000..bf22f93bc4f --- /dev/null +++ b/build_files/build_environment/patches/gmp.diff @@ -0,0 +1,15 @@ +--- a/mpz/inp_raw.c Tue Dec 22 23:49:51 2020 +0100 ++++ b/mpz/inp_raw.c Thu Oct 21 19:06:49 2021 +0200 +@@ -88,8 +88,11 @@ + + abs_csize = ABS (csize); + ++ if (UNLIKELY (abs_csize > ~(mp_bitcnt_t) 0 / 8)) ++ return 0; /* Bit size overflows */ ++ + /* round up to a multiple of limbs */ +- abs_xsize = BITS_TO_LIMBS (abs_csize*8); ++ abs_xsize = BITS_TO_LIMBS ((mp_bitcnt_t) abs_csize * 8); + + if (abs_xsize != 0) + { diff --git a/build_files/build_environment/patches/opencollada.diff b/build_files/build_environment/patches/opencollada.diff index e8efc1a6909..02eab251a13 100644 --- a/build_files/build_environment/patches/opencollada.diff +++ b/build_files/build_environment/patches/opencollada.diff @@ -130,3 +130,28 @@ index 715d903..24423ce 100644 { string id = node.attribute("id").value(); size_t line = node.line(); +diff -Naur a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -274,7 +274,7 @@ + add_subdirectory(${EXTERNAL_LIBRARIES}/UTF) + add_subdirectory(common/libBuffer) + add_subdirectory(${EXTERNAL_LIBRARIES}/MathMLSolver) +-add_subdirectory(${EXTERNAL_LIBRARIES}/zlib) ++#add_subdirectory(${EXTERNAL_LIBRARIES}/zlib) + + # building OpenCOLLADA libs + add_subdirectory(COLLADABaseUtils) +@@ -284,10 +284,10 @@ + add_subdirectory(COLLADAStreamWriter) + + # building COLLADAValidator app +-add_subdirectory(COLLADAValidator) ++#add_subdirectory(COLLADAValidator) + + # DAE validator app +-add_subdirectory(DAEValidator) ++#add_subdirectory(DAEValidator) + + # Library export + install(EXPORT LibraryExport DESTINATION ${OPENCOLLADA_INST_CMAKECONFIG} FILE OpenCOLLADATargets.cmake) diff --git a/build_files/build_environment/patches/osl.diff b/build_files/build_environment/patches/osl.diff index 28e1d6e101d..3f4a485b037 100644 --- a/build_files/build_environment/patches/osl.diff +++ b/build_files/build_environment/patches/osl.diff @@ -1,67 +1,53 @@ -diff -Naur OpenShadingLanguage-Release-1.9.9/src/include/OSL/llvm_util.h external_osl/src/include/OSL/llvm_util.h ---- OpenShadingLanguage-Release-1.9.9/src/include/OSL/llvm_util.h 2018-05-01 16:39:02 -0600 -+++ external_osl/src/include/OSL/llvm_util.h 2018-08-25 14:05:00 -0600 -@@ -33,6 +33,8 @@ - - #include <vector> - -+#define OSL_HAS_BLENDER_CLEANUP_FIX -+ - #ifdef LLVM_NAMESPACE - namespace llvm = LLVM_NAMESPACE; - #endif -@@ -487,6 +489,7 @@ - std::string func_name (llvm::Function *f); - - static size_t total_jit_memory_held (); -+ static void Cleanup (); - - private: - class MemoryManager; -diff -Naur OpenShadingLanguage-Release-1.9.9/src/liboslexec/llvm_util.cpp external_osl/src/liboslexec/llvm_util.cpp ---- OpenShadingLanguage-Release-1.9.9/src/liboslexec/llvm_util.cpp 2018-05-01 16:39:02 -0600 -+++ external_osl/src/liboslexec/llvm_util.cpp 2018-08-25 14:04:27 -0600 -@@ -140,7 +140,10 @@ - }; - - -- -+void LLVM_Util::Cleanup () -+{ -+ if(jitmm_hold) jitmm_hold->clear(); -+} - - size_t - LLVM_Util::total_jit_memory_held () -diff -Naur org/CMakeLists.txt external_osl/CMakeLists.txt ---- org/CMakeLists.txt 2020-12-01 12:37:15 -0700 -+++ external_osl/CMakeLists.txt 2021-01-20 13:26:50 -0700 -@@ -84,6 +84,11 @@ +diff -Naur OpenShadingLanguage-1.12.6.2/CMakeLists.txt external_osl/CMakeLists.txt +--- OpenShadingLanguage-1.12.6.2/CMakeLists.txt 2022-09-30 17:43:53 -0600 ++++ external_osl/CMakeLists.txt 2022-10-15 14:49:26 -0600 +@@ -101,6 +101,11 @@ CACHE STRING "Directory where OptiX PTX files will be installed") set (CMAKE_DEBUG_POSTFIX "" CACHE STRING "Library naming postfix for Debug builds (e.g., '_debug')") - + +set (USE_OIIO_STATIC ON CACHE BOOL "If OIIO is built static") +if (USE_OIIO_STATIC) + add_definitions ("-DOIIO_STATIC_BUILD=1") + add_definitions ("-DOIIO_STATIC_DEFINE=1") +endif () - + set (OSL_NO_DEFAULT_TEXTURESYSTEM OFF CACHE BOOL "Do not use create a raw OIIO::TextureSystem") if (OSL_NO_DEFAULT_TEXTURESYSTEM) -diff -Naur external_osl_orig/src/cmake/externalpackages.cmake external_osl/src/cmake/externalpackages.cmake ---- external_osl_orig/src/cmake/externalpackages.cmake 2021-06-01 13:44:18 -0600 -+++ external_osl/src/cmake/externalpackages.cmake 2021-06-28 07:44:32 -0600 -@@ -80,6 +80,7 @@ - - +diff -Naur OpenShadingLanguage-1.12.6.2/src/cmake/externalpackages.cmake external_osl/src/cmake/externalpackages.cmake +--- OpenShadingLanguage-1.12.6.2/src/cmake/externalpackages.cmake 2022-09-30 17:43:53 -0600 ++++ external_osl/src/cmake/externalpackages.cmake 2022-10-15 14:49:26 -0600 +@@ -77,6 +77,7 @@ + + checked_find_package (ZLIB REQUIRED) # Needed by several packages +checked_find_package (PNG REQUIRED) # Needed since OIIO needs it - + # IlmBase & OpenEXR checked_find_package (OpenEXR REQUIRED -diff -Naur external_osl_orig/src/liboslcomp/oslcomp.cpp external_osl/src/liboslcomp/oslcomp.cpp ---- external_osl_orig/src/liboslcomp/oslcomp.cpp 2021-06-01 13:44:18 -0600 -+++ external_osl/src/liboslcomp/oslcomp.cpp 2021-06-28 09:11:06 -0600 +diff -Naur OpenShadingLanguage-1.12.6.2/src/include/OSL/llvm_util.h external_osl/src/include/OSL/llvm_util.h +--- OpenShadingLanguage-1.12.6.2/src/include/OSL/llvm_util.h 2022-09-30 17:43:53 -0600 ++++ external_osl/src/include/OSL/llvm_util.h 2022-10-15 15:37:24 -0600 +@@ -9,6 +9,8 @@ + #include <unordered_set> + #include <vector> + ++#define OSL_HAS_BLENDER_CLEANUP_FIX ++ + #ifdef LLVM_NAMESPACE + namespace llvm = LLVM_NAMESPACE; + #endif +@@ -455,7 +457,7 @@ + llvm::BasicBlock* masked_return_block() const; + + bool is_masking_required() const { return m_is_masking_required; } +- ++ static void Cleanup (); + struct ScopedMasking { + ScopedMasking() {} + +diff -Naur OpenShadingLanguage-1.12.6.2/src/liboslcomp/oslcomp.cpp external_osl/src/liboslcomp/oslcomp.cpp +--- OpenShadingLanguage-1.12.6.2/src/liboslcomp/oslcomp.cpp 2022-09-30 17:43:53 -0600 ++++ external_osl/src/liboslcomp/oslcomp.cpp 2022-10-15 14:49:26 -0600 @@ -21,6 +21,13 @@ #if !defined(__STDC_CONSTANT_MACROS) # define __STDC_CONSTANT_MACROS 1 @@ -76,3 +62,50 @@ diff -Naur external_osl_orig/src/liboslcomp/oslcomp.cpp external_osl/src/liboslc #include <clang/Basic/TargetInfo.h> #include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/TextDiagnosticPrinter.h> +diff -Naur OpenShadingLanguage-1.12.6.2/src/liboslexec/llvm_util.cpp external_osl/src/liboslexec/llvm_util.cpp +--- OpenShadingLanguage-1.12.6.2/src/liboslexec/llvm_util.cpp 2022-09-30 17:43:53 -0600 ++++ external_osl/src/liboslexec/llvm_util.cpp 2022-10-15 15:53:11 -0600 +@@ -116,8 +116,6 @@ + return { A.data(), size_t(A.size()) }; + } + +- +- + namespace pvt { + + typedef llvm::SectionMemoryManager LLVMMemoryManager; +@@ -182,6 +180,13 @@ + ++jit_mem_hold_users; + } + ++void ++LLVM_Util::Cleanup() ++{ ++ if (jitmm_hold) ++ jitmm_hold->clear(); ++} ++ + + LLVM_Util::ScopedJitMemoryUser::~ScopedJitMemoryUser() + { +diff --git a/src/include/OSL/mask.h b/src/include/OSL/mask.h +index 24197af..b9275f6 100644 +--- a/src/include/OSL/mask.h ++++ b/src/include/OSL/mask.h +@@ -4,7 +4,6 @@ + + #pragma once + +-#include <immintrin.h> + #include <type_traits> + + #include <OSL/oslconfig.h> +@@ -23,6 +22,8 @@ using std::countr_zero; + + #elif OSL_INTEL_CLASSIC_COMPILER_VERSION + ++#include <immintrin.h> ++ + OSL_FORCEINLINE int popcount(uint32_t x) noexcept { return _mm_popcnt_u32(x);} + OSL_FORCEINLINE int popcount(uint64_t x) noexcept { return _mm_popcnt_u64(x); } + OSL_FORCEINLINE int countr_zero(uint32_t x) noexcept { return _bit_scan_forward(x); } diff --git a/build_files/build_environment/patches/python_windows.diff b/build_files/build_environment/patches/python_windows.diff deleted file mode 100644 index f9c89a90fde..00000000000 --- a/build_files/build_environment/patches/python_windows.diff +++ /dev/null @@ -1,24 +0,0 @@ -diff -Naur orig/PCbuild/get_externals.bat Python-3.10.2/PCbuild/get_externals.bat ---- orig/PCbuild/get_externals.bat 2022-01-13 11:52:14 -0700 -+++ Python-3.10.2/PCbuild/get_externals.bat 2022-08-17 11:24:42 -0600 -@@ -51,7 +51,7 @@ - echo.Fetching external libraries... - - set libraries= --set libraries=%libraries% bzip2-1.0.6 -+set libraries=%libraries% bzip2-1.0.8 - if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.3.0 - if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1m - set libraries=%libraries% sqlite-3.35.5.0 - diff -Naur orig/PCbuild/python.props external_python/PCbuild/python.props ---- orig/PCbuild/python.props 2022-01-13 11:52:14 -0700 -+++ external_python/PCbuild/python.props 2022-08-17 11:38:38 -0600 -@@ -58,7 +58,7 @@ - <ExternalsDir Condition="$(ExternalsDir) == ''">$([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`))</ExternalsDir> - <ExternalsDir Condition="!HasTrailingSlash($(ExternalsDir))">$(ExternalsDir)\</ExternalsDir> - <sqlite3Dir>$(ExternalsDir)sqlite-3.35.5.0\</sqlite3Dir> -- <bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir> -+ <bz2Dir>$(ExternalsDir)bzip2-1.0.8\</bz2Dir> - <lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir> - <libffiDir>$(ExternalsDir)libffi-3.3.0\</libffiDir> - <libffiOutDir>$(ExternalsDir)libffi-3.3.0\$(ArchName)\</libffiOutDir> diff --git a/build_files/build_environment/patches/sndfile.diff b/build_files/build_environment/patches/sndfile.diff deleted file mode 100644 index ab43baa78df..00000000000 --- a/build_files/build_environment/patches/sndfile.diff +++ /dev/null @@ -1,42 +0,0 @@ ---- src/Makefile.in 2017-09-26 01:28:47.000000000 +0300 -+++ src/Makefile.in 2017-09-26 01:19:06.000000000 +0300 -@@ -513,7 +513,7 @@ - libcommon_la_SOURCES = common.c file_io.c command.c pcm.c ulaw.c alaw.c \ - float32.c double64.c ima_adpcm.c ms_adpcm.c gsm610.c dwvw.c vox_adpcm.c \ - interleave.c strings.c dither.c cart.c broadcast.c audio_detect.c \ -- ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \ -+ ima_oki_adpcm.c ima_oki_adpcm.h alac.c chunk.c ogg.c chanmap.c \ - windows.c id3.c $(WIN_VERSION_FILE) - - -@@ -719,10 +719,10 @@ - $(AM_V_CCLD)$(LINK) $(GSM610_libgsm_la_OBJECTS) $(GSM610_libgsm_la_LIBADD) $(LIBS) - - libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(EXTRA_libcommon_la_DEPENDENCIES) -- $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) -+ $(AM_V_CCLD)$(LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS) - - libsndfile.la: $(libsndfile_la_OBJECTS) $(libsndfile_la_DEPENDENCIES) $(EXTRA_libsndfile_la_DEPENDENCIES) -- $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS) -+ $(AM_V_CCLD)$(libsndfile_la_LINK) -rpath $(libdir) $(libsndfile_la_OBJECTS) $(libsndfile_la_LIBADD) $(LIBS) $(EXTERNAL_XIPH_LIBS) - - clean-checkPROGRAMS: - @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ -@@ -924,7 +924,7 @@ - @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-dwd.lo `test -f 'dwd.c' || echo '$(srcdir)/'`dwd.c - - libsndfile_la-flac.lo: flac.c --@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c -+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-flac.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-flac.Tpo -c -o libsndfile_la-flac.lo `test -f 'flac.c' || echo '$(srcdir)/'`flac.c - @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-flac.Tpo $(DEPDIR)/libsndfile_la-flac.Plo - @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='flac.c' object='libsndfile_la-flac.lo' libtool=yes @AMDEPBACKSLASH@ - @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@@ -1092,7 +1092,7 @@ - @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -c -o libsndfile_la-rf64.lo `test -f 'rf64.c' || echo '$(srcdir)/'`rf64.c - - libsndfile_la-ogg_vorbis.lo: ogg_vorbis.c --@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c -+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsndfile_la_CPPFLAGS) $(CPPFLAGS) $(libsndfile_la_CFLAGS) $(CFLAGS) $(EXTERNAL_XIPH_CFLAGS) -MT libsndfile_la-ogg_vorbis.lo -MD -MP -MF $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo -c -o libsndfile_la-ogg_vorbis.lo `test -f 'ogg_vorbis.c' || echo '$(srcdir)/'`ogg_vorbis.c - @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsndfile_la-ogg_vorbis.Tpo $(DEPDIR)/libsndfile_la-ogg_vorbis.Plo - @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ogg_vorbis.c' object='libsndfile_la-ogg_vorbis.lo' libtool=yes @AMDEPBACKSLASH@ - @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ diff --git a/build_files/build_environment/patches/sqlite.diff b/build_files/build_environment/patches/sqlite.diff deleted file mode 100644 index 80f1384f9cf..00000000000 --- a/build_files/build_environment/patches/sqlite.diff +++ /dev/null @@ -1,14 +0,0 @@ -Only in external_sqlite_orig: config.log -diff -ru external_sqlite_orig/config.sub external_sqlite/config.sub ---- external_sqlite_orig/config.sub 2020-07-10 14:06:42.000000000 +0200 -+++ external_sqlite/config.sub 2020-07-10 14:10:24.000000000 +0200 -@@ -314,6 +314,7 @@ - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ -+ | aarch64-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ -Only in external_sqlite: mksourceid -Only in external_sqlite: sqlite3session.h diff --git a/build_files/build_environment/patches/ssl.diff b/build_files/build_environment/patches/ssl.diff new file mode 100644 index 00000000000..7bb4413952c --- /dev/null +++ b/build_files/build_environment/patches/ssl.diff @@ -0,0 +1,10 @@ +--- ./test/v3ext.c 2022-07-05 11:08:33.000000000 +0200 ++++ ./test/v3ext.c 2022-10-18 13:58:05.000000000 +0200 +@@ -8,6 +8,7 @@ + */ + + #include <stdio.h> ++#include <string.h> + #include <openssl/x509.h> + #include <openssl/x509v3.h> + #include <openssl/pem.h> diff --git a/build_files/cmake/Modules/FindOSL.cmake b/build_files/cmake/Modules/FindOSL.cmake index ab5de53d3c9..a8d8344ae66 100644 --- a/build_files/cmake/Modules/FindOSL.cmake +++ b/build_files/cmake/Modules/FindOSL.cmake @@ -20,6 +20,7 @@ IF(NOT OSL_ROOT_DIR AND NOT $ENV{OSL_ROOT_DIR} STREQUAL "") ENDIF() SET(_osl_FIND_COMPONENTS + oslnoise oslcomp oslexec oslquery @@ -39,7 +40,6 @@ FIND_PATH(OSL_INCLUDE_DIR include ) -SET(_osl_LIBRARIES) FOREACH(COMPONENT ${_osl_FIND_COMPONENTS}) STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT) @@ -51,9 +51,20 @@ FOREACH(COMPONENT ${_osl_FIND_COMPONENTS}) PATH_SUFFIXES lib64 lib ) - LIST(APPEND _osl_LIBRARIES "${OSL_${UPPERCOMPONENT}_LIBRARY}") ENDFOREACH() +# Note linking order matters, and oslnoise existence depends on version. +SET(_osl_LIBRARIES ${OSL_OSLCOMP_LIBRARY}) +IF(APPLE) + list(APPEND _osl_LIBRARIES -force_load ${OSL_OSLEXEC_LIBRARY}) +ELSE() + list(APPEND _osl_LIBRARIES ${OSL_OSLEXEC_LIBRARY}) +ENDIF() +list(APPEND _osl_LIBRARIES ${OSL_OSLQUERY_LIBRARY}) +IF(OSL_OSLNOISE_LIBRARY) + list(APPEND _osl_LIBRARIES ${OSL_OSLNOISE_LIBRARY}) +ENDIF() + FIND_PROGRAM(OSL_COMPILER oslc HINTS ${_osl_SEARCH_DIRS} PATH_SUFFIXES bin) diff --git a/build_files/cmake/Modules/FindOpenSubdiv.cmake b/build_files/cmake/Modules/FindOpenSubdiv.cmake index 37a2cddf3de..66d3b435c46 100644 --- a/build_files/cmake/Modules/FindOpenSubdiv.cmake +++ b/build_files/cmake/Modules/FindOpenSubdiv.cmake @@ -71,21 +71,6 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenSubdiv DEFAULT_MSG IF(OPENSUBDIV_FOUND) SET(OPENSUBDIV_LIBRARIES ${_opensubdiv_LIBRARIES}) SET(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_INCLUDE_DIR}) - - # Find available compute controllers. - - FIND_PACKAGE(OpenMP) - IF(OPENMP_FOUND) - SET(OPENSUBDIV_HAS_OPENMP TRUE) - ELSE() - SET(OPENSUBDIV_HAS_OPENMP FALSE) - ENDIF() - - OPENSUBDIV_CHECK_CONTROLLER("tbbEvaluator.h" OPENSUBDIV_HAS_TBB) - OPENSUBDIV_CHECK_CONTROLLER("clEvaluator.h" OPENSUBDIV_HAS_OPENCL) - OPENSUBDIV_CHECK_CONTROLLER("cudaEvaluator.h" OPENSUBDIV_HAS_CUDA) - OPENSUBDIV_CHECK_CONTROLLER("glXFBEvaluator.h" OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK) - OPENSUBDIV_CHECK_CONTROLLER("glComputeEvaluator.h" OPENSUBDIV_HAS_GLSL_COMPUTE) ENDIF() MARK_AS_ADVANCED( diff --git a/build_files/cmake/Modules/FindSYCL.cmake b/build_files/cmake/Modules/FindSYCL.cmake index 139ebad46b1..1ccbee179fb 100644 --- a/build_files/cmake/Modules/FindSYCL.cmake +++ b/build_files/cmake/Modules/FindSYCL.cmake @@ -30,6 +30,7 @@ SET(_sycl_search_dirs # dpcpp binary. FIND_PROGRAM(SYCL_COMPILER NAMES + icpx dpcpp clang++ HINTS @@ -45,6 +46,7 @@ FIND_PROGRAM(SYCL_COMPILER if(NOT SYCL_COMPILER) FIND_PROGRAM(SYCL_COMPILER NAMES + icpx dpcpp HINTS ${_sycl_search_dirs} @@ -55,6 +57,8 @@ endif() FIND_LIBRARY(SYCL_LIBRARY NAMES + sycl7 + sycl6 sycl HINTS ${_sycl_search_dirs} @@ -63,34 +67,51 @@ FIND_LIBRARY(SYCL_LIBRARY ) if(WIN32) - string(REPLACE ".lib" "d.lib" SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY}) - set(SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY_DEBUG} CACHE FILEPATH "Path to SYCL debug library") -else() - set(SYCL_LIBRARY_DEBUG ${SYCL_LIBRARY} CACHE FILEPATH "Path to SYCL debug library") + FIND_LIBRARY(SYCL_LIBRARY_DEBUG + NAMES + sycl7d + sycl6d + sycld + HINTS + ${_sycl_search_dirs} + PATH_SUFFIXES + lib64 lib + ) endif() FIND_PATH(SYCL_INCLUDE_DIR NAMES - CL/sycl.hpp + sycl/sycl.hpp HINTS ${_sycl_search_dirs} PATH_SUFFIXES include - include/sycl ) +IF(EXISTS "${SYCL_INCLUDE_DIR}/sycl/version.hpp") + FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_major_version REGEX "^#define __LIBSYCL_MAJOR_VERSION[ \t].*$") + STRING(REGEX MATCHALL "[0-9]+" _libsycl_major_version ${_libsycl_major_version}) + FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_minor_version REGEX "^#define __LIBSYCL_MINOR_VERSION[ \t].*$") + STRING(REGEX MATCHALL "[0-9]+" _libsycl_minor_version ${_libsycl_minor_version}) + FILE(STRINGS "${SYCL_INCLUDE_DIR}/sycl/version.hpp" _libsycl_patch_version REGEX "^#define __LIBSYCL_PATCH_VERSION[ \t].*$") + STRING(REGEX MATCHALL "[0-9]+" _libsycl_patch_version ${_libsycl_patch_version}) + + SET(SYCL_VERSION "${_libsycl_major_version}.${_libsycl_minor_version}.${_libsycl_patch_version}") +ENDIF() + INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL DEFAULT_MSG SYCL_LIBRARY SYCL_INCLUDE_DIR) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL + REQUIRED_VARS SYCL_LIBRARY SYCL_INCLUDE_DIR + VERSION_VAR SYCL_VERSION +) IF(SYCL_FOUND) - get_filename_component(_SYCL_INCLUDE_PARENT_DIR ${SYCL_INCLUDE_DIR} DIRECTORY) - SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${_SYCL_INCLUDE_PARENT_DIR}) + SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${SYCL_INCLUDE_DIR}/sycl) ELSE() SET(SYCL_SYCL_FOUND FALSE) ENDIF() MARK_AS_ADVANCED( _SYCL_INCLUDE_PARENT_DIR - SYCL_LIBRARY_DEBUG ) diff --git a/build_files/cmake/config/blender_developer.cmake b/build_files/cmake/config/blender_developer.cmake index 1f1a100d958..ebc5727a79c 100644 --- a/build_files/cmake/config/blender_developer.cmake +++ b/build_files/cmake/config/blender_developer.cmake @@ -8,7 +8,11 @@ set(WITH_ASSERT_ABORT ON CACHE BOOL "" FORCE) set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE) -set(WITH_COMPILER_ASAN ON CACHE BOOL "" FORCE) +# Sadly ASAN is more often broken than working with MSVC do not enable it in the +# developer profile for now. +if(NOT WIN32) + set(WITH_COMPILER_ASAN ON CACHE BOOL "" FORCE) +endif() set(WITH_CYCLES_NATIVE_ONLY ON CACHE BOOL "" FORCE) set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE) set(WITH_GTESTS ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake index 958eb17522b..95304bd64c7 100644 --- a/build_files/cmake/config/blender_full.cmake +++ b/build_files/cmake/config/blender_full.cmake @@ -66,13 +66,11 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE) if(APPLE) set(WITH_COREAUDIO ON CACHE BOOL "" FORCE) endif() -if(NOT WIN32) - set(WITH_JACK ON CACHE BOOL "" FORCE) -endif() if(WIN32) set(WITH_WASAPI ON CACHE BOOL "" FORCE) endif() if(UNIX AND NOT APPLE) + set(WITH_JACK ON CACHE BOOL "" FORCE) set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE) set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE) set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index d5f5230862b..74bbcb223c3 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -67,13 +67,11 @@ if(APPLE) set(WITH_COREAUDIO ON CACHE BOOL "" FORCE) set(WITH_CYCLES_DEVICE_METAL ON CACHE BOOL "" FORCE) endif() -if(NOT WIN32) - set(WITH_JACK ON CACHE BOOL "" FORCE) -endif() if(WIN32) set(WITH_WASAPI ON CACHE BOOL "" FORCE) endif() if(UNIX AND NOT APPLE) + set(WITH_JACK ON CACHE BOOL "" FORCE) set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE) set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE) set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 3acea19079b..8af45690862 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -1205,11 +1205,27 @@ macro(set_and_warn_dependency _dependency _setting _val) # when $_dependency is disabled, forces $_setting = $_val if(NOT ${${_dependency}} AND ${${_setting}}) - message(STATUS "'${_dependency}' is disabled: forcing 'set(${_setting} ${_val})'") + if(WITH_STRICT_BUILD_OPTIONS) + message(SEND_ERROR "${_dependency} disabled but required by ${_setting}") + else() + message(STATUS "${_dependency} is disabled, setting ${_setting}=${_val}") + endif() set(${_setting} ${_val}) endif() endmacro() +macro(set_and_warn_library_found + _library_name _library_found _setting) + if(NOT ${${_library_found}} AND ${${_setting}}) + if(WITH_STRICT_BUILD_OPTIONS) + message(SEND_ERROR "${_library_name} required but not found") + else() + message(STATUS "${_library_name} not found, disabling ${_setting}") + endif() + set(${_setting} OFF) + endif() +endmacro() + macro(without_system_libs_begin) set(CMAKE_IGNORE_PATH "${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES};${CMAKE_SYSTEM_INCLUDE_PATH};${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES};${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}") endmacro() diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 04f5a312030..c5fe3c908de 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -43,22 +43,18 @@ find_package(BZip2 REQUIRED) list(APPEND ZLIB_LIBRARIES ${BZIP2_LIBRARIES}) if(WITH_OPENAL) - find_package(OpenAL) - if(NOT OPENAL_FOUND) - message(WARNING "OpenAL not found, disabling WITH_OPENAL") - set(WITH_OPENAL OFF) - endif() + find_package(OpenAL REQUIRED) endif() if(WITH_JACK) find_library(JACK_FRAMEWORK NAMES jackmp ) - if(NOT JACK_FRAMEWORK) - message(STATUS "JACK not found, disabling WITH_JACK") - set(WITH_JACK OFF) - else() + + if(JACK_FRAMEWORK) set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers) + else() + set_and_warn_library_found("JACK" JACK_FRAMEWORK WITH_JACK) endif() endif() @@ -101,11 +97,7 @@ if(WITH_ALEMBIC) endif() if(WITH_USD) - find_package(USD) - if(NOT USD_FOUND) - message(STATUS "USD not found, disabling WITH_USD") - set(WITH_USD OFF) - endif() + find_package(USD REQUIRED) endif() if(WITH_OPENSUBDIV) @@ -227,20 +219,12 @@ find_package(JPEG REQUIRED) if(WITH_IMAGE_TIFF) set(TIFF_ROOT ${LIBDIR}/tiff) - find_package(TIFF) - if(NOT TIFF_FOUND) - message(WARNING "TIFF not found, disabling WITH_IMAGE_TIFF") - set(WITH_IMAGE_TIFF OFF) - endif() + find_package(TIFF REQUIRED) endif() if(WITH_IMAGE_WEBP) set(WEBP_ROOT_DIR ${LIBDIR}/webp) - find_package(WebP) - if(NOT WEBP_FOUND) - message(WARNING "WebP not found, disabling WITH_IMAGE_WEBP") - set(WITH_IMAGE_WEBP OFF) - endif() + find_package(WebP REQUIRED) endif() if(WITH_BOOST) @@ -270,11 +254,7 @@ if(WITH_INTERNATIONAL OR WITH_CODEC_FFMPEG) endif() if(WITH_PUGIXML) - find_package(PugiXML) - if(NOT PUGIXML_FOUND) - message(WARNING "PugiXML not found, disabling WITH_PUGIXML") - set(WITH_PUGIXML OFF) - endif() + find_package(PugiXML REQUIRED) endif() if(WITH_OPENIMAGEIO) @@ -292,12 +272,7 @@ if(WITH_OPENIMAGEIO) endif() if(WITH_OPENCOLORIO) - find_package(OpenColorIO 2.0.0) - - if(NOT OPENCOLORIO_FOUND) - set(WITH_OPENCOLORIO OFF) - message(STATUS "OpenColorIO not found, disabling WITH_OPENCOLORIO") - endif() + find_package(OpenColorIO 2.0.0 REQUIRED) endif() if(WITH_OPENVDB) @@ -331,23 +306,7 @@ if(WITH_LLVM) endif() if(WITH_CYCLES AND WITH_CYCLES_OSL) - set(CYCLES_OSL ${LIBDIR}/osl) - - find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib) - find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib) - find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib) - # WARNING! depends on correct order of OSL libs linking - list(APPEND OSL_LIBRARIES ${OSL_LIB_COMP} -force_load ${OSL_LIB_EXEC} ${OSL_LIB_QUERY}) - find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include) - find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin) - find_path(OSL_SHADER_DIR NAMES stdosl.h PATHS ${CYCLES_OSL}/share/OSL/shaders) - - if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER AND OSL_SHADER_DIR) - set(OSL_FOUND TRUE) - else() - message(WARNING "OSL not found, disabling WITH_CYCLES_OSL") - set(WITH_CYCLES_OSL OFF) - endif() + find_package(OSL REQUIRED) endif() if(WITH_CYCLES AND WITH_CYCLES_EMBREE) @@ -365,28 +324,15 @@ if(WITH_CYCLES AND WITH_CYCLES_EMBREE) endif() if(WITH_OPENIMAGEDENOISE) - find_package(OpenImageDenoise) - - if(NOT OPENIMAGEDENOISE_FOUND) - set(WITH_OPENIMAGEDENOISE OFF) - message(STATUS "OpenImageDenoise not found, disabling WITH_OPENIMAGEDENOISE") - endif() + find_package(OpenImageDenoise REQUIRED) endif() if(WITH_TBB) - find_package(TBB) - if(NOT TBB_FOUND) - message(WARNING "TBB not found, disabling WITH_TBB") - set(WITH_TBB OFF) - endif() + find_package(TBB REQUIRED) endif() if(WITH_POTRACE) - find_package(Potrace) - if(NOT POTRACE_FOUND) - message(WARNING "potrace not found, disabling WITH_POTRACE") - set(WITH_POTRACE OFF) - endif() + find_package(Potrace REQUIRED) endif() # CMake FindOpenMP doesn't know about AppleClang before 3.12, so provide custom flags. @@ -406,27 +352,15 @@ if(WITH_OPENMP) endif() if(WITH_XR_OPENXR) - find_package(XR_OpenXR_SDK) - if(NOT XR_OPENXR_SDK_FOUND) - message(WARNING "OpenXR-SDK was not found, disabling WITH_XR_OPENXR") - set(WITH_XR_OPENXR OFF) - endif() + find_package(XR_OpenXR_SDK REQUIRED) endif() if(WITH_GMP) - find_package(GMP) - if(NOT GMP_FOUND) - message(WARNING "GMP not found, disabling WITH_GMP") - set(WITH_GMP OFF) - endif() + find_package(GMP REQUIRED) endif() if(WITH_HARU) - find_package(Haru) - if(NOT HARU_FOUND) - message(WARNING "Haru not found, disabling WITH_HARU") - set(WITH_HARU OFF) - endif() + find_package(Haru REQUIRED) endif() if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 695ea3d773e..343ed6d8ef4 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -174,32 +174,24 @@ endif() if(WITH_IMAGE_OPENEXR) find_package_wrapper(OpenEXR) # our own module - if(NOT OPENEXR_FOUND) - set(WITH_IMAGE_OPENEXR OFF) - endif() + set_and_warn_library_found("OpenEXR" OPENEXR_FOUND WITH_IMAGE_OPENEXR) endif() if(WITH_IMAGE_OPENJPEG) find_package_wrapper(OpenJPEG) - if(NOT OPENJPEG_FOUND) - set(WITH_IMAGE_OPENJPEG OFF) - endif() + set_and_warn_library_found("OpenJPEG" OPENJPEG_FOUND WITH_IMAGE_OPENJPEG) endif() if(WITH_IMAGE_TIFF) # XXX Linking errors with debian static tiff :/ # find_package_wrapper(TIFF) find_package(TIFF) - if(NOT TIFF_FOUND) - set(WITH_IMAGE_TIFF OFF) - endif() + set_and_warn_library_found("TIFF" TIFF_FOUND WITH_IMAGE_TIFF) endif() if(WITH_OPENAL) find_package_wrapper(OpenAL) - if(NOT OPENAL_FOUND) - set(WITH_OPENAL OFF) - endif() + set_and_warn_library_found("OpenAL" OPENAL_FOUND WITH_OPENAL) endif() if(WITH_SDL) @@ -221,18 +213,14 @@ if(WITH_SDL) SDL_LIBRARY ) # unset(SDLMAIN_LIBRARY CACHE) - if(NOT SDL_FOUND) - set(WITH_SDL OFF) - endif() + set_and_warn_library_found("SDL" SDL_FOUND WITH_SDL) endif() endif() # Codecs if(WITH_CODEC_SNDFILE) find_package_wrapper(SndFile) - if(NOT SNDFILE_FOUND) - set(WITH_CODEC_SNDFILE OFF) - endif() + set_and_warn_library_found("libsndfile" SNDFILE_FOUND WITH_CODEC_SNDFILE) endif() if(WITH_CODEC_FFMPEG) @@ -260,17 +248,12 @@ if(WITH_CODEC_FFMPEG) endif() find_package(FFmpeg) - if(NOT FFMPEG_FOUND) - set(WITH_CODEC_FFMPEG OFF) - message(STATUS "FFmpeg not found, disabling it") - endif() + set_and_warn_library_found("FFmpeg" FFMPEG_FOUND WITH_CODEC_FFMPEG) endif() if(WITH_FFTW3) find_package_wrapper(Fftw3) - if(NOT FFTW3_FOUND) - set(WITH_FFTW3 OFF) - endif() + set_and_warn_library_found("fftw3" FFTW3_FOUND WITH_FFTW3) endif() if(WITH_OPENCOLLADA) @@ -285,25 +268,23 @@ if(WITH_OPENCOLLADA) endif() find_package_wrapper(XML2) else() - set(WITH_OPENCOLLADA OFF) + set_and_warn_library_found("OpenCollada" OPENCOLLADA_FOUND WITH_OPENCOLLADA) endif() endif() if(WITH_MEM_JEMALLOC) find_package_wrapper(JeMalloc) - if(NOT JEMALLOC_FOUND) - set(WITH_MEM_JEMALLOC OFF) - endif() + set_and_warn_library_found("JeMalloc" JEMALLOC_FOUND WITH_MEM_JEMALLOC) endif() if(WITH_INPUT_NDOF) find_package_wrapper(Spacenav) + set_and_warn_library_found("SpaceNav" SPACENAV_FOUND WITH_INPUT_NDOF) + if(SPACENAV_FOUND) # use generic names within blenders buildsystem. set(NDOF_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIRS}) set(NDOF_LIBRARIES ${SPACENAV_LIBRARIES}) - else() - set(WITH_INPUT_NDOF OFF) endif() endif() @@ -313,6 +294,8 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) set(OSL_ROOT ${CYCLES_OSL}) endif() find_package_wrapper(OSL) + set_and_warn_library_found("OSL" OSL_FOUND WITH_CYCLES_OSL) + if(OSL_FOUND) if(${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6") # Note: --whole-archive is needed to force loading of all symbols in liboslexec, @@ -323,9 +306,6 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) -Wl,--no-whole-archive ${OSL_OSLQUERY_LIBRARY} ) endif() - else() - message(STATUS "OSL not found, disabling it from Cycles") - set(WITH_CYCLES_OSL OFF) endif() endif() @@ -341,35 +321,27 @@ if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI) endif() file(GLOB _sycl_runtime_libraries ${SYCL_ROOT_DIR}/lib/libsycl.so - ${SYCL_ROOT_DIR}/lib/libsycl.so.[0-9] - ${SYCL_ROOT_DIR}/lib/libsycl.so.[0-9].[0-9].[0-9]-[0-9] + ${SYCL_ROOT_DIR}/lib/libsycl.so.* ${SYCL_ROOT_DIR}/lib/libpi_level_zero.so ) + list(FILTER _sycl_runtime_libraries EXCLUDE REGEX ".*\.py") list(APPEND PLATFORM_BUNDLED_LIBRARIES ${_sycl_runtime_libraries}) unset(_sycl_runtime_libraries) endif() if(WITH_OPENVDB) find_package_wrapper(OpenVDB) - find_package_wrapper(Blosc) - - if(NOT OPENVDB_FOUND) - set(WITH_OPENVDB OFF) - set(WITH_OPENVDB_BLOSC OFF) - message(STATUS "OpenVDB not found, disabling it") - elseif(NOT BLOSC_FOUND) - set(WITH_OPENVDB_BLOSC OFF) - message(STATUS "Blosc not found, disabling it for OpenVBD") + set_and_warn_library_found("OpenVDB" OPENVDB_FOUND WITH_OPENVDB) + + if(OPENVDB_FOUND) + find_package_wrapper(Blosc) + set_and_warn_library_found("Blosc" BLOSC_FOUND WITH_OPENVDB_BLOSC) endif() endif() if(WITH_NANOVDB) find_package_wrapper(NanoVDB) - - if(NOT NANOVDB_FOUND) - set(WITH_NANOVDB OFF) - message(STATUS "NanoVDB not found, disabling it") - endif() + set_and_warn_library_found("NanoVDB" NANOVDB_FOUND WITH_NANOVDB) endif() if(WITH_CPU_SIMD AND SUPPORT_NEON_BUILD) @@ -378,18 +350,12 @@ endif() if(WITH_ALEMBIC) find_package_wrapper(Alembic) - - if(NOT ALEMBIC_FOUND) - set(WITH_ALEMBIC OFF) - endif() + set_and_warn_library_found("Alembic" ALEMBIC_FOUND WITH_ALEMBIC) endif() if(WITH_USD) find_package_wrapper(USD) - - if(NOT USD_FOUND) - set(WITH_USD OFF) - endif() + set_and_warn_library_found("USD" USD_FOUND WITH_USD) endif() if(WITH_BOOST) @@ -442,20 +408,13 @@ endif() if(WITH_PUGIXML) find_package_wrapper(PugiXML) - - if(NOT PUGIXML_FOUND) - set(WITH_PUGIXML OFF) - message(STATUS "PugiXML not found, disabling WITH_PUGIXML") - endif() + set_and_warn_library_found("PugiXML" PUGIXML_FOUND WITH_PUGIXML) endif() if(WITH_IMAGE_WEBP) set(WEBP_ROOT_DIR ${LIBDIR}/webp) find_package_wrapper(WebP) - if(NOT WEBP_FOUND) - set(WITH_IMAGE_WEBP OFF) - message(WARNING "WebP not found, disabling WITH_IMAGE_WEBP") - endif() + set_and_warn_library_found("WebP" WEBP_FOUND WITH_IMAGE_WEBP) endif() if(WITH_OPENIMAGEIO) @@ -480,10 +439,7 @@ if(WITH_OPENIMAGEIO) list(APPEND OPENIMAGEIO_LIBRARIES "${WEBP_LIBRARIES}") endif() - if(NOT OPENIMAGEIO_FOUND) - set(WITH_OPENIMAGEIO OFF) - message(STATUS "OpenImageIO not found, disabling WITH_CYCLES") - endif() + set_and_warn_library_found("OPENIMAGEIO" OPENIMAGEIO_FOUND WITH_OPENIMAGEIO) endif() if(WITH_OPENCOLORIO) @@ -493,10 +449,7 @@ if(WITH_OPENCOLORIO) set(OPENCOLORIO_LIBPATH) # TODO, remove and reference the absolute path everywhere set(OPENCOLORIO_DEFINITIONS) - if(NOT OPENCOLORIO_FOUND) - set(WITH_OPENCOLORIO OFF) - message(STATUS "OpenColorIO not found") - endif() + set_and_warn_library_found("OpenColorIO" OPENCOLORIO_FOUND WITH_OPENCOLORIO) endif() if(WITH_CYCLES AND WITH_CYCLES_EMBREE) @@ -505,11 +458,7 @@ endif() if(WITH_OPENIMAGEDENOISE) find_package_wrapper(OpenImageDenoise) - - if(NOT OPENIMAGEDENOISE_FOUND) - set(WITH_OPENIMAGEDENOISE OFF) - message(STATUS "OpenImageDenoise not found") - endif() + set_and_warn_library_found("OpenImageDenoise" OPENIMAGEDENOISE_FOUND WITH_OPENIMAGEDENOISE) endif() if(WITH_LLVM) @@ -518,24 +467,19 @@ if(WITH_LLVM) endif() find_package_wrapper(LLVM) - if(WITH_CLANG) - find_package_wrapper(Clang) - endif() - # Symbol conflicts with same UTF library used by OpenCollada - if(EXISTS ${LIBDIR}) - if(WITH_OPENCOLLADA AND (${LLVM_VERSION} VERSION_LESS "4.0.0")) - list(REMOVE_ITEM OPENCOLLADA_LIBRARIES ${OPENCOLLADA_UTF_LIBRARY}) + set_and_warn_library_found("LLVM" LLVM_FOUND WITH_LLVM) + + if(LLVM_FOUND) + if(WITH_CLANG) + find_package_wrapper(Clang) + set_and_warn_library_found("Clang" CLANG_FOUND WITH_CLANG) endif() - endif() - if(NOT LLVM_FOUND) - set(WITH_LLVM OFF) - set(WITH_CLANG OFF) - message(STATUS "LLVM not found") - else() - if(NOT CLANG_FOUND) - set(WITH_CLANG OFF) - message(STATUS "Clang not found") + # Symbol conflicts with same UTF library used by OpenCollada + if(EXISTS ${LIBDIR}) + if(WITH_OPENCOLLADA AND (${LLVM_VERSION} VERSION_LESS "4.0.0")) + list(REMOVE_ITEM OPENCOLLADA_LIBRARIES ${OPENCOLLADA_UTF_LIBRARY}) + endif() endif() endif() endif() @@ -546,50 +490,32 @@ if(WITH_OPENSUBDIV) set(OPENSUBDIV_LIBRARIES ${OPENSUBDIV_LIBRARIES}) set(OPENSUBDIV_LIBPATH) # TODO, remove and reference the absolute path everywhere - if(NOT OPENSUBDIV_FOUND) - set(WITH_OPENSUBDIV OFF) - message(STATUS "OpenSubdiv not found") - endif() + set_and_warn_library_found("OpenSubdiv" OPENSUBDIV_FOUND WITH_OPENSUBDIV) endif() if(WITH_TBB) find_package_wrapper(TBB) - if(NOT TBB_FOUND) - message(WARNING "TBB not found, disabling WITH_TBB") - set(WITH_TBB OFF) - endif() + set_and_warn_library_found("TBB" TBB_FOUND WITH_TBB) endif() if(WITH_XR_OPENXR) find_package(XR_OpenXR_SDK) - if(NOT XR_OPENXR_SDK_FOUND) - message(WARNING "OpenXR-SDK not found, disabling WITH_XR_OPENXR") - set(WITH_XR_OPENXR OFF) - endif() + set_and_warn_library_found("OpenXR-SDK" XR_OPENXR_SDK_FOUND WITH_XR_OPENXR) endif() if(WITH_GMP) find_package_wrapper(GMP) - if(NOT GMP_FOUND) - message(WARNING "GMP not found, disabling WITH_GMP") - set(WITH_GMP OFF) - endif() + set_and_warn_library_found("GMP" GMP_FOUND WITH_GMP) endif() if(WITH_POTRACE) find_package_wrapper(Potrace) - if(NOT POTRACE_FOUND) - message(WARNING "potrace not found, disabling WITH_POTRACE") - set(WITH_POTRACE OFF) - endif() + set_and_warn_library_found("Potrace" POTRACE_FOUND WITH_POTRACE) endif() if(WITH_HARU) find_package_wrapper(Haru) - if(NOT HARU_FOUND) - message(WARNING "Haru not found, disabling WITH_HARU") - set(WITH_HARU OFF) - endif() + set_and_warn_library_found("Haru" HARU_FOUND WITH_HARU) endif() if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING) @@ -676,25 +602,20 @@ endif() # Jack is intended to use the system library. if(WITH_JACK) find_package_wrapper(Jack) - if(NOT JACK_FOUND) - set(WITH_JACK OFF) - endif() + set_and_warn_library_found("JACK" JACK_FOUND WITH_JACK) endif() # Pulse is intended to use the system library. if(WITH_PULSEAUDIO) find_package_wrapper(Pulse) - if(NOT PULSE_FOUND) - set(WITH_PULSEAUDIO OFF) - endif() + set_and_warn_library_found("PulseAudio" PULSE_FOUND WITH_PULSEAUDIO) endif() # Audio IO if(WITH_SYSTEM_AUDASPACE) find_package_wrapper(Audaspace) - if(NOT AUDASPACE_FOUND OR NOT AUDASPACE_C_FOUND) - message(FATAL_ERROR "Audaspace external library not found!") - endif() + set(AUDASPACE_FOUND ${AUDASPACE_FOUND} AND ${AUDASPACE_C_FOUND}) + set_and_warn_library_found("External Audaspace" AUDASPACE_FOUND WITH_SYSTEM_AUDASPACE) endif() if(WITH_GHOST_WAYLAND) @@ -739,31 +660,14 @@ if(WITH_GHOST_WAYLAND) set(wayland-scanner_FOUND ON) set(wayland-cursor_FOUND ON) endif() + mark_as_advanced(WAYLAND_PROTOCOLS_DIR) - if (NOT wayland-client_FOUND) - message(STATUS "wayland-client not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-egl_FOUND) - message(STATUS "wayland-egl not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-scanner_FOUND) - message(STATUS "wayland-scanner not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-cursor_FOUND) - message(STATUS "wayland-cursor not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT wayland-protocols_FOUND) - message(STATUS "wayland-protocols not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() - if (NOT xkbcommon_FOUND) - message(STATUS "xkbcommon not found, disabling WITH_GHOST_WAYLAND") - set(WITH_GHOST_WAYLAND OFF) - endif() + set_and_warn_library_found("wayland-client" wayland-client_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-egl" wayland-egl_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-scanner" wayland-scanner_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-cursor" wayland-cursor_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("wayland-protocols" wayland-protocols_FOUND WITH_GHOST_WAYLAND) + set_and_warn_library_found("xkbcommon" xkbcommon_FOUND WITH_GHOST_WAYLAND) if(WITH_GHOST_WAYLAND) if(WITH_GHOST_WAYLAND_DBUS) @@ -791,6 +695,7 @@ if(WITH_GHOST_WAYLAND) else() pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner) endif() + mark_as_advanced(WAYLAND_SCANNER) # When using dynamic loading, headers generated # from older versions of `wayland-scanner` aren't compatible. diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index cfb8bf34b81..3818076634a 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -326,18 +326,10 @@ if(WITH_FFTW3) endif() if(WITH_IMAGE_WEBP) - windows_find_package(WebP) - if(NOT WEBP_FOUND) - if(EXISTS ${LIBDIR}/webp) - set(WEBP_INCLUDE_DIRS ${LIBDIR}/webp/include) - set(WEBP_ROOT_DIR ${LIBDIR}/webp) - set(WEBP_LIBRARIES ${LIBDIR}/webp/lib/webp.lib ${LIBDIR}/webp/lib/webpdemux.lib ${LIBDIR}/webp/lib/webpmux.lib) - set(WEBP_FOUND ON) - else() - message(STATUS "WITH_IMAGE_WEBP is ON but WEBP libraries are not found, setting WITH_IMAGE_WEBP=OFF") - set(WITH_IMAGE_WEBP OFF) - endif() - endif() + set(WEBP_INCLUDE_DIRS ${LIBDIR}/webp/include) + set(WEBP_ROOT_DIR ${LIBDIR}/webp) + set(WEBP_LIBRARIES ${LIBDIR}/webp/lib/webp.lib ${LIBDIR}/webp/lib/webpdemux.lib ${LIBDIR}/webp/lib/webpmux.lib) + set(WEBP_FOUND ON) endif() if(WITH_OPENCOLLADA) @@ -358,7 +350,6 @@ if(WITH_OPENCOLLADA) optimized ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter.lib optimized ${OPENCOLLADA}/lib/opencollada/MathMLSolver.lib optimized ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser.lib - optimized ${OPENCOLLADA}/lib/opencollada/xml.lib optimized ${OPENCOLLADA}/lib/opencollada/buffer.lib optimized ${OPENCOLLADA}/lib/opencollada/ftoa.lib @@ -368,10 +359,14 @@ if(WITH_OPENCOLLADA) debug ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter_d.lib debug ${OPENCOLLADA}/lib/opencollada/MathMLSolver_d.lib debug ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser_d.lib - debug ${OPENCOLLADA}/lib/opencollada/xml_d.lib debug ${OPENCOLLADA}/lib/opencollada/buffer_d.lib debug ${OPENCOLLADA}/lib/opencollada/ftoa_d.lib ) + if(EXISTS ${LIBDIR}/xml2/lib/libxml2s.lib) # 3.4 libraries + list(APPEND OPENCOLLADA_LIBRARIES ${LIBDIR}/xml2/lib/libxml2s.lib) + else() + list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/xml.lib) + endif() list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/UTF.lib) @@ -679,11 +674,11 @@ endif() if(WITH_IMAGE_OPENJPEG) set(OPENJPEG ${LIBDIR}/openjpeg) - set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.4) + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.5) if(NOT EXISTS "${OPENJPEG_INCLUDE_DIRS}") - # when not found, could be an older lib folder with openjpeg 2.3 - # to ease the transition period, fall back if 2.4 is not found. - set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.3) + # when not found, could be an older lib folder with openjpeg 2.4 + # to ease the transition period, fall back if 2.5 is not found. + set(OPENJPEG_INCLUDE_DIRS ${OPENJPEG}/include/openjpeg-2.4) endif() set(OPENJPEG_LIBRARIES ${OPENJPEG}/lib/openjp2.lib) endif() @@ -700,12 +695,6 @@ if(WITH_OPENSUBDIV) debug ${OPENSUBDIV_LIBPATH}/osdCPU_d.lib debug ${OPENSUBDIV_LIBPATH}/osdGPU_d.lib ) - set(OPENSUBDIV_HAS_OPENMP TRUE) - set(OPENSUBDIV_HAS_TBB FALSE) - set(OPENSUBDIV_HAS_OPENCL TRUE) - set(OPENSUBDIV_HAS_CUDA FALSE) - set(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK TRUE) - set(OPENSUBDIV_HAS_GLSL_COMPUTE TRUE) endif() endif() @@ -773,9 +762,11 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) find_library(OSL_LIB_EXEC NAMES oslexec PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_COMP NAMES oslcomp PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_QUERY NAMES oslquery PATHS ${CYCLES_OSL}/lib) + find_library(OSL_LIB_NOISE NAMES oslnoise PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_EXEC_DEBUG NAMES oslexec_d PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_COMP_DEBUG NAMES oslcomp_d PATHS ${CYCLES_OSL}/lib) find_library(OSL_LIB_QUERY_DEBUG NAMES oslquery_d PATHS ${CYCLES_OSL}/lib) + find_library(OSL_LIB_NOISE_DEBUG NAMES oslnoise_d PATHS ${CYCLES_OSL}/lib) list(APPEND OSL_LIBRARIES optimized ${OSL_LIB_COMP} optimized ${OSL_LIB_EXEC} @@ -785,15 +776,14 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL) debug ${OSL_LIB_QUERY_DEBUG} ${PUGIXML_LIBRARIES} ) + if(OSL_LIB_NOISE) + list(APPEND OSL_LIBRARIES optimized ${OSL_LIB_NOISE}) + endif() + if(OSL_LIB_NOISE_DEBUG) + list(APPEND OSL_LIBRARIES debug ${OSL_LIB_NOISE_DEBUG}) + endif() find_path(OSL_INCLUDE_DIR OSL/oslclosure.h PATHS ${CYCLES_OSL}/include) find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin) - - if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER) - set(OSL_FOUND TRUE) - else() - message(STATUS "OSL not found") - set(WITH_CYCLES_OSL OFF) - endif() endif() if(WITH_CYCLES AND WITH_CYCLES_EMBREE) @@ -893,21 +883,16 @@ if(WINDOWS_PYTHON_DEBUG) endif() if(WITH_XR_OPENXR) - if(EXISTS ${LIBDIR}/xr_openxr_sdk) - set(XR_OPENXR_SDK ${LIBDIR}/xr_openxr_sdk) - set(XR_OPENXR_SDK_LIBPATH ${LIBDIR}/xr_openxr_sdk/lib) - set(XR_OPENXR_SDK_INCLUDE_DIR ${XR_OPENXR_SDK}/include) - # This is the old name of this library, it is checked to - # support the transition between the old and new lib versions - # this can be removed after the next lib update. - if(EXISTS ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) - set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) - else() - set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loaderd.lib) - endif() + set(XR_OPENXR_SDK ${LIBDIR}/xr_openxr_sdk) + set(XR_OPENXR_SDK_LIBPATH ${LIBDIR}/xr_openxr_sdk/lib) + set(XR_OPENXR_SDK_INCLUDE_DIR ${XR_OPENXR_SDK}/include) + # This is the old name of this library, it is checked to + # support the transition between the old and new lib versions + # this can be removed after the next lib update. + if(EXISTS ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) + set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loader_d.lib) else() - message(WARNING "OpenXR-SDK was not found, disabling WITH_XR_OPENXR") - set(WITH_XR_OPENXR OFF) + set(XR_OPENXR_SDK_LIBRARIES optimized ${XR_OPENXR_SDK_LIBPATH}/openxr_loader.lib debug ${XR_OPENXR_SDK_LIBPATH}/openxr_loaderd.lib) endif() endif() @@ -925,15 +910,10 @@ if(WITH_POTRACE) endif() if(WITH_HARU) - if(EXISTS ${LIBDIR}/haru) - set(HARU_FOUND ON) - set(HARU_ROOT_DIR ${LIBDIR}/haru) - set(HARU_INCLUDE_DIRS ${HARU_ROOT_DIR}/include) - set(HARU_LIBRARIES ${HARU_ROOT_DIR}/lib/libhpdfs.lib) - else() - message(WARNING "Haru was not found, disabling WITH_HARU") - set(WITH_HARU OFF) - endif() + set(HARU_FOUND ON) + set(HARU_ROOT_DIR ${LIBDIR}/haru) + set(HARU_INCLUDE_DIRS ${HARU_ROOT_DIR}/include) + set(HARU_LIBRARIES ${HARU_ROOT_DIR}/lib/libhpdfs.lib) endif() if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING) diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml index 82cd009ea95..3359f89c41e 100644 --- a/build_files/config/pipeline_config.yaml +++ b/build_files/config/pipeline_config.yaml @@ -58,6 +58,8 @@ buildbot: version: '5.2.21440' optix: version: '7.3.0' + ocloc: + version: '101.3430' cmake: default: version: any diff --git a/build_files/utils/make_bpy_wheel.py b/build_files/utils/make_bpy_wheel.py index ba1d0f21937..81d267c6e10 100755 --- a/build_files/utils/make_bpy_wheel.py +++ b/build_files/utils/make_bpy_wheel.py @@ -208,12 +208,15 @@ def main() -> None: dist_dir = os.path.join(install_dir, "dist") for f in os.listdir(dist_dir): if f.endswith(".whl"): - # No apparent way to override this ABI version with setuptools, so rename. - sys_py = "cp%d%d" % (sys.version_info.major, sys.version_info.minor) - sys_py_abi = sys_py + sys.abiflags blender_py = "cp%d%d" % (python_version_number[0], python_version_number[1]) - renamed_f = f.replace(sys_py_abi, blender_py).replace(sys_py, blender_py) + # No apparent way to override this ABI version with setuptools, so rename. + sys_py = "cp%d%d" % (sys.version_info.major, sys.version_info.minor) + if hasattr(sys, "abiflags"): + sys_py_abi = sys_py + sys.abiflags + renamed_f = f.replace(sys_py_abi, blender_py).replace(sys_py, blender_py) + else: + renamed_f = f.replace(sys_py, blender_py) os.rename(os.path.join(dist_dir, f), os.path.join(output_dir, renamed_f)) diff --git a/build_files/utils/make_update.py b/build_files/utils/make_update.py index 254cccda301..a0b61b18e60 100755 --- a/build_files/utils/make_update.py +++ b/build_files/utils/make_update.py @@ -18,8 +18,13 @@ import sys import make_utils from make_utils import call, check_output +from typing import ( + List, + Optional, +) -def print_stage(text): + +def print_stage(text: str) -> None: print("") print(text) print("") @@ -27,7 +32,7 @@ def print_stage(text): # Parse arguments -def parse_arguments(): +def parse_arguments() -> argparse.Namespace: parser = argparse.ArgumentParser() parser.add_argument("--no-libraries", action="store_true") parser.add_argument("--no-blender", action="store_true") @@ -40,13 +45,13 @@ def parse_arguments(): return parser.parse_args() -def get_blender_git_root(): +def get_blender_git_root() -> str: return check_output([args.git_command, "rev-parse", "--show-toplevel"]) # Setup for precompiled libraries and tests from svn. -def svn_update(args, release_version): +def svn_update(args: argparse.Namespace, release_version: Optional[str]) -> None: svn_non_interactive = [args.svn_command, '--non-interactive'] lib_dirpath = os.path.join(get_blender_git_root(), '..', 'lib') @@ -99,42 +104,42 @@ def svn_update(args, release_version): call(svn_non_interactive + ["checkout", svn_url_tests, lib_tests_dirpath]) # Update precompiled libraries and tests - print_stage("Updating Precompiled Libraries and Tests") - - 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 - elif dirname.startswith("."): - # Temporary paths such as ".mypy_cache" will report a warning, skip hidden directories. - continue - - svn_dirpath = os.path.join(dirpath, ".svn") - svn_root_dirpath = os.path.join(lib_dirpath, ".svn") - - if ( - os.path.isdir(dirpath) and - (os.path.exists(svn_dirpath) or os.path.exists(svn_root_dirpath)) - ): - if make_utils.command_missing(args.svn_command): - sys.stderr.write("svn not found, can't update libraries\n") - sys.exit(1) - - # Cleanup to continue with interrupted downloads. - if os.path.exists(svn_dirpath): - call(svn_non_interactive + ["cleanup", dirpath]) + + if not os.path.isdir(lib_dirpath): + print("Library path: %r, not found, skipping" % lib_dirpath) + else: + paths_local_and_remote = [] + if os.path.exists(os.path.join(lib_dirpath, ".svn")): + print_stage("Updating Precompiled Libraries and Tests (one repository)") + paths_local_and_remote.append((lib_dirpath, svn_url)) + else: + print_stage("Updating Precompiled Libraries and Tests (multiple repositories)") + # Separate paths checked out. + for dirname in os.listdir(lib_dirpath): + if dirname.startswith("."): + # Temporary paths such as ".mypy_cache" will report a warning, skip hidden directories. + continue + + dirpath = os.path.join(lib_dirpath, dirname) + if not (os.path.isdir(dirpath) and os.path.exists(os.path.join(dirpath, ".svn"))): + continue + + paths_local_and_remote.append((dirpath, svn_url + dirname)) + + if paths_local_and_remote: + if make_utils.command_missing(args.svn_command): + sys.stderr.write("svn not found, can't update libraries\n") + sys.exit(1) + + for dirpath, svn_url_full in paths_local_and_remote: + call(svn_non_interactive + ["cleanup", dirpath]) # Switch to appropriate branch and update. - call(svn_non_interactive + ["switch", svn_url + dirname, dirpath], exit_on_error=False) + call(svn_non_interactive + ["switch", svn_url_full, dirpath], exit_on_error=False) call(svn_non_interactive + ["update", dirpath]) # Test if git repo can be updated. -def git_update_skip(args, check_remote_exists=True): +def git_update_skip(args: argparse.Namespace, check_remote_exists: bool = True) -> str: if make_utils.command_missing(args.git_command): sys.stderr.write("git not found, can't update code\n") sys.exit(1) @@ -166,13 +171,17 @@ def git_update_skip(args, check_remote_exists=True): # Update blender repository. -def blender_update(args): +def blender_update(args: argparse.Namespace) -> None: print_stage("Updating Blender Git Repository") call([args.git_command, "pull", "--rebase"]) # Update submodules. -def submodules_update(args, release_version, branch): +def submodules_update( + args: argparse.Namespace, + release_version: Optional[str], + branch: Optional[str], +) -> str: print_stage("Updating Submodules") if make_utils.command_missing(args.git_command): sys.stderr.write("git not found, can't update code\n") @@ -214,7 +223,8 @@ def submodules_update(args, release_version, branch): elif make_utils.git_branch_exists(args.git_command, submodule_branch_fallback): submodule_branch = submodule_branch_fallback else: - submodule_branch = None + # Skip. + submodule_branch = "" # Switch to branch and pull. if submodule_branch: diff --git a/build_files/utils/make_utils.py b/build_files/utils/make_utils.py index 564930617ff..9b15eb363bc 100755 --- a/build_files/utils/make_utils.py +++ b/build_files/utils/make_utils.py @@ -80,7 +80,7 @@ def git_tag(git_command: str) -> Optional[str]: return tag.strip().decode('utf8') -def git_branch_release_version(branch: str, tag: str) -> Optional[str]: +def git_branch_release_version(branch: str, tag: Optional[str]) -> Optional[str]: re_match = re.search("^blender-v(.*)-release$", branch) release_version = None if re_match: diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd index eaf4a85f7ac..a2ff4c1ff95 100644 --- a/build_files/windows/parse_arguments.cmd +++ b/build_files/windows/parse_arguments.cmd @@ -80,9 +80,11 @@ if NOT "%1" == "" ( REM Non-Build Commands ) else if "%1" == "update" ( SET BUILD_UPDATE=1 + SET BUILD_UPDATE_SVN=1 set BUILD_UPDATE_ARGS= ) else if "%1" == "code_update" ( SET BUILD_UPDATE=1 + SET BUILD_UPDATE_SVN=0 set BUILD_UPDATE_ARGS="--no-libraries" ) else if "%1" == "ninja" ( SET BUILD_WITH_NINJA=1 diff --git a/build_files/windows/reset_variables.cmd b/build_files/windows/reset_variables.cmd index 8ba7b4d3307..37c5d1034ea 100644 --- a/build_files/windows/reset_variables.cmd +++ b/build_files/windows/reset_variables.cmd @@ -34,3 +34,4 @@ set BUILD_WITH_SCCACHE= set ICONS= set ICONS_GEOM= set DOC_PY= +SET BUILD_UPDATE_SVN=
\ No newline at end of file diff --git a/build_files/windows/svn_update.cmd b/build_files/windows/svn_update.cmd new file mode 100644 index 00000000000..f91f03f15b3 --- /dev/null +++ b/build_files/windows/svn_update.cmd @@ -0,0 +1,24 @@ +if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15 +if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15 + +set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST% +set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%" + +cd %BUILD_VS_LIBDIR% +:RETRY +"%SVN%" update +if errorlevel 1 ( + set /p LibRetry= "Error during update, retry? y/n" + if /I "!LibRetry!"=="Y" ( + "%SVN%" cleanup + goto RETRY + ) + echo. + echo Error: Download of external libraries failed. + echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in + echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successful blender build + echo. + exit /b 1 +) + +cd %BLENDER_DIR%
\ No newline at end of file diff --git a/extern/hipew/src/hipew.c b/extern/hipew/src/hipew.c index ecf952e266f..7cafe7727f5 100644 --- a/extern/hipew/src/hipew.c +++ b/extern/hipew/src/hipew.c @@ -253,7 +253,7 @@ static int hipewHipInit(void) { /* Default installation path. */ const char *hip_paths[] = {"", NULL}; #else - const char *hip_paths[] = {"/opt/rocm/hip/lib/libamdhip64.so", NULL}; + const char *hip_paths[] = {"libamdhip64.so", "/opt/rocm/hip/lib/libamdhip64.so", NULL}; #endif static int initialized = 0; static int result = 0; diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index f619e6b104e..329aa3990f6 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -263,8 +263,7 @@ if(WITH_CYCLES_DEVICE_OPTIX) ${OPTIX_INCLUDE_DIR} ) else() - message(STATUS "OptiX not found, disabling it from Cycles") - set(WITH_CYCLES_DEVICE_OPTIX OFF) + set_and_warn_library_found("OptiX" OPTIX_FOUND WITH_CYCLES_DEVICE_OPTIX) endif() endif() @@ -387,8 +386,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif() if(WITH_CYCLES_HYDRA_RENDER_DELEGATE AND (NOT WITH_USD)) - message(STATUS "USD not found, disabling WITH_CYCLES_HYDRA_RENDER_DELEGATE") - set(WITH_CYCLES_HYDRA_RENDER_DELEGATE OFF) + set_and_warn_library_found("USD" WITH_USD WITH_CYCLES_HYDRA_RENDER_DELEGATE) endif() if(WITH_CYCLES_HYDRA_RENDER_DELEGATE AND (NOT WITH_BLENDER) AND (NOT WITH_CYCLES_STANDALONE)) set(CYCLES_INSTALL_PATH ${CYCLES_INSTALL_PATH}/hdCycles/resources) diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index 0988b1c0ac4..1c7a861ea93 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -43,7 +43,10 @@ else() endif() if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) - list(APPEND INC_SYS ${Epoxy_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${Epoxy_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIRS} + ) list(APPEND LIB ${Epoxy_LIBRARIES} ${SDL2_LIBRARIES}) endif() diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 794338fe78e..e33891fa7a2 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -209,22 +209,25 @@ def list_render_passes(scene, srl): yield ("Debug Sample Count", "X", 'VALUE') # Cryptomatte passes. - crypto_depth = (srl.pass_cryptomatte_depth + 1) // 2 + # NOTE: Name channels are lowercase RGBA so that compression rules check in OpenEXR DWA code + # uses lossless compression. Reportedly this naming is the only one which works good from the + # interoperability point of view. Using XYZW naming is not portable. + crypto_depth = (min(16, srl.pass_cryptomatte_depth) + 1) // 2 if srl.use_pass_cryptomatte_object: for i in range(0, crypto_depth): - yield ("CryptoObject" + '{:02d}'.format(i), "RGBA", 'COLOR') + yield ("CryptoObject" + '{:02d}'.format(i), "rgba", 'COLOR') if srl.use_pass_cryptomatte_material: for i in range(0, crypto_depth): - yield ("CryptoMaterial" + '{:02d}'.format(i), "RGBA", 'COLOR') + yield ("CryptoMaterial" + '{:02d}'.format(i), "rgba", 'COLOR') if srl.use_pass_cryptomatte_asset: for i in range(0, crypto_depth): - yield ("CryptoAsset" + '{:02d}'.format(i), "RGBA", 'COLOR') + yield ("CryptoAsset" + '{:02d}'.format(i), "rgba", 'COLOR') # Denoising passes. if scene.cycles.use_denoising and crl.use_denoising: yield ("Noisy Image", "RGBA", 'COLOR') if crl.use_pass_shadow_catcher: - yield ("Noisy Shadow Catcher", "RGBA", 'COLOR') + yield ("Noisy Shadow Catcher", "RGB", 'COLOR') if crl.denoising_store_passes: yield ("Denoising Normal", "XYZ", 'VECTOR') yield ("Denoising Albedo", "RGB", 'COLOR') @@ -232,6 +235,8 @@ def list_render_passes(scene, srl): # Custom AOV passes. for aov in srl.aovs: + if not aov.is_valid: + continue if aov.type == 'VALUE': yield (aov.name, "X", 'VALUE') else: diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index b7ce76d8f44..f5cd88f6b6a 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -60,13 +60,14 @@ enum_filter_types = ( ) enum_panorama_types = ( - ('EQUIRECTANGULAR', "Equirectangular", "Render the scene with a spherical camera, also known as Lat Long panorama"), - ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions"), + ('EQUIRECTANGULAR', "Equirectangular", "Spherical camera for environment maps, also known as Lat Long panorama", 0), + ('EQUIANGULAR_CUBEMAP_FACE', "Equiangular Cubemap Face", "Single face of an equiangular cubemap", 5), + ('MIRRORBALL', "Mirror Ball", "Mirror ball mapping for environment maps", 3), + ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions", 1), ('FISHEYE_EQUISOLID', "Fisheye Equisolid", - "Similar to most fisheye modern lens, takes sensor dimensions into consideration"), - ('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"), + "Similar to most fisheye modern lens, takes sensor dimensions into consideration", 2), ('FISHEYE_LENS_POLYNOMIAL', "Fisheye Lens Polynomial", - "Defines the lens projection as polynomial to allow real world camera lenses to be mimicked"), + "Defines the lens projection as polynomial to allow real world camera lenses to be mimicked", 4), ) enum_curve_shape = ( @@ -1636,11 +1637,13 @@ class CyclesPreferences(bpy.types.AddonPreferences): col.label(text="and AMD driver version 22.10 or newer", icon='BLANK1') elif device_type == 'ONEAPI': import sys - col.label(text="Requires Intel GPU with Xe-HPG architecture", icon='BLANK1') if sys.platform.startswith("win"): + col.label(text="Requires Intel GPU with Xe-HPG architecture", icon='BLANK1') col.label(text="and Windows driver version 101.3430 or newer", icon='BLANK1') elif sys.platform.startswith("linux"): - col.label(text="and Linux driver version xx.xx.23904 or newer", icon='BLANK1') + col.label(text="Requires Intel GPU with Xe-HPG architecture and", icon='BLANK1') + col.label(text=" - Linux driver version xx.xx.23904 or newer", icon='BLANK1') + col.label(text=" - oneAPI Level-Zero Loader", icon='BLANK1') elif device_type == 'METAL': col.label(text="Requires Apple Silicon with macOS 12.2 or newer", icon='BLANK1') col.label(text="or AMD with macOS 12.3 or newer", icon='BLANK1') @@ -1651,6 +1654,7 @@ class CyclesPreferences(bpy.types.AddonPreferences): box.prop( device, "use", text=device.name .replace('(TM)', unicodedata.lookup('TRADE MARK SIGN')) + .replace('(tm)', unicodedata.lookup('TRADE MARK SIGN')) .replace('(R)', unicodedata.lookup('REGISTERED SIGN')) .replace('(C)', unicodedata.lookup('COPYRIGHT SIGN')) ) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index f763fe0eb0b..305accc8f1a 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -150,6 +150,16 @@ def get_effective_preview_denoiser(context): return 'OIDN' +def use_mnee(context): + # The MNEE kernel doesn't compile on macOS < 13. + if use_metal(context): + import platform + v, _, _ = platform.mac_ver() + if float(v) < 13.0: + return False + return True + + class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel): bl_label = "Sampling" @@ -1235,7 +1245,7 @@ class CYCLES_OBJECT_PT_shading_caustics(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): - return CyclesButtonsPanel.poll(context) and not use_metal(context) and context.object.type != 'LIGHT' + return CyclesButtonsPanel.poll(context) and use_mnee(context) and context.object.type != 'LIGHT' def draw(self, context): layout = self.layout @@ -1449,7 +1459,7 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel): sub.active = not (light.type == 'AREA' and clamp.is_portal) sub.prop(clamp, "cast_shadow") sub.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance") - if not use_metal(context): + if use_mnee(context): sub.prop(clamp, "is_caustics_light", text="Shadow Caustics") if light.type == 'AREA': diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp index f9a83b2dc4b..6641e2b8ac5 100644 --- a/intern/cycles/blender/session.cpp +++ b/intern/cycles/blender/session.cpp @@ -497,9 +497,9 @@ void BlenderSession::render_frame_finish() session->full_buffer_written_cb = function_null; /* The display driver is the source of drawing context for both drawing and possible graphics - * interop objects in the path trace. Once the frame is finished the OpenGL context might be - * freed form Blender side. Need to ensure that all GPU resources are freed prior to that - * point. + * interoperability objects in the path trace. Once the frame is finished the OpenGL context + * might be freed form Blender side. Need to ensure that all GPU resources are freed prior to + * that point. * Ideally would only do this when OpenGL context is actually destroyed, but there is no way to * know when this happens (at least in the code at the time when this comment was written). * The penalty of re-creating resources on every frame is unlikely to be noticed. */ diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp index a69a94614d3..5251f0fee9c 100644 --- a/intern/cycles/blender/sync.cpp +++ b/intern/cycles/blender/sync.cpp @@ -575,68 +575,72 @@ void BlenderSync::sync_images() /* Passes */ -static PassType get_blender_pass_type(BL::RenderPass &b_pass) +static bool get_known_pass_type(BL::RenderPass &b_pass, PassType &type, PassMode &mode) { string name = b_pass.name(); -#define MAP_PASS(passname, passtype) \ +#define MAP_PASS(passname, passtype, noisy) \ if (name == passname) { \ - return passtype; \ + type = passtype; \ + mode = (noisy) ? PassMode::NOISY : PassMode::DENOISED; \ + return true; \ } \ ((void)0) - /* NOTE: Keep in sync with defined names from DNA_scene_types.h */ + /* NOTE: Keep in sync with defined names from engine.py */ - MAP_PASS("Combined", PASS_COMBINED); - MAP_PASS("Noisy Image", PASS_COMBINED); + MAP_PASS("Combined", PASS_COMBINED, false); + MAP_PASS("Noisy Image", PASS_COMBINED, true); - MAP_PASS("Depth", PASS_DEPTH); - MAP_PASS("Mist", PASS_MIST); - MAP_PASS("Position", PASS_POSITION); - MAP_PASS("Normal", PASS_NORMAL); - MAP_PASS("IndexOB", PASS_OBJECT_ID); - MAP_PASS("UV", PASS_UV); - MAP_PASS("Vector", PASS_MOTION); - MAP_PASS("IndexMA", PASS_MATERIAL_ID); + MAP_PASS("Depth", PASS_DEPTH, false); + MAP_PASS("Mist", PASS_MIST, false); + MAP_PASS("Position", PASS_POSITION, false); + MAP_PASS("Normal", PASS_NORMAL, false); + MAP_PASS("IndexOB", PASS_OBJECT_ID, false); + MAP_PASS("UV", PASS_UV, false); + MAP_PASS("Vector", PASS_MOTION, false); + MAP_PASS("IndexMA", PASS_MATERIAL_ID, false); - MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT); - MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT); - MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT); - MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT); + MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT, false); + MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT, false); + MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT, false); + MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT, false); - MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT); - MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT); - MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT); - MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT); + MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT, false); + MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT, false); + MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT, false); + MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT, false); - MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR); - MAP_PASS("GlossCol", PASS_GLOSSY_COLOR); - MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR); + MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR, false); + MAP_PASS("GlossCol", PASS_GLOSSY_COLOR, false); + MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR, false); - MAP_PASS("Emit", PASS_EMISSION); - MAP_PASS("Env", PASS_BACKGROUND); - MAP_PASS("AO", PASS_AO); - MAP_PASS("Shadow", PASS_SHADOW); + MAP_PASS("Emit", PASS_EMISSION, false); + MAP_PASS("Env", PASS_BACKGROUND, false); + MAP_PASS("AO", PASS_AO, false); + MAP_PASS("Shadow", PASS_SHADOW, false); - MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE); - MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL); + MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE, false); + MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL, false); - MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL); - MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO); - MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH); + MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL, true); + MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO, true); + MAP_PASS("Denoising Depth", PASS_DENOISING_DEPTH, true); - MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER); - MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER); + MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER, false); + MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER, true); - MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER); - MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT); + MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER, false); + MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT, false); if (string_startswith(name, cryptomatte_prefix)) { - return PASS_CRYPTOMATTE; + type = PASS_CRYPTOMATTE; + mode = PassMode::DENOISED; + return true; } #undef MAP_PASS - return PASS_NONE; + return false; } static Pass *pass_add(Scene *scene, @@ -655,8 +659,6 @@ static Pass *pass_add(Scene *scene, void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - /* Delete all existing passes. */ set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end()); scene->delete_nodes(clear_passes); @@ -664,103 +666,23 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v /* Always add combined pass. */ pass_add(scene, PASS_COMBINED, "Combined"); - /* Blender built-in data and light passes. */ - for (BL::RenderPass &b_pass : b_rlay.passes) { - const PassType pass_type = get_blender_pass_type(b_pass); - - if (pass_type == PASS_NONE) { - LOG(ERROR) << "Unknown pass " << b_pass.name(); - continue; - } - - if (pass_type == PASS_MOTION && - (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) { - continue; - } - - pass_add(scene, pass_type, b_pass.name().c_str()); - } - - PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - - /* Debug passes. */ - if (get_boolean(crl, "pass_debug_sample_count")) { - b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str()); - pass_add(scene, PASS_SAMPLE_COUNT, "Debug Sample Count"); - } - - /* Cycles specific passes. */ - if (get_boolean(crl, "use_pass_volume_direct")) { - b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_VOLUME_DIRECT, "VolumeDir"); - } - if (get_boolean(crl, "use_pass_volume_indirect")) { - b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_VOLUME_INDIRECT, "VolumeInd"); - } - if (get_boolean(crl, "use_pass_shadow_catcher")) { - b_engine.add_pass("Shadow Catcher", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_SHADOW_CATCHER, "Shadow Catcher"); - } - /* Cryptomatte stores two ID/weight pairs per RGBA layer. - * User facing parameter is the number of pairs. - * - * NOTE: Name channels lowercase RGBA so that compression rules check in OpenEXR DWA code uses - * lossless compression. Reportedly this naming is the only one which works good from the - * interoperability point of view. Using XYZW naming is not portable. */ + * User facing parameter is the number of pairs. */ int crypto_depth = divide_up(min(16, b_view_layer.pass_cryptomatte_depth()), 2); scene->film->set_cryptomatte_depth(crypto_depth); CryptomatteType cryptomatte_passes = CRYPT_NONE; if (b_view_layer.use_pass_cryptomatte_object()) { - for (int i = 0; i < crypto_depth; i++) { - string passname = cryptomatte_prefix + string_printf("Object%02d", i); - b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str()); - pass_add(scene, PASS_CRYPTOMATTE, passname.c_str()); - } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT); } if (b_view_layer.use_pass_cryptomatte_material()) { - for (int i = 0; i < crypto_depth; i++) { - string passname = cryptomatte_prefix + string_printf("Material%02d", i); - b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str()); - pass_add(scene, PASS_CRYPTOMATTE, passname.c_str()); - } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL); } if (b_view_layer.use_pass_cryptomatte_asset()) { - for (int i = 0; i < crypto_depth; i++) { - string passname = cryptomatte_prefix + string_printf("Asset%02d", i); - b_engine.add_pass(passname.c_str(), 4, "rgba", b_view_layer.name().c_str()); - pass_add(scene, PASS_CRYPTOMATTE, passname.c_str()); - } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET); } scene->film->set_cryptomatte_passes(cryptomatte_passes); - /* Denoising passes. */ - const bool use_denoising = get_boolean(cscene, "use_denoising") && - get_boolean(crl, "use_denoising"); - const bool store_denoising_passes = get_boolean(crl, "denoising_store_passes"); - if (use_denoising) { - b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str()); - pass_add(scene, PASS_COMBINED, "Noisy Image", PassMode::NOISY); - if (get_boolean(crl, "use_pass_shadow_catcher")) { - b_engine.add_pass("Noisy Shadow Catcher", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_SHADOW_CATCHER, "Noisy Shadow Catcher", PassMode::NOISY); - } - } - if (store_denoising_passes) { - b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); - pass_add(scene, PASS_DENOISING_NORMAL, "Denoising Normal", PassMode::NOISY); - - b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str()); - pass_add(scene, PASS_DENOISING_ALBEDO, "Denoising Albedo", PassMode::NOISY); - - b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str()); - pass_add(scene, PASS_DENOISING_DEPTH, "Denoising Depth", PassMode::NOISY); - } - + /* Path guiding debug passes. */ #ifdef WITH_CYCLES_DEBUG b_engine.add_pass("Guiding Color", 3, "RGB", b_view_layer.name().c_str()); pass_add(scene, PASS_GUIDING_COLOR, "Guiding Color", PassMode::NOISY); @@ -772,6 +694,8 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v pass_add(scene, PASS_GUIDING_AVG_ROUGHNESS, "Guiding Average Roughness", PassMode::NOISY); #endif + unordered_set<string> expected_passes; + /* Custom AOV passes. */ BL::ViewLayer::aovs_iterator b_aov_iter; for (b_view_layer.aovs.begin(b_aov_iter); b_aov_iter != b_view_layer.aovs.end(); ++b_aov_iter) { @@ -781,16 +705,10 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v } string name = b_aov.name(); - bool is_color = b_aov.type() == BL::AOV::type_COLOR; + PassType type = (b_aov.type() == BL::AOV::type_COLOR) ? PASS_AOV_COLOR : PASS_AOV_VALUE; - if (is_color) { - b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str()); - pass_add(scene, PASS_AOV_COLOR, name.c_str()); - } - else { - b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str()); - pass_add(scene, PASS_AOV_VALUE, name.c_str()); - } + pass_add(scene, type, name.c_str()); + expected_passes.insert(name); } /* Light Group passes. */ @@ -802,9 +720,29 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v string name = string_printf("Combined_%s", b_lightgroup.name().c_str()); - b_engine.add_pass(name.c_str(), 3, "RGB", b_view_layer.name().c_str()); Pass *pass = pass_add(scene, PASS_COMBINED, name.c_str(), PassMode::NOISY); pass->set_lightgroup(ustring(b_lightgroup.name())); + expected_passes.insert(name); + } + + /* Sync the passes that were defined in engine.py. */ + for (BL::RenderPass &b_pass : b_rlay.passes) { + PassType pass_type = PASS_NONE; + PassMode pass_mode = PassMode::DENOISED; + + if (!get_known_pass_type(b_pass, pass_type, pass_mode)) { + if (!expected_passes.count(b_pass.name())) { + LOG(ERROR) << "Unknown pass " << b_pass.name(); + } + continue; + } + + if (pass_type == PASS_MOTION && + (b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) { + continue; + } + + pass_add(scene, pass_type, b_pass.name().c_str(), pass_mode); } scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold()); diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake index 9524cda54f5..44542a08156 100644 --- a/intern/cycles/cmake/external_libs.cmake +++ b/intern/cycles/cmake/external_libs.cmake @@ -289,8 +289,7 @@ if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_PATH_GUIDING) endif() get_target_property(OPENPGL_INCLUDE_DIR openpgl::openpgl INTERFACE_INCLUDE_DIRECTORIES) else() - set(WITH_CYCLES_PATH_GUIDING OFF) - message(STATUS "OpenPGL not found, disabling WITH_CYCLES_PATH_GUIDING") + set_and_warn_library_found("OpenPGL" openpgl_FOUND WITH_CYCLES_PATH_GUIDING) endif() endif() @@ -588,16 +587,14 @@ if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) # We can't use the version from the Blender precompiled libraries because # it does not include the video subsystem. find_package(SDL2 REQUIRED) + set_and_warn_library_found("SDL" SDL2_FOUND WITH_CYCLES_STANDALONE_GUI) - if(NOT SDL2_FOUND) - set(WITH_CYCLES_STANDALONE_GUI OFF) - message(STATUS "SDL not found, disabling Cycles standalone GUI") + if(SDL2_FOUND) + include_directories( + SYSTEM + ${SDL2_INCLUDE_DIRS} + ) endif() - - include_directories( - SYSTEM - ${SDL2_INCLUDE_DIRS} - ) endif() ########################################################################### @@ -606,11 +603,11 @@ endif() if(WITH_CYCLES_DEVICE_CUDA AND (WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD)) find_package(CUDA) # Try to auto locate CUDA toolkit + set_and_warn_library_found("CUDA compiler" CUDA_FOUND WITH_CYCLES_CUDA_BINARIES) + if(CUDA_FOUND) message(STATUS "Found CUDA ${CUDA_NVCC_EXECUTABLE} (${CUDA_VERSION})") else() - message(STATUS "CUDA compiler not found, disabling WITH_CYCLES_CUDA_BINARIES") - set(WITH_CYCLES_CUDA_BINARIES OFF) if(NOT WITH_CUDA_DYNLOAD) message(STATUS "Additionally falling back to dynamic CUDA load") set(WITH_CUDA_DYNLOAD ON) @@ -624,11 +621,10 @@ endif() if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) find_package(HIP) + set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES) + if(HIP_FOUND) message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})") - else() - message(STATUS "HIP compiler not found, disabling WITH_CYCLES_HIP_BINARIES") - set(WITH_CYCLES_HIP_BINARIES OFF) endif() endif() @@ -644,13 +640,17 @@ if(WITH_CYCLES_DEVICE_METAL) find_library(METAL_LIBRARY Metal) # This file was added in the 12.0 SDK, use it as a way to detect the version. - if(METAL_LIBRARY AND NOT EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h") - message(STATUS "Metal version too old, must be SDK 12.0 or newer, disabling WITH_CYCLES_DEVICE_METAL") - set(WITH_CYCLES_DEVICE_METAL OFF) - elseif(NOT METAL_LIBRARY) - message(STATUS "Metal not found, disabling WITH_CYCLES_DEVICE_METAL") - set(WITH_CYCLES_DEVICE_METAL OFF) - else() + if(METAL_LIBRARY) + if(EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h") + set(METAL_FOUND ON) + else() + message(STATUS "Metal version too old, must be SDK 12.0 or newer") + set(METAL_FOUND OFF) + endif() + endif() + + set_and_warn_library_found("Metal" METAL_FOUND WITH_CYCLES_DEVICE_METAL) + if(METAL_FOUND) message(STATUS "Found Metal: ${METAL_LIBRARY}") endif() endif() @@ -662,9 +662,10 @@ endif() if(WITH_CYCLES_DEVICE_ONEAPI) find_package(SYCL) find_package(LevelZero) + set_and_warn_library_found("oneAPI" SYCL_FOUND WITH_CYCLES_DEVICE_ONEAPI) + set_and_warn_library_found("Level Zero" LEVEL_ZERO_FOUND WITH_CYCLES_DEVICE_ONEAPI) - if(SYCL_FOUND AND LEVEL_ZERO_FOUND) - message(STATUS "Found oneAPI: ${SYCL_LIBRARY}") + if(SYCL_FOUND AND SYCL_VERSION VERSION_GREATER_EQUAL 6.0 AND LEVEL_ZERO_FOUND) message(STATUS "Found Level Zero: ${LEVEL_ZERO_LIBRARY}") if(WITH_CYCLES_ONEAPI_BINARIES) @@ -675,13 +676,14 @@ if(WITH_CYCLES_DEVICE_ONEAPI) endif() if(NOT EXISTS ${OCLOC_INSTALL_DIR}) - message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}, disabling WITH_CYCLES_ONEAPI_BINARIES." + set(OCLOC_FOUND OFF) + message(STATUS "oneAPI ocloc not found in ${OCLOC_INSTALL_DIR}." " A different ocloc directory can be set using OCLOC_INSTALL_DIR cmake variable.") - set(WITH_CYCLES_ONEAPI_BINARIES OFF) + set_and_warn_library_found("ocloc" OCLOC_FOUND WITH_CYCLES_ONEAPI_BINARIES) endif() endif() else() - message(STATUS "oneAPI or Level Zero not found, disabling WITH_CYCLES_DEVICE_ONEAPI") + message(STATUS "SYCL 6.0+ or Level Zero not found, disabling WITH_CYCLES_DEVICE_ONEAPI") set(WITH_CYCLES_DEVICE_ONEAPI OFF) endif() endif() diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt index 5516e97f34f..5296d819e42 100644 --- a/intern/cycles/device/CMakeLists.txt +++ b/intern/cycles/device/CMakeLists.txt @@ -187,18 +187,22 @@ if(WITH_CYCLES_DEVICE_METAL) ) endif() if (WITH_CYCLES_DEVICE_ONEAPI) + if(WITH_CYCLES_ONEAPI_BINARIES) + set(cycles_kernel_oneapi_lib_suffix "_aot") + else() + set(cycles_kernel_oneapi_lib_suffix "_jit") + endif() if(WIN32) - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/cycles_kernel_oneapi.lib) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.lib) else() - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi.so) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so) + endif() + list(APPEND LIB ${cycles_kernel_oneapi_lib}) + if(WIN32) + list(APPEND LIB debug ${SYCL_LIBRARY_DEBUG} optimized ${SYCL_LIBRARY}) + else() + list(APPEND LIB ${SYCL_LIBRARY}) endif() - list(APPEND LIB - ${cycles_kernel_oneapi_lib} - "$<$<CONFIG:Debug>:${SYCL_LIBRARY_DEBUG}>" - "$<$<CONFIG:Release>:${SYCL_LIBRARY}>" - "$<$<CONFIG:RelWithDebInfo>:${SYCL_LIBRARY}>" - "$<$<CONFIG:MinSizeRel>:${SYCL_LIBRARY}>" - ) add_definitions(-DWITH_ONEAPI) list(APPEND SRC ${SRC_ONEAPI} diff --git a/intern/cycles/device/cuda/queue.cpp b/intern/cycles/device/cuda/queue.cpp index 84b0a1e0dd6..69fae03e32c 100644 --- a/intern/cycles/device/cuda/queue.cpp +++ b/intern/cycles/device/cuda/queue.cpp @@ -49,7 +49,7 @@ int CUDADeviceQueue::num_concurrent_states(const size_t state_size) const return num_states; } -int CUDADeviceQueue::num_concurrent_busy_states() const +int CUDADeviceQueue::num_concurrent_busy_states(const size_t /*state_size*/) const { const int max_num_threads = cuda_device_->get_num_multiprocessors() * cuda_device_->get_max_num_threads_per_multiprocessor(); diff --git a/intern/cycles/device/cuda/queue.h b/intern/cycles/device/cuda/queue.h index b450f5b3592..7107afe70c9 100644 --- a/intern/cycles/device/cuda/queue.h +++ b/intern/cycles/device/cuda/queue.h @@ -23,7 +23,7 @@ class CUDADeviceQueue : public DeviceQueue { ~CUDADeviceQueue(); virtual int num_concurrent_states(const size_t state_size) const override; - virtual int num_concurrent_busy_states() const override; + virtual int num_concurrent_busy_states(const size_t state_size) const override; virtual void init_execution() override; diff --git a/intern/cycles/device/hip/queue.cpp b/intern/cycles/device/hip/queue.cpp index 3f8b6267100..e93a9b4df3a 100644 --- a/intern/cycles/device/hip/queue.cpp +++ b/intern/cycles/device/hip/queue.cpp @@ -49,7 +49,7 @@ int HIPDeviceQueue::num_concurrent_states(const size_t state_size) const return num_states; } -int HIPDeviceQueue::num_concurrent_busy_states() const +int HIPDeviceQueue::num_concurrent_busy_states(const size_t /*state_size*/) const { const int max_num_threads = hip_device_->get_num_multiprocessors() * hip_device_->get_max_num_threads_per_multiprocessor(); diff --git a/intern/cycles/device/hip/queue.h b/intern/cycles/device/hip/queue.h index 729d8a19acb..df0678108af 100644 --- a/intern/cycles/device/hip/queue.h +++ b/intern/cycles/device/hip/queue.h @@ -23,7 +23,7 @@ class HIPDeviceQueue : public DeviceQueue { ~HIPDeviceQueue(); virtual int num_concurrent_states(const size_t state_size) const override; - virtual int num_concurrent_busy_states() const override; + virtual int num_concurrent_busy_states(const size_t state_size) const override; virtual void init_execution() override; diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index 6a16d4bb3b4..6f1042b1e55 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -296,9 +296,11 @@ void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_feat } source = global_defines + source; +# if 0 metal_printf("================\n%s================\n\%s================\n", global_defines.c_str(), baked_constants.c_str()); +# endif /* Generate an MD5 from the source and include any baked constants. This is used when caching * PSOs. */ @@ -339,6 +341,14 @@ bool MetalDevice::compile_and_load(MetalPipelineType pso_type) MTLCompileOptions *options = [[MTLCompileOptions alloc] init]; +# if defined(MAC_OS_VERSION_13_0) + if (@available(macos 13.0, *)) { + if (device_vendor == METAL_GPU_INTEL) { + [options setOptimizationLevel:MTLLibraryOptimizationLevelSize]; + } + } +# endif + options.fastMathEnabled = YES; if (@available(macOS 12.0, *)) { options.languageVersion = MTLLanguageVersion2_4; diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm index 5e0cb6d18f4..55938d1a03a 100644 --- a/intern/cycles/device/metal/kernel.mm +++ b/intern/cycles/device/metal/kernel.mm @@ -162,6 +162,13 @@ bool ShaderCache::should_load_kernel(DeviceKernel device_kernel, } } + if (device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE) { + if ((device->kernel_features & KERNEL_FEATURE_MNEE) == 0) { + /* Skip shade_surface_mnee kernel if the scene doesn't require it. */ + return false; + } + } + if (pso_type != PSO_GENERIC) { /* Only specialize kernels where it can make an impact. */ if (device_kernel < DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST || @@ -317,6 +324,12 @@ bool MetalKernelPipeline::should_use_binary_archive() const } } + /* Workaround for Intel GPU having issue using Binary Archives */ + MetalGPUVendor gpu_vendor = MetalInfo::get_device_vendor(mtlDevice); + if (gpu_vendor == METAL_GPU_INTEL) { + return false; + } + if (pso_type == PSO_GENERIC) { /* Archive the generic kernels. */ return true; diff --git a/intern/cycles/device/metal/queue.h b/intern/cycles/device/metal/queue.h index fc32740f3e1..2a6c12e2a60 100644 --- a/intern/cycles/device/metal/queue.h +++ b/intern/cycles/device/metal/queue.h @@ -23,7 +23,7 @@ class MetalDeviceQueue : public DeviceQueue { ~MetalDeviceQueue(); virtual int num_concurrent_states(const size_t) const override; - virtual int num_concurrent_busy_states() const override; + virtual int num_concurrent_busy_states(const size_t) const override; virtual int num_sort_partition_elements() const override; virtual void init_execution() override; diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm index 5ac63a16c61..c0df2c8553f 100644 --- a/intern/cycles/device/metal/queue.mm +++ b/intern/cycles/device/metal/queue.mm @@ -264,33 +264,46 @@ MetalDeviceQueue::~MetalDeviceQueue() } } -int MetalDeviceQueue::num_concurrent_states(const size_t /*state_size*/) const +int MetalDeviceQueue::num_concurrent_states(const size_t state_size) const { - /* METAL_WIP */ - /* TODO: compute automatically. */ - /* TODO: must have at least num_threads_per_block. */ - int result = 1048576; - if (metal_device_->device_vendor == METAL_GPU_AMD) { - result *= 2; + static int result = 0; + if (result) { + return result; } - else if (metal_device_->device_vendor == METAL_GPU_APPLE) { + + result = 1048576; + if (metal_device_->device_vendor == METAL_GPU_APPLE) { result *= 4; + + if (MetalInfo::get_apple_gpu_architecture(metal_device_->mtlDevice) == APPLE_M2) { + size_t system_ram = system_physical_ram(); + size_t allocated_so_far = [metal_device_->mtlDevice currentAllocatedSize]; + size_t max_recommended_working_set = [metal_device_->mtlDevice recommendedMaxWorkingSetSize]; + + /* Determine whether we can double the state count, and leave enough GPU-available memory + * (1/8 the system RAM or 1GB - whichever is largest). Enlarging the state size allows us to + * keep dispatch sizes high and minimize work submission overheads. */ + size_t min_headroom = std::max(system_ram / 8, size_t(1024 * 1024 * 1024)); + size_t total_state_size = result * state_size; + if (max_recommended_working_set - allocated_so_far - total_state_size * 2 >= min_headroom) { + result *= 2; + metal_printf("Doubling state count to exploit available RAM (new size = %d)\n", result); + } + } + } + else if (metal_device_->device_vendor == METAL_GPU_AMD) { + /* METAL_WIP */ + /* TODO: compute automatically. */ + /* TODO: must have at least num_threads_per_block. */ + result *= 2; } return result; } -int MetalDeviceQueue::num_concurrent_busy_states() const +int MetalDeviceQueue::num_concurrent_busy_states(const size_t state_size) const { - /* METAL_WIP */ - /* TODO: compute automatically. */ - int result = 65536; - if (metal_device_->device_vendor == METAL_GPU_AMD) { - result *= 2; - } - else if (metal_device_->device_vendor == METAL_GPU_APPLE) { - result *= 4; - } - return result; + /* A 1:4 busy:total ratio gives best rendering performance, independent of total state count. */ + return num_concurrent_states(state_size) / 4; } int MetalDeviceQueue::num_sort_partition_elements() const diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm index 65c67c400fe..f47638fac15 100644 --- a/intern/cycles/device/metal/util.mm +++ b/intern/cycles/device/metal/util.mm @@ -110,6 +110,12 @@ vector<id<MTLDevice>> const &MetalInfo::get_usable_devices() usable |= (vendor == METAL_GPU_AMD); } +# if defined(MAC_OS_VERSION_13_0) + if (@available(macos 13.0, *)) { + usable |= (vendor == METAL_GPU_INTEL); + } +# endif + if (usable) { metal_printf("- %s\n", device_name.c_str()); [device retain]; diff --git a/intern/cycles/device/oneapi/device.cpp b/intern/cycles/device/oneapi/device.cpp index f303ab41627..66d6f749e30 100644 --- a/intern/cycles/device/oneapi/device.cpp +++ b/intern/cycles/device/oneapi/device.cpp @@ -39,7 +39,7 @@ bool device_oneapi_init() _putenv_s("SYCL_CACHE_THRESHOLD", "0"); } if (getenv("SYCL_DEVICE_FILTER") == nullptr) { - _putenv_s("SYCL_DEVICE_FILTER", "host,level_zero"); + _putenv_s("SYCL_DEVICE_FILTER", "level_zero"); } if (getenv("SYCL_ENABLE_PCI") == nullptr) { _putenv_s("SYCL_ENABLE_PCI", "1"); @@ -50,7 +50,7 @@ bool device_oneapi_init() # elif __linux__ setenv("SYCL_CACHE_PERSISTENT", "1", false); setenv("SYCL_CACHE_THRESHOLD", "0", false); - setenv("SYCL_DEVICE_FILTER", "host,level_zero", false); + setenv("SYCL_DEVICE_FILTER", "level_zero", false); setenv("SYCL_ENABLE_PCI", "1", false); setenv("SYCL_PI_LEVEL_ZERO_USE_COPY_ENGINE_FOR_IN_ORDER_QUEUE", "0", false); # endif diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp index 91f53fd1eae..d0ddd69289c 100644 --- a/intern/cycles/device/oneapi/device_impl.cpp +++ b/intern/cycles/device/oneapi/device_impl.cpp @@ -430,9 +430,9 @@ void OneapiDevice::check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_ sycl::usm::alloc usm_type = get_pointer_type(usm_ptr, queue->get_context()); (void)usm_type; assert(usm_type == sycl::usm::alloc::device || - ((device_type == sycl::info::device_type::host || - device_type == sycl::info::device_type::cpu || allow_host) && - usm_type == sycl::usm::alloc::host)); + ((device_type == sycl::info::device_type::cpu || allow_host) && + usm_type == sycl::usm::alloc::host || + usm_type == sycl::usm::alloc::unknown)); # else /* Silence warning about unused arguments. */ (void)queue_; @@ -668,16 +668,9 @@ int OneapiDevice::parse_driver_build_version(const sycl::device &device) std::vector<sycl::device> OneapiDevice::available_devices() { bool allow_all_devices = false; - if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr) + if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr) { allow_all_devices = true; - - /* Host device is useful only for debugging at the moment - * so we hide this device with default build settings. */ -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED - bool allow_host = true; -# else - bool allow_host = false; -# endif + } const std::vector<sycl::platform> &oneapi_platforms = sycl::platform::get_platforms(); @@ -690,33 +683,28 @@ std::vector<sycl::device> OneapiDevice::available_devices() } const std::vector<sycl::device> &oneapi_devices = - (allow_all_devices || allow_host) ? platform.get_devices(sycl::info::device_type::all) : - platform.get_devices(sycl::info::device_type::gpu); + (allow_all_devices) ? platform.get_devices(sycl::info::device_type::all) : + platform.get_devices(sycl::info::device_type::gpu); for (const sycl::device &device : oneapi_devices) { - if (allow_all_devices) { - /* still filter out host device if build doesn't support it. */ - if (allow_host || !device.is_host()) { - available_devices.push_back(device); - } - } - else { - bool filter_out = false; - + bool filter_out = false; + if (!allow_all_devices) { /* For now we support all Intel(R) Arc(TM) devices and likely any future GPU, * assuming they have either more than 96 Execution Units or not 7 threads per EU. * Official support can be broaden to older and smaller GPUs once ready. */ - if (device.is_gpu() && platform.get_backend() == sycl::backend::ext_oneapi_level_zero) { - /* Filtered-out defaults in-case these values aren't available through too old L0 - * runtime. */ + if (!device.is_gpu() || platform.get_backend() != sycl::backend::ext_oneapi_level_zero) { + filter_out = true; + } + else { + /* Filtered-out defaults in-case these values aren't available. */ int number_of_eus = 96; int threads_per_eu = 7; if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) { - number_of_eus = device.get_info<sycl::info::device::ext_intel_gpu_eu_count>(); + number_of_eus = device.get_info<sycl::ext::intel::info::device::gpu_eu_count>(); } if (device.has(sycl::aspect::ext_intel_gpu_hw_threads_per_eu)) { threads_per_eu = - device.get_info<sycl::info::device::ext_intel_gpu_hw_threads_per_eu>(); + device.get_info<sycl::ext::intel::info::device::gpu_hw_threads_per_eu>(); } /* This filters out all Level-Zero supported GPUs from older generation than Arc. */ if (number_of_eus <= 96 && threads_per_eu == 7) { @@ -732,16 +720,9 @@ std::vector<sycl::device> OneapiDevice::available_devices() } } } - else if (!allow_host && device.is_host()) { - filter_out = true; - } - else if (!allow_all_devices) { - filter_out = true; - } - - if (!filter_out) { - available_devices.push_back(device); - } + } + if (!filter_out) { + available_devices.push_back(device); } } } @@ -797,9 +778,7 @@ char *OneapiDevice::device_capabilities() GET_NUM_ATTR(native_vector_width_double) GET_NUM_ATTR(native_vector_width_half) - size_t max_clock_frequency = - (size_t)(device.is_host() ? (size_t)0 : - device.get_info<sycl::info::device::max_clock_frequency>()); + size_t max_clock_frequency = device.get_info<sycl::info::device::max_clock_frequency>(); WRITE_ATTR("max_clock_frequency", max_clock_frequency) GET_NUM_ATTR(address_bits) @@ -837,7 +816,7 @@ void OneapiDevice::iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_p std::string name = device.get_info<sycl::info::device::name>(); std::string id = "ONEAPI_" + platform_name + "_" + name; if (device.has(sycl::aspect::ext_intel_pci_address)) { - id.append("_" + device.get_info<sycl::info::device::ext_intel_pci_address>()); + id.append("_" + device.get_info<sycl::ext::intel::info::device::pci_address>()); } (cb)(id.c_str(), name.c_str(), num, user_ptr); num++; @@ -855,7 +834,7 @@ int OneapiDevice::get_num_multiprocessors() { const sycl::device &device = reinterpret_cast<sycl::queue *>(device_queue_)->get_device(); if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) { - return device.get_info<sycl::info::device::ext_intel_gpu_eu_count>(); + return device.get_info<sycl::ext::intel::info::device::gpu_eu_count>(); } else return 0; @@ -866,8 +845,8 @@ int OneapiDevice::get_max_num_threads_per_multiprocessor() const sycl::device &device = reinterpret_cast<sycl::queue *>(device_queue_)->get_device(); if (device.has(sycl::aspect::ext_intel_gpu_eu_simd_width) && device.has(sycl::aspect::ext_intel_gpu_hw_threads_per_eu)) { - return device.get_info<sycl::info::device::ext_intel_gpu_eu_simd_width>() * - device.get_info<sycl::info::device::ext_intel_gpu_hw_threads_per_eu>(); + return device.get_info<sycl::ext::intel::info::device::gpu_eu_simd_width>() * + device.get_info<sycl::ext::intel::info::device::gpu_hw_threads_per_eu>(); } else return 0; diff --git a/intern/cycles/device/oneapi/device_impl.h b/intern/cycles/device/oneapi/device_impl.h index 62034150eac..197cf03d60d 100644 --- a/intern/cycles/device/oneapi/device_impl.h +++ b/intern/cycles/device/oneapi/device_impl.h @@ -3,7 +3,7 @@ #ifdef WITH_ONEAPI -# include <CL/sycl.hpp> +# include <sycl/sycl.hpp> # include "device/device.h" # include "device/oneapi/device.h" diff --git a/intern/cycles/device/oneapi/queue.cpp b/intern/cycles/device/oneapi/queue.cpp index 9632b14d485..3d019661aa8 100644 --- a/intern/cycles/device/oneapi/queue.cpp +++ b/intern/cycles/device/oneapi/queue.cpp @@ -43,7 +43,7 @@ int OneapiDeviceQueue::num_concurrent_states(const size_t state_size) const return num_states; } -int OneapiDeviceQueue::num_concurrent_busy_states() const +int OneapiDeviceQueue::num_concurrent_busy_states(const size_t /*state_size*/) const { const int max_num_threads = oneapi_device_->get_num_multiprocessors() * oneapi_device_->get_max_num_threads_per_multiprocessor(); diff --git a/intern/cycles/device/oneapi/queue.h b/intern/cycles/device/oneapi/queue.h index 32363bf2a6e..bbd947b49cb 100644 --- a/intern/cycles/device/oneapi/queue.h +++ b/intern/cycles/device/oneapi/queue.h @@ -25,7 +25,7 @@ class OneapiDeviceQueue : public DeviceQueue { virtual int num_concurrent_states(const size_t state_size) const override; - virtual int num_concurrent_busy_states() const override; + virtual int num_concurrent_busy_states(const size_t state_size) const override; virtual void init_execution() override; diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h index 1d6a8d736b7..e27e081a407 100644 --- a/intern/cycles/device/queue.h +++ b/intern/cycles/device/queue.h @@ -103,7 +103,7 @@ class DeviceQueue { /* Number of states which keeps the device occupied with work without losing performance. * The renderer will add more work (when available) when number of active paths falls below this * value. */ - virtual int num_concurrent_busy_states() const = 0; + virtual int num_concurrent_busy_states(const size_t state_size) const = 0; /* Number of elements in a partition of sorted shaders, that improves memory locality of * integrator state fetch at the cost of decreased coherence for shader kernel execution. */ diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp index ee250a6916b..547e8d50a22 100644 --- a/intern/cycles/integrator/path_trace_work_gpu.cpp +++ b/intern/cycles/integrator/path_trace_work_gpu.cpp @@ -18,13 +18,15 @@ CCL_NAMESPACE_BEGIN -static size_t estimate_single_state_size() +static size_t estimate_single_state_size(const uint kernel_features) { size_t state_size = 0; #define KERNEL_STRUCT_BEGIN(name) for (int array_index = 0;; array_index++) { -#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) state_size += sizeof(type); -#define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) state_size += sizeof(type); +#define KERNEL_STRUCT_MEMBER(parent_struct, type, name, feature) \ + state_size += (kernel_features & (feature)) ? sizeof(type) : 0; +#define KERNEL_STRUCT_ARRAY_MEMBER(parent_struct, type, name, feature) \ + state_size += (kernel_features & (feature)) ? sizeof(type) : 0; #define KERNEL_STRUCT_END(name) \ break; \ } @@ -76,16 +78,11 @@ PathTraceWorkGPU::PathTraceWorkGPU(Device *device, num_queued_paths_(device, "num_queued_paths", MEM_READ_WRITE), work_tiles_(device, "work_tiles", MEM_READ_WRITE), display_rgba_half_(device, "display buffer half", MEM_READ_WRITE), - max_num_paths_(queue_->num_concurrent_states(estimate_single_state_size())), - min_num_active_main_paths_(queue_->num_concurrent_busy_states()), + max_num_paths_(0), + min_num_active_main_paths_(0), max_active_main_path_index_(0) { memset(&integrator_state_gpu_, 0, sizeof(integrator_state_gpu_)); - - /* Limit number of active paths to the half of the overall state. This is due to the logic in the - * path compaction which relies on the fact that regeneration does not happen sooner than half of - * the states are available again. */ - min_num_active_main_paths_ = min(min_num_active_main_paths_, max_num_paths_ / 2); } void PathTraceWorkGPU::alloc_integrator_soa() @@ -103,6 +100,20 @@ void PathTraceWorkGPU::alloc_integrator_soa() integrator_state_soa_volume_stack_size_ = max(integrator_state_soa_volume_stack_size_, requested_volume_stack_size); + /* Determine the number of path states. Deferring this for as long as possible allows the + * back-end to make better decisions about memory availability. */ + if (max_num_paths_ == 0) { + size_t single_state_size = estimate_single_state_size(kernel_features); + + max_num_paths_ = queue_->num_concurrent_states(single_state_size); + min_num_active_main_paths_ = queue_->num_concurrent_busy_states(single_state_size); + + /* Limit number of active paths to the half of the overall state. This is due to the logic in + * the path compaction which relies on the fact that regeneration does not happen sooner than + * half of the states are available again. */ + min_num_active_main_paths_ = min(min_num_active_main_paths_, max_num_paths_ / 2); + } + /* Allocate a device only memory buffer before for each struct member, and then * write the pointers into a struct that resides in constant memory. * diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 36c8b23d983..81c5f593974 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -713,10 +713,17 @@ endif() # oneAPI module if(WITH_CYCLES_DEVICE_ONEAPI) + if(WITH_CYCLES_ONEAPI_BINARIES) + set(cycles_kernel_oneapi_lib_suffix "_aot") + else() + set(cycles_kernel_oneapi_lib_suffix "_jit") + endif() + if(WIN32) - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi.dll) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.dll) + set(cycles_kernel_oneapi_linker_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.lib) else() - set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/libcycles_kernel_oneapi.so) + set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so) endif() set(cycles_oneapi_kernel_sources @@ -751,10 +758,6 @@ if(WITH_CYCLES_DEVICE_ONEAPI) ${SYCL_CPP_FLAGS} ) - if (WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED) - list(APPEND sycl_compiler_flags -DWITH_ONEAPI_SYCL_HOST_ENABLED) - endif() - # Set defaults for spir64 and spir64_gen options if (NOT DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_spir64) set(CYCLES_ONEAPI_SYCL_OPTIONS_spir64 "-options '-ze-opt-large-register-file -ze-opt-regular-grf-kernel integrator_intersect'") @@ -767,6 +770,8 @@ if(WITH_CYCLES_DEVICE_ONEAPI) string(PREPEND CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "-device ${CYCLES_ONEAPI_SPIR64_GEN_DEVICES} ") if (WITH_CYCLES_ONEAPI_BINARIES) + # AoT binaries aren't currently reused when calling sycl::build. + list (APPEND sycl_compiler_flags -DSYCL_SKIP_KERNELS_PRELOAD) # Iterate over all targest and their options list (JOIN CYCLES_ONEAPI_SYCL_TARGETS "," targets_string) list (APPEND sycl_compiler_flags -fsycl-targets=${targets_string}) @@ -819,12 +824,17 @@ if(WITH_CYCLES_DEVICE_ONEAPI) -DONEAPI_EXPORT) string(REPLACE /Redist/ /Tools/ MSVC_TOOLS_DIR ${MSVC_REDIST_DIR}) - if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) # case for Ninja on Windows + # Version Folder between Redist and Tools can mismatch sometimes + if(NOT EXISTS ${MSVC_TOOLS_DIR}) + get_filename_component(cmake_ar_dir ${CMAKE_AR} DIRECTORY) + get_filename_component(MSVC_TOOLS_DIR "${cmake_ar_dir}/../../../" ABSOLUTE) + endif() + if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) + set(WINDOWS_KIT_DIR ${WINDOWS_KITS_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}) + else() # case for Ninja on Windows get_filename_component(cmake_mt_dir ${CMAKE_MT} DIRECTORY) string(REPLACE /bin/ /Lib/ WINDOWS_KIT_DIR ${cmake_mt_dir}) get_filename_component(WINDOWS_KIT_DIR "${WINDOWS_KIT_DIR}/../" ABSOLUTE) - else() - set(WINDOWS_KIT_DIR ${WINDOWS_KITS_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}) endif() list(APPEND sycl_compiler_flags -L "${MSVC_TOOLS_DIR}/lib/x64" @@ -836,15 +846,13 @@ if(WITH_CYCLES_DEVICE_ONEAPI) set(sycl_compiler_flags_RelWithDebInfo ${sycl_compiler_flags}) set(sycl_compiler_flags_MinSizeRel ${sycl_compiler_flags}) list(APPEND sycl_compiler_flags_RelWithDebInfo -g) - get_filename_component(sycl_library_debug_name ${SYCL_LIBRARY_DEBUG} NAME_WE) list(APPEND sycl_compiler_flags_Debug -g -D_DEBUG - -nostdlib -Xclang --dependent-lib=msvcrtd - -Xclang --dependent-lib=${sycl_library_debug_name}) + -nostdlib -Xclang --dependent-lib=msvcrtd) add_custom_command( - OUTPUT ${cycles_kernel_oneapi_lib} + OUTPUT ${cycles_kernel_oneapi_lib} ${cycles_kernel_oneapi_linker_lib} COMMAND ${CMAKE_COMMAND} -E env "LIB=${sycl_compiler_root}/../lib" # for compiler to find sycl.lib "PATH=${OCLOC_INSTALL_DIR}\;${sycl_compiler_root}" diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h index 2ffe1496c72..b31ba479e4f 100644 --- a/intern/cycles/kernel/bvh/shadow_all.h +++ b/intern/cycles/kernel/bvh/shadow_all.h @@ -229,7 +229,7 @@ ccl_device_inline /* Always use baked shadow transparency for curves. */ if (isect.type & PRIMITIVE_CURVE) { *r_throughput *= intersection_curve_shadow_transparency( - kg, isect.object, isect.prim, isect.u); + kg, isect.object, isect.prim, isect.type, isect.u); if (*r_throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) { return true; diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h index a57703a8b8c..9ba787550c5 100644 --- a/intern/cycles/kernel/bvh/util.h +++ b/intern/cycles/kernel/bvh/util.h @@ -190,10 +190,8 @@ ccl_device_inline int intersection_find_attribute(KernelGlobals kg, /* Cut-off value to stop transparent shadow tracing when practically opaque. */ #define CURVE_SHADOW_TRANSPARENCY_CUTOFF 0.001f -ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, - const int object, - const int prim, - const float u) +ccl_device_inline float intersection_curve_shadow_transparency( + KernelGlobals kg, const int object, const int prim, const int type, const float u) { /* Find attribute. */ const int offset = intersection_find_attribute(kg, object, ATTR_STD_SHADOW_TRANSPARENCY); @@ -204,7 +202,7 @@ ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, /* Interpolate transparency between curve keys. */ const KernelCurve kcurve = kernel_data_fetch(curves, prim); - const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(kcurve.type); + const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type); const int k1 = k0 + 1; const float f0 = kernel_data_fetch(attributes_float, offset + k0); diff --git a/intern/cycles/kernel/camera/projection.h b/intern/cycles/kernel/camera/projection.h index c9fe3a6c7fb..1d16aa35abe 100644 --- a/intern/cycles/kernel/camera/projection.h +++ b/intern/cycles/kernel/camera/projection.h @@ -201,11 +201,35 @@ ccl_device float2 direction_to_mirrorball(float3 dir) return make_float2(u, v); } +/* Single face of a equiangular cube map projection as described in + https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */ +ccl_device float3 equiangular_cubemap_face_to_direction(float u, float v) +{ + u = (1.0f - u); + + u = tanf(u * M_PI_2_F - M_PI_4_F); + v = tanf(v * M_PI_2_F - M_PI_4_F); + + return make_float3(1.0f, u, v); +} + +ccl_device float2 direction_to_equiangular_cubemap_face(float3 dir) +{ + float u = atan2f(dir.y, dir.x) * 2.0f / M_PI_F + 0.5f; + float v = atan2f(dir.z, dir.x) * 2.0f / M_PI_F + 0.5f; + + u = 1.0f - u; + + return make_float2(u, v); +} + ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v) { switch (cam->panorama_type) { case PANORAMA_EQUIRECTANGULAR: return equirectangular_range_to_direction(u, v, cam->equirectangular_range); + case PANORAMA_EQUIANGULAR_CUBEMAP_FACE: + return equiangular_cubemap_face_to_direction(u, v); case PANORAMA_MIRRORBALL: return mirrorball_to_direction(u, v); case PANORAMA_FISHEYE_EQUIDISTANT: @@ -230,6 +254,8 @@ ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, f switch (cam->panorama_type) { case PANORAMA_EQUIRECTANGULAR: return direction_to_equirectangular_range(dir, cam->equirectangular_range); + case PANORAMA_EQUIANGULAR_CUBEMAP_FACE: + return direction_to_equiangular_cubemap_face(dir); case PANORAMA_MIRRORBALL: return direction_to_mirrorball(dir); case PANORAMA_FISHEYE_EQUIDISTANT: diff --git a/intern/cycles/kernel/device/cpu/bvh.h b/intern/cycles/kernel/device/cpu/bvh.h index d9267e1cd6d..2d7d8c2d704 100644 --- a/intern/cycles/kernel/device/cpu/bvh.h +++ b/intern/cycles/kernel/device/cpu/bvh.h @@ -252,7 +252,7 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum /* Always use baked shadow transparency for curves. */ if (current_isect.type & PRIMITIVE_CURVE) { ctx->throughput *= intersection_curve_shadow_transparency( - kg, current_isect.object, current_isect.prim, current_isect.u); + kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u); if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) { ctx->opaque_hit = true; diff --git a/intern/cycles/kernel/device/gpu/parallel_active_index.h b/intern/cycles/kernel/device/gpu/parallel_active_index.h index c1df49c4f49..38cdcb572eb 100644 --- a/intern/cycles/kernel/device/gpu/parallel_active_index.h +++ b/intern/cycles/kernel/device/gpu/parallel_active_index.h @@ -23,22 +23,6 @@ CCL_NAMESPACE_BEGIN * and keep device specific code in compat.h */ #ifdef __KERNEL_ONEAPI__ -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED -template<typename IsActiveOp> -void cpu_serial_active_index_array_impl(const uint num_states, - ccl_global int *ccl_restrict indices, - ccl_global int *ccl_restrict num_indices, - IsActiveOp is_active_op) -{ - int write_index = 0; - for (int state_index = 0; state_index < num_states; state_index++) { - if (is_active_op(state_index)) - indices[write_index++] = state_index; - } - *num_indices = write_index; - return; -} -# endif /* WITH_ONEAPI_SYCL_HOST_ENABLED */ template<typename IsActiveOp> void gpu_parallel_active_index_array_impl(const uint num_states, @@ -182,18 +166,11 @@ __device__ num_simd_groups, \ simdgroup_offset) #elif defined(__KERNEL_ONEAPI__) -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED -# define gpu_parallel_active_index_array( \ - blocksize, num_states, indices, num_indices, is_active_op) \ - if (ccl_gpu_global_size_x() == 1) \ - cpu_serial_active_index_array_impl(num_states, indices, num_indices, is_active_op); \ - else \ - gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op); -# else -# define gpu_parallel_active_index_array( \ - blocksize, num_states, indices, num_indices, is_active_op) \ - gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op) -# endif + +# define gpu_parallel_active_index_array( \ + blocksize, num_states, indices, num_indices, is_active_op) \ + gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op) + #else # define gpu_parallel_active_index_array( \ diff --git a/intern/cycles/kernel/device/metal/context_begin.h b/intern/cycles/kernel/device/metal/context_begin.h index 99cb1e3826e..e75ec9cadec 100644 --- a/intern/cycles/kernel/device/metal/context_begin.h +++ b/intern/cycles/kernel/device/metal/context_begin.h @@ -34,21 +34,48 @@ class MetalKernelContext { kernel_assert(0); return 0; } - + +#ifdef __KERNEL_METAL_INTEL__ + template<typename TextureType, typename CoordsType> + inline __attribute__((__always_inline__)) + auto ccl_gpu_tex_object_read_intel_workaround(TextureType texture_array, + const uint tid, const uint sid, + CoordsType coords) const + { + switch(sid) { + default: + case 0: return texture_array[tid].tex.sample(sampler(address::repeat, filter::nearest), coords); + case 1: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::nearest), coords); + case 2: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::nearest), coords); + case 3: return texture_array[tid].tex.sample(sampler(address::repeat, filter::linear), coords); + case 4: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::linear), coords); + case 5: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::linear), coords); + } + } +#endif + // texture2d template<> inline __attribute__((__always_inline__)) float4 ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object_2D tex, float x, float y) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)); +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_2d, tid, sid, float2(x, y)); +#endif } template<> inline __attribute__((__always_inline__)) float ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object_2D tex, float x, float y) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)).x; +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_2d, tid, sid, float2(x, y)).x; +#endif } // texture3d @@ -57,14 +84,22 @@ class MetalKernelContext { float4 ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object_3D tex, float x, float y, float z) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)); +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_3d, tid, sid, float3(x, y, z)); +#endif } template<> inline __attribute__((__always_inline__)) float ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object_3D tex, float x, float y, float z) const { const uint tid(tex); const uint sid(tex >> 32); +#ifndef __KERNEL_METAL_INTEL__ return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)).x; +#else + return ccl_gpu_tex_object_read_intel_workaround(metal_ancillaries->textures_3d, tid, sid, float3(x, y, z)).x; +#endif } # include "kernel/device/gpu/image.h" diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal index 5646c7446db..8b69ee025cd 100644 --- a/intern/cycles/kernel/device/metal/kernel.metal +++ b/intern/cycles/kernel/device/metal/kernel.metal @@ -228,7 +228,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal, /* Always use baked shadow transparency for curves. */ if (type & PRIMITIVE_CURVE) { float throughput = payload.throughput; - throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u); + throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, type, u); payload.throughput = throughput; payload.num_hits += 1; diff --git a/intern/cycles/kernel/device/oneapi/compat.h b/intern/cycles/kernel/device/oneapi/compat.h index 8ae40b0612e..dfaec65130c 100644 --- a/intern/cycles/kernel/device/oneapi/compat.h +++ b/intern/cycles/kernel/device/oneapi/compat.h @@ -55,18 +55,6 @@ #define ccl_gpu_kernel(block_num_threads, thread_num_registers) #define ccl_gpu_kernel_threads(block_num_threads) -#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED -# define KG_ND_ITEMS \ - kg->nd_item_local_id_0 = item.get_local_id(0); \ - kg->nd_item_local_range_0 = item.get_local_range(0); \ - kg->nd_item_group_0 = item.get_group(0); \ - kg->nd_item_group_range_0 = item.get_group_range(0); \ - kg->nd_item_global_id_0 = item.get_global_id(0); \ - kg->nd_item_global_range_0 = item.get_global_range(0); -#else -# define KG_ND_ITEMS -#endif - #define ccl_gpu_kernel_signature(name, ...) \ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \ size_t kernel_global_size, \ @@ -76,8 +64,7 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \ (kg); \ cgh.parallel_for<class kernel_##name>( \ sycl::nd_range<1>(kernel_global_size, kernel_local_size), \ - [=](sycl::nd_item<1> item) { \ - KG_ND_ITEMS + [=](sycl::nd_item<1> item) { #define ccl_gpu_kernel_postfix \ }); \ @@ -95,31 +82,17 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \ } ccl_gpu_kernel_lambda_pass((ONEAPIKernelContext *)kg) /* GPU thread, block, grid size and index */ -#ifndef WITH_ONEAPI_SYCL_HOST_ENABLED -# define ccl_gpu_thread_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_id(0)) -# define ccl_gpu_block_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_range(0)) -# define ccl_gpu_block_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group(0)) -# define ccl_gpu_grid_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group_range(0)) -# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0]) -# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) - -# define ccl_gpu_global_id_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_id(0)) -# define ccl_gpu_global_size_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_range(0)) -#else -# define ccl_gpu_thread_idx_x (kg->nd_item_local_id_0) -# define ccl_gpu_block_dim_x (kg->nd_item_local_range_0) -# define ccl_gpu_block_idx_x (kg->nd_item_group_0) -# define ccl_gpu_grid_dim_x (kg->nd_item_group_range_0) -# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0]) -# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) - -# define ccl_gpu_global_id_x() (kg->nd_item_global_id_0) -# define ccl_gpu_global_size_x() (kg->nd_item_global_range_0) -#endif +#define ccl_gpu_thread_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_id(0)) +#define ccl_gpu_block_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_range(0)) +#define ccl_gpu_block_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group(0)) +#define ccl_gpu_grid_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group_range(0)) +#define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0]) +#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) +#define ccl_gpu_global_id_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_id(0)) +#define ccl_gpu_global_size_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_range(0)) /* GPU warp synchronization */ - #define ccl_gpu_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier() #define ccl_gpu_local_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier(sycl::access::fence_space::local_space) #ifdef __SYCL_DEVICE_ONLY__ diff --git a/intern/cycles/kernel/device/oneapi/globals.h b/intern/cycles/kernel/device/oneapi/globals.h index d60f4f135ba..116620eb725 100644 --- a/intern/cycles/kernel/device/oneapi/globals.h +++ b/intern/cycles/kernel/device/oneapi/globals.h @@ -23,15 +23,6 @@ typedef struct KernelGlobalsGPU { #undef KERNEL_DATA_ARRAY IntegratorStateGPU *integrator_state; const KernelData *__data; -#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED - size_t nd_item_local_id_0; - size_t nd_item_local_range_0; - size_t nd_item_group_0; - size_t nd_item_group_range_0; - - size_t nd_item_global_id_0; - size_t nd_item_global_range_0; -#endif } KernelGlobalsGPU; typedef ccl_global KernelGlobalsGPU *ccl_restrict KernelGlobals; diff --git a/intern/cycles/kernel/device/oneapi/kernel.cpp b/intern/cycles/kernel/device/oneapi/kernel.cpp index 40e0b1f0b2b..525ae288f0c 100644 --- a/intern/cycles/kernel/device/oneapi/kernel.cpp +++ b/intern/cycles/kernel/device/oneapi/kernel.cpp @@ -8,7 +8,7 @@ # include <map> # include <set> -# include <CL/sycl.hpp> +# include <sycl/sycl.hpp> # include "kernel/device/oneapi/compat.h" # include "kernel/device/oneapi/globals.h" @@ -144,6 +144,10 @@ size_t oneapi_kernel_preferred_local_size(SyclQueue *queue, bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features) { +# ifdef SYCL_SKIP_KERNELS_PRELOAD + (void)queue_; + (void)requested_features; +# else assert(queue_); sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_); @@ -175,7 +179,7 @@ bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features) sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle = sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id}); - sycl::build(one_kernel_bundle, {queue->get_device()}, sycl::property::queue::in_order()); + sycl::build(one_kernel_bundle); } } catch (sycl::exception const &e) { @@ -184,7 +188,7 @@ bool oneapi_load_kernels(SyclQueue *queue_, const uint requested_features) } return false; } - +# endif return true; } @@ -226,13 +230,6 @@ bool oneapi_enqueue_kernel(KernelContext *kernel_context, /* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices, * we extend work size to fit uniformity requirements. */ global_size = groups_count * local_size; - -# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED - if (queue->get_device().is_host()) { - global_size = 1; - local_size = 1; - } -# endif } /* Let the compiler throw an error if there are any kernels missing in this implementation. */ diff --git a/intern/cycles/kernel/device/optix/bvh.h b/intern/cycles/kernel/device/optix/bvh.h index fb9907709ce..6d81b44660c 100644 --- a/intern/cycles/kernel/device/optix/bvh.h +++ b/intern/cycles/kernel/device/optix/bvh.h @@ -202,7 +202,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit() /* Always use baked shadow transparency for curves. */ if (type & PRIMITIVE_CURVE) { float throughput = __uint_as_float(optixGetPayload_1()); - throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, u); + throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, type, u); optixSetPayload_1(__float_as_uint(throughput)); optixSetPayload_2(uint16_pack_to_uint(num_recorded_hits, num_hits + 1)); diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 8f7cfd19169..24c5a6a4540 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -490,6 +490,7 @@ enum PanoramaType { PANORAMA_FISHEYE_EQUISOLID = 2, PANORAMA_MIRRORBALL = 3, PANORAMA_FISHEYE_LENS_POLYNOMIAL = 4, + PANORAMA_EQUIANGULAR_CUBEMAP_FACE = 5, PANORAMA_NUM_TYPES, }; diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp index 240e5d9c128..255dd320ec7 100644 --- a/intern/cycles/scene/camera.cpp +++ b/intern/cycles/scene/camera.cpp @@ -84,6 +84,7 @@ NODE_DEFINE(Camera) static NodeEnum panorama_type_enum; panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR); + panorama_type_enum.insert("equiangular_cubemap_face", PANORAMA_EQUIANGULAR_CUBEMAP_FACE); panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL); panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT); panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID); diff --git a/intern/cycles/util/transform_inverse.h b/intern/cycles/util/transform_inverse.h index b72bbc5f680..bb410a6daef 100644 --- a/intern/cycles/util/transform_inverse.h +++ b/intern/cycles/util/transform_inverse.h @@ -11,7 +11,7 @@ CCL_NAMESPACE_BEGIN ccl_device_forceinline float3 transform_inverse_cross(const float3 a, const float3 b) { -#ifdef __AVX2__ +#if defined(__AVX2__) && defined(__KERNEL_SSE2__) const ssef sse_a = (const __m128 &)a; const ssef sse_b = (const __m128 &)b; const ssef r = shuffle<1, 2, 0, 3>( diff --git a/intern/cycles/util/types_float3.h b/intern/cycles/util/types_float3.h index 87c6b1d3654..34430945c38 100644 --- a/intern/cycles/util/types_float3.h +++ b/intern/cycles/util/types_float3.h @@ -10,7 +10,12 @@ CCL_NAMESPACE_BEGIN #ifndef __KERNEL_NATIVE_VECTOR_TYPES__ +# ifdef __KERNEL_ONEAPI__ +/* Define float3 as packed for oneAPI. */ +struct float3 +# else struct ccl_try_align(16) float3 +# endif { # ifdef __KERNEL_GPU__ /* Compact structure for GPU. */ diff --git a/intern/ffmpeg/tests/ffmpeg_codecs.cc b/intern/ffmpeg/tests/ffmpeg_codecs.cc index d0c40736884..e5c33202417 100644 --- a/intern/ffmpeg/tests/ffmpeg_codecs.cc +++ b/intern/ffmpeg/tests/ffmpeg_codecs.cc @@ -130,6 +130,7 @@ FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_DVVIDEO, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG1VIDEO, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG2VIDEO, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FLV1, AV_PIX_FMT_YUV420P) +FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_AV1, AV_PIX_FMT_YUV420P) /* Audio codecs */ @@ -149,6 +150,12 @@ FFMPEG_TEST_VCODEC_NAME(libx264, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_NAME(libvpx, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_NAME(libopenjpeg, AV_PIX_FMT_YUV420P) FFMPEG_TEST_VCODEC_NAME(libxvid, AV_PIX_FMT_YUV420P) +/* aom's AV1 encoder is "libaom-av1". FFMPEG_TEST_VCODEC_NAME(libaom-av1, ...) + * will not work because the dash will not work with the test macro. */ +TEST(ffmpeg, libaom_av1_AV_PIX_FMT_YUV420P) +{ + EXPECT_TRUE(test_codec_video_by_name("libaom-av1", AV_PIX_FMT_YUV420P)); +} FFMPEG_TEST_ACODEC_NAME(libvorbis, AV_SAMPLE_FMT_FLTP) FFMPEG_TEST_ACODEC_NAME(libopus, AV_SAMPLE_FMT_FLT) FFMPEG_TEST_ACODEC_NAME(libmp3lame, AV_SAMPLE_FMT_FLTP) diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 2f8ea1f9065..ea21d831b0c 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -268,7 +268,7 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) if(WITH_GHOST_WAYLAND_DYNLOAD) list(APPEND INC_SYS - ../../intern/wayland_dynload/extern + ../wayland_dynload/extern ) list(APPEND LIB bf_intern_wayland_dynload @@ -372,14 +372,22 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND) generate_protocol_bindings( "${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" ) + # Pointer-gestures (multi-touch). + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" + ) # Tablet. generate_protocol_bindings( "${WAYLAND_PROTOCOLS_DIR}/unstable/tablet/tablet-unstable-v2.xml" ) - - add_definitions(-DWITH_GHOST_WAYLAND) + # Primary-selection. + generate_protocol_bindings( + "${WAYLAND_PROTOCOLS_DIR}/unstable/primary-selection/primary-selection-unstable-v1.xml" + ) unset(INC_DST) + + add_definitions(-DWITH_GHOST_WAYLAND) endif() if(WITH_INPUT_NDOF) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 7fda535a7ac..62984c762c1 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -162,7 +162,6 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle, * \param height: The height the window. * \param state: The state of the window when opened. * \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized. - * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL options. * \return A handle to the new window ( == NULL if creation failed). */ @@ -175,7 +174,6 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, uint32_t height, GHOST_TWindowState state, bool is_dialog, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings); /** diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 9fb94ed1525..edaeca1e159 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -118,9 +118,11 @@ class GHOST_ISystem { /** * Creates the one and only system. * \param verbose: report back-ends that were attempted no back-end could be loaded. + * \param background: loading the system for background rendering (no visible windows). * \return An indication of success. */ - static GHOST_TSuccess createSystem(bool verbose); + + static GHOST_TSuccess createSystem(bool verbose, bool background); static GHOST_TSuccess createSystemBackground(); /** @@ -232,7 +234,6 @@ class GHOST_ISystem { * \param width: The width the window. * \param height: The height the window. * \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 full-screen). * \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized. @@ -245,7 +246,6 @@ class GHOST_ISystem { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 2645ce448b0..db4eeff3122 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -60,10 +60,6 @@ typedef struct { int hot_spot[2]; } GHOST_CursorBitmapRef; -typedef struct { - int flags; -} GHOST_GLSettings; - typedef enum { GHOST_glStereoVisual = (1 << 0), GHOST_glDebugContext = (1 << 1), @@ -157,6 +153,9 @@ typedef enum { #ifdef WIN32 GHOST_kDrawingContextTypeD3D, #endif +#ifdef __APPLE__ + GHOST_kDrawingContextTypeMetal, +#endif } GHOST_TDrawingContextType; typedef enum { @@ -598,6 +597,11 @@ typedef struct { uint32_t frequency; } GHOST_DisplaySetting; +typedef struct { + int flags; + GHOST_TDrawingContextType context_type; +} GHOST_GLSettings; + typedef enum { /** Axis that cursor grab will wrap. */ GHOST_kDebugDefault = (1 << 1), diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 158e979cdf2..0c595b27148 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -24,7 +24,7 @@ GHOST_SystemHandle GHOST_CreateSystem(void) { - GHOST_ISystem::createSystem(true); + GHOST_ISystem::createSystem(true, false); GHOST_ISystem *system = GHOST_ISystem::getSystem(); return (GHOST_SystemHandle)system; @@ -161,7 +161,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, uint32_t height, GHOST_TWindowState state, bool is_dialog, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings) { GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; @@ -172,7 +171,6 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, width, height, state, - type, glSettings, false, is_dialog, diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h index 130b926f25c..d19fffffb43 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.h +++ b/intern/ghost/intern/GHOST_ContextCGL.h @@ -30,7 +30,8 @@ class GHOST_ContextCGL : public GHOST_Context { GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, - NSOpenGLView *openglView); + NSOpenGLView *openglView, + GHOST_TDrawingContextType type); /** * Destructor. diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index ff53ecdbbba..9dad337a5d6 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -46,8 +46,10 @@ int GHOST_ContextCGL::s_sharedCount = 0; GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, - NSOpenGLView *openGLView) + NSOpenGLView *openGLView, + GHOST_TDrawingContextType type) : GHOST_Context(stereoVisual), + m_useMetalForRendering(type == GHOST_kDrawingContextTypeMetal), m_metalView(metalView), m_metalLayer(metalLayer), m_metalCmdQueue(nil), diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index 93708983f37..d9f2df21ee0 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -140,7 +140,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext() /* End Inline GLEW. */ /* -------------------------------------------------------------------- */ #else - /* Important to initialize only glxew (_not_ GLEW), + /* Important to initialize only GLXEW (_not_ GLEW), * since this breaks w/ Mesa's `swrast`, see: T46431. */ glxewInit(); #endif /* USE_GLXEW_INIT_WORKAROUND */ diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h index ec1a0b34be6..64eff7f9aed 100644 --- a/intern/ghost/intern/GHOST_Debug.h +++ b/intern/ghost/intern/GHOST_Debug.h @@ -15,29 +15,41 @@ # endif #endif -#if defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG)) -# include <iostream> -# include <stdio.h> //for printf() -#endif // WITH_GHOST_DEBUG +#include <iostream> +#include <stdio.h> /* For `printf()`. */ #if defined(WITH_GHOST_DEBUG) # define GHOST_PRINT(x) \ { \ std::cout << x; \ } \ - (void)0 + ((void)0) # define GHOST_PRINTF(x, ...) \ { \ printf(x, __VA_ARGS__); \ } \ - (void)0 + ((void)0) #else -# define GHOST_PRINT(x) -# define GHOST_PRINTF(x, ...) +/* Expand even when `WITH_GHOST_DEBUG` is disabled to prevent expressions + * becoming invalid even when the option is disable. */ +# define GHOST_PRINT(x) \ + { \ + if (false) { \ + std::cout << x; \ + } \ + } \ + ((void)0) +# define GHOST_PRINTF(x, ...) \ + { \ + if (false) { \ + printf(x, __VA_ARGS__); \ + } \ + } \ + ((void)0) + #endif /* `!defined(WITH_GHOST_DEBUG)` */ #ifdef WITH_ASSERT_ABORT -# include <stdio.h> //for fprintf() # include <stdlib.h> //for abort() # define GHOST_ASSERT(x, info) \ { \ @@ -48,7 +60,7 @@ abort(); \ } \ } \ - (void)0 + ((void)0) /* Assert in non-release builds too. */ #elif defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG)) # define GHOST_ASSERT(x, info) \ @@ -59,7 +71,7 @@ GHOST_PRINT("\n"); \ } \ } \ - (void)0 + ((void)0) #else /* `defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))` */ # define GHOST_ASSERT(x, info) ((void)0) #endif /* `defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))` */ diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 8e2859ca1e1..696848ce623 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -34,7 +34,7 @@ const char *GHOST_ISystem::m_system_backend_id = nullptr; GHOST_TBacktraceFn GHOST_ISystem::m_backtrace_fn = nullptr; -GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) +GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose, [[maybe_unused]] bool background) { /* When GHOST fails to start, report the back-ends that were attempted. * A Verbose argument could be supported in printing isn't always desired. */ @@ -61,7 +61,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) if (has_wayland_libraries) { backends_attempted[backends_attempted_num++] = "WAYLAND"; try { - m_system = new GHOST_SystemWayland(); + m_system = new GHOST_SystemWayland(background); } catch (const std::runtime_error &) { delete m_system; @@ -99,7 +99,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose) if (has_wayland_libraries) { backends_attempted[backends_attempted_num++] = "WAYLAND"; try { - m_system = new GHOST_SystemWayland(); + m_system = new GHOST_SystemWayland(background); } catch (const std::runtime_error &) { delete m_system; @@ -160,7 +160,7 @@ GHOST_TSuccess GHOST_ISystem::createSystemBackground() if (!m_system) { #if !defined(WITH_HEADLESS) /* Try to create a off-screen render surface with the graphical systems. */ - success = createSystem(false); + success = createSystem(false, true); if (success) { return success; } diff --git a/intern/ghost/intern/GHOST_ImeWin32.h b/intern/ghost/intern/GHOST_ImeWin32.h index 85c8ed7b4bd..cb6d8a770cf 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.h +++ b/intern/ghost/intern/GHOST_ImeWin32.h @@ -266,7 +266,7 @@ class GHOST_ImeWin32 { * Parameters * * window_handle [in] (HWND) * Represents the window handle of the caller. - * * caret_rect [in] (const gfx::Rect&) + * * caret_rect [in] (`const gfx::Rect&`) * Represent the rectangle of the input caret. * This rectangle is used for controlling the positions of IME windows. * * complete [in] (bool) diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index f4c726c7450..5484da82a18 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -12,11 +12,14 @@ #include <climits> #include <cmath> -#include <cstdio> /* For error/info reporting. */ #include <cstring> /* For memory functions. */ -/* Printable version of each GHOST_TProgress value. */ -static const char *progress_string[] = { +/* -------------------------------------------------------------------- */ +/** \name NDOF Enum Strings + * \{ */ + +/* Printable values for #GHOST_TProgress enum (keep aligned). */ +static const char *ndof_progress_string[] = { "not started", "starting", "in progress", @@ -24,41 +27,30 @@ static const char *progress_string[] = { "finished", }; +/* Printable values for #NDOF_ButtonT enum (keep aligned) */ static const char *ndof_button_names[] = { - /* used internally, never sent */ - "NDOF_BUTTON_NONE", - /* these two are available from any 3Dconnexion device */ + /* Exclude `NDOF_BUTTON_NONE` (-1). */ "NDOF_BUTTON_MENU", "NDOF_BUTTON_FIT", - /* standard views */ "NDOF_BUTTON_TOP", "NDOF_BUTTON_BOTTOM", "NDOF_BUTTON_LEFT", "NDOF_BUTTON_RIGHT", "NDOF_BUTTON_FRONT", "NDOF_BUTTON_BACK", - /* more views */ "NDOF_BUTTON_ISO1", "NDOF_BUTTON_ISO2", - /* 90 degree rotations */ "NDOF_BUTTON_ROLL_CW", "NDOF_BUTTON_ROLL_CCW", "NDOF_BUTTON_SPIN_CW", "NDOF_BUTTON_SPIN_CCW", "NDOF_BUTTON_TILT_CW", "NDOF_BUTTON_TILT_CCW", - /* device control */ "NDOF_BUTTON_ROTATE", "NDOF_BUTTON_PANZOOM", "NDOF_BUTTON_DOMINANT", "NDOF_BUTTON_PLUS", "NDOF_BUTTON_MINUS", - /* keyboard emulation */ - "NDOF_BUTTON_ESC", - "NDOF_BUTTON_ALT", - "NDOF_BUTTON_SHIFT", - "NDOF_BUTTON_CTRL", - /* general-purpose buttons */ "NDOF_BUTTON_1", "NDOF_BUTTON_2", "NDOF_BUTTON_3", @@ -69,18 +61,47 @@ static const char *ndof_button_names[] = { "NDOF_BUTTON_8", "NDOF_BUTTON_9", "NDOF_BUTTON_10", - /* more general-purpose buttons */ "NDOF_BUTTON_A", "NDOF_BUTTON_B", "NDOF_BUTTON_C", - /* the end */ - "NDOF_BUTTON_LAST", + "NDOF_BUTTON_V1", + "NDOF_BUTTON_V2", + "NDOF_BUTTON_V3", + /* Keyboard emulation. */ + "NDOF_BUTTON_ESC", + "NDOF_BUTTON_ENTER", + "NDOF_BUTTON_DELETE", + "NDOF_BUTTON_TAB", + "NDOF_BUTTON_SPACE", + "NDOF_BUTTON_ALT", + "NDOF_BUTTON_SHIFT", + "NDOF_BUTTON_CTRL", }; +static const char *ndof_device_names[] = { + "UnknownDevice", + "SpaceNavigator", + "SpaceExplorer", + "SpacePilotPro", + "SpaceMousePro", + "SpaceMouseWireless", + "SpaceMouseProWireless", + "SpaceMouseEnterprise", + "SpacePilot", + "Spaceball5000", + "SpaceTraveler", +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Button Maps + * \{ */ + /* Shared by the latest 3Dconnexion hardware * SpacePilotPro uses all of these * smaller devices use only some, based on button mask. */ -static const NDOF_ButtonT Modern3Dx_HID_map[] = { +static const NDOF_ButtonT ndof_HID_map_Modern3Dx[] = { NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_BOTTOM, NDOF_BUTTON_BACK, NDOF_BUTTON_ROLL_CW, NDOF_BUTTON_ROLL_CCW, NDOF_BUTTON_ISO1, NDOF_BUTTON_ISO2, @@ -90,7 +111,7 @@ static const NDOF_ButtonT Modern3Dx_HID_map[] = { NDOF_BUTTON_SHIFT, NDOF_BUTTON_CTRL, NDOF_BUTTON_ROTATE, NDOF_BUTTON_PANZOOM, NDOF_BUTTON_DOMINANT, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS}; -static const NDOF_ButtonT SpaceExplorer_HID_map[] = { +static const NDOF_ButtonT ndof_HID_map_SpaceExplorer[] = { NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_TOP, @@ -108,9 +129,8 @@ static const NDOF_ButtonT SpaceExplorer_HID_map[] = { NDOF_BUTTON_ROTATE, }; -/* This is the older SpacePilot (sans Pro) - * thanks to polosson for info about this device. */ -static const NDOF_ButtonT SpacePilot_HID_map[] = { +/* This is the older SpacePilot (sans Pro). */ +static const NDOF_ButtonT ndof_HID_map_SpacePilot[] = { NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, NDOF_BUTTON_4, NDOF_BUTTON_5, NDOF_BUTTON_6, NDOF_BUTTON_TOP, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_ESC, NDOF_BUTTON_ALT, @@ -119,7 +139,7 @@ static const NDOF_ButtonT SpacePilot_HID_map[] = { NDOF_BUTTON_NONE /* the CONFIG button -- what does it do? */ }; -static const NDOF_ButtonT Generic_HID_map[] = { +static const NDOF_ButtonT ndof_HID_map_Generic[] = { NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, @@ -134,27 +154,70 @@ static const NDOF_ButtonT Generic_HID_map[] = { NDOF_BUTTON_C, }; -static const int genericButtonCount = ARRAY_SIZE(Generic_HID_map); +/* Values taken from: https://github.com/FreeSpacenav/spacenavd/wiki/Device-button-names */ +static const NDOF_ButtonT ndof_HID_map_SpaceMouseEnterprise[] = { + NDOF_BUTTON_1, /* (0) */ + NDOF_BUTTON_2, /* (1) */ + NDOF_BUTTON_3, /* (2) */ + NDOF_BUTTON_4, /* (3) */ + NDOF_BUTTON_5, /* (4) */ + NDOF_BUTTON_6, /* (5) */ + NDOF_BUTTON_7, /* (6) */ + NDOF_BUTTON_8, /* (7) */ + NDOF_BUTTON_9, /* (8) */ + NDOF_BUTTON_A, /* Labeled "10" (9). */ + NDOF_BUTTON_B, /* Labeled "11" (10). */ + NDOF_BUTTON_C, /* Labeled "12" (11). */ + NDOF_BUTTON_MENU, /* (12). */ + NDOF_BUTTON_FIT, /* (13). */ + NDOF_BUTTON_TOP, /* (14). */ + NDOF_BUTTON_RIGHT, /* (15). */ + NDOF_BUTTON_FRONT, /* (16). */ + NDOF_BUTTON_ROLL_CW, /* (17). */ + NDOF_BUTTON_ESC, /* (18). */ + NDOF_BUTTON_ALT, /* (19). */ + NDOF_BUTTON_SHIFT, /* (20). */ + NDOF_BUTTON_CTRL, /* (21). */ + NDOF_BUTTON_ROTATE, /* Labeled "Lock Rotate" (22). */ + NDOF_BUTTON_ENTER, /* Labeled "Enter" (23). */ + NDOF_BUTTON_DELETE, /* (24). */ + NDOF_BUTTON_TAB, /* (25). */ + NDOF_BUTTON_SPACE, /* (26). */ + NDOF_BUTTON_V1, /* Labeled "V1" (27). */ + NDOF_BUTTON_V2, /* Labeled "V2" (28). */ + NDOF_BUTTON_V3, /* Labeled "V3" (29). */ + NDOF_BUTTON_ISO1, /* Labeled "ISO1" (30). */ +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Manager Class + * \{ */ + +static const int genericButtonCount = ARRAY_SIZE(ndof_HID_map_Generic); GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys) - : m_system(sys), - m_deviceType(NDOF_UnknownDevice), /* Each platform has its own device detection code. */ - m_buttonCount(genericButtonCount), - m_buttonMask(0), - m_hidMap(Generic_HID_map), - m_buttons(0), - m_motionTime(0), - m_prevMotionTime(0), - m_motionState(GHOST_kNotStarted), - m_motionEventPending(false), - m_deadZone(0.0f) + : system_(sys), + device_type_(NDOF_UnknownDevice), /* Each platform has its own device detection code. */ + hid_map_button_num_(genericButtonCount), + hid_map_button_mask_(0), + hid_map_(ndof_HID_map_Generic), + button_depressed_(0), + motion_time_(0), + motion_time_prev_(0), + motion_state_(GHOST_kNotStarted), + motion_event_pending_(false), + motion_dead_zone_(0.0f) { /* To avoid the rare situation where one triple is updated and * the other is not, initialize them both here: */ - memset(m_translation, 0, sizeof(m_translation)); - memset(m_rotation, 0, sizeof(m_rotation)); + memset(translation_, 0, sizeof(translation_)); + memset(rotation_, 0, sizeof(rotation_)); } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name NDOF Device Setup * \{ */ @@ -166,16 +229,16 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id) { /* Call this function until it returns true * it's a good idea to stop calling it after that, as it will "forget" - * whichever device it already found */ + * whichever device it already found. */ /* Default to safe generic behavior for "unknown" devices * unidentified devices will emit motion events like normal * rogue buttons do nothing by default, but can be customized by the user. */ - m_deviceType = NDOF_UnknownDevice; - m_hidMap = Generic_HID_map; - m_buttonCount = genericButtonCount; - m_buttonMask = 0; + device_type_ = NDOF_UnknownDevice; + hid_map_ = ndof_HID_map_Generic; + hid_map_button_num_ = genericButtonCount; + hid_map_button_mask_ = 0; /* "mystery device" owners can help build a HID_map for their hardware * A few users have already contributed information about several older devices @@ -185,96 +248,102 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id) case 0x046D: /* Logitech (3Dconnexion was a subsidiary). */ switch (product_id) { /* -- current devices -- */ - case 0xC626: /* full-size SpaceNavigator */ - case 0xC628: /* the "for Notebooks" one */ - puts("ndof: using SpaceNavigator"); - m_deviceType = NDOF_SpaceNavigator; - m_buttonCount = 2; - m_hidMap = Modern3Dx_HID_map; + case 0xC626: /* Full-size SpaceNavigator. */ + case 0xC628: /* The "for Notebooks" one. */ + { + device_type_ = NDOF_SpaceNavigator; + hid_map_button_num_ = 2; + hid_map_ = ndof_HID_map_Modern3Dx; break; - case 0xC627: - puts("ndof: using SpaceExplorer"); - m_deviceType = NDOF_SpaceExplorer; - m_buttonCount = 15; - m_hidMap = SpaceExplorer_HID_map; + } + case 0xC627: { + device_type_ = NDOF_SpaceExplorer; + hid_map_button_num_ = 15; + hid_map_ = ndof_HID_map_SpaceExplorer; break; - case 0xC629: - puts("ndof: using SpacePilot Pro"); - m_deviceType = NDOF_SpacePilotPro; - m_buttonCount = 31; - m_hidMap = Modern3Dx_HID_map; + } + case 0xC629: { + device_type_ = NDOF_SpacePilotPro; + hid_map_button_num_ = 31; + hid_map_ = ndof_HID_map_Modern3Dx; break; - case 0xC62B: - puts("ndof: using SpaceMouse Pro"); - m_deviceType = NDOF_SpaceMousePro; - m_buttonCount = 27; - /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26 */ - m_buttonMask = 0x07C0F137; - m_hidMap = Modern3Dx_HID_map; + } + case 0xC62B: { + device_type_ = NDOF_SpaceMousePro; + hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */ + hid_map_button_mask_ = 0x07C0F137; + hid_map_ = ndof_HID_map_Modern3Dx; break; + } /* -- older devices -- */ - case 0xC625: - puts("ndof: using SpacePilot"); - m_deviceType = NDOF_SpacePilot; - m_buttonCount = 21; - m_hidMap = SpacePilot_HID_map; + case 0xC625: { + device_type_ = NDOF_SpacePilot; + hid_map_button_num_ = 21; + hid_map_ = ndof_HID_map_SpacePilot; break; - case 0xC621: - puts("ndof: using Spaceball 5000"); - m_deviceType = NDOF_Spaceball5000; - m_buttonCount = 12; + } + case 0xC621: { + device_type_ = NDOF_Spaceball5000; + hid_map_button_num_ = 12; break; - case 0xC623: - puts("ndof: using SpaceTraveler"); - m_deviceType = NDOF_SpaceTraveler; - m_buttonCount = 8; + } + case 0xC623: { + device_type_ = NDOF_SpaceTraveler; + hid_map_button_num_ = 8; break; - - default: - printf("ndof: unknown Logitech product %04hx\n", product_id); + } + default: { + CLOG_INFO(LOG, 2, "unknown Logitech product %04hx", product_id); + } } break; - case 0x256F: /* 3Dconnexion */ + case 0x256F: /* 3Dconnexion. */ switch (product_id) { case 0xC62E: /* Plugged in. */ case 0xC62F: /* Wireless. */ - puts("ndof: using SpaceMouse Wireless"); - m_deviceType = NDOF_SpaceMouseWireless; - m_buttonCount = 2; - m_hidMap = Modern3Dx_HID_map; + case 0xC658: /* Wireless (3DConnexion Universal Wireless Receiver in WIN32), see T82412. */ + { + device_type_ = NDOF_SpaceMouseWireless; + hid_map_button_num_ = 2; + hid_map_ = ndof_HID_map_Modern3Dx; break; + } case 0xC631: /* Plugged in. */ case 0xC632: /* Wireless. */ - puts("ndof: using SpaceMouse Pro Wireless"); - m_deviceType = NDOF_SpaceMouseProWireless; - m_buttonCount = 27; - /* ^^ actually has 15 buttons, but their HID codes range from 0 to 26. */ - m_buttonMask = 0x07C0F137; - m_hidMap = Modern3Dx_HID_map; + { + device_type_ = NDOF_SpaceMouseProWireless; + hid_map_button_num_ = 27; /* 15 physical buttons, but HID codes range from 0 to 26. */ + hid_map_button_mask_ = 0x07C0F137; + hid_map_ = ndof_HID_map_Modern3Dx; break; - case 0xC633: - puts("ndof: using SpaceMouse Enterprise"); - m_deviceType = NDOF_SpaceMouseEnterprise; - m_buttonCount = 31; - m_hidMap = Modern3Dx_HID_map; + } + case 0xC633: { + device_type_ = NDOF_SpaceMouseEnterprise; + hid_map_button_num_ = 31; + hid_map_ = ndof_HID_map_SpaceMouseEnterprise; break; - - default: - printf("ndof: unknown 3Dconnexion product %04hx\n", product_id); + } + default: { + CLOG_INFO(LOG, 2, "unknown 3Dconnexion product %04hx", product_id); + } } break; default: - printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id); + CLOG_INFO(LOG, 2, "unknown device %04hx:%04hx", vendor_id, product_id); + } + + if (device_type_ != NDOF_UnknownDevice) { + CLOG_INFO(LOG, 2, "using %s", ndof_device_names[device_type_]); } - if (m_buttonMask == 0) { - m_buttonMask = int(~(UINT_MAX << m_buttonCount)); + if (hid_map_button_mask_ == 0) { + hid_map_button_mask_ = int(~(UINT_MAX << hid_map_button_num_)); } - CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", m_buttonCount, (uint)m_buttonMask); + CLOG_INFO(LOG, 2, "%d buttons -> hex:%X", hid_map_button_num_, (uint)hid_map_button_mask_); - return m_deviceType != NDOF_UnknownDevice; + return device_type_ != NDOF_UnknownDevice; } #undef LOG @@ -287,16 +356,16 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id) void GHOST_NDOFManager::updateTranslation(const int t[3], uint64_t time) { - memcpy(m_translation, t, sizeof(m_translation)); - m_motionTime = time; - m_motionEventPending = true; + memcpy(translation_, t, sizeof(translation_)); + motion_time_ = time; + motion_event_pending_ = true; } void GHOST_NDOFManager::updateRotation(const int r[3], uint64_t time) { - memcpy(m_rotation, r, sizeof(m_rotation)); - m_motionTime = time; - m_motionEventPending = true; + memcpy(rotation_, r, sizeof(rotation_)); + motion_time_ = time; + motion_event_pending_ = true; } /** \} */ @@ -314,6 +383,18 @@ static GHOST_TKey ghost_map_keyboard_from_ndof_buttom(const NDOF_ButtonT button) case NDOF_BUTTON_ESC: { return GHOST_kKeyEsc; } + case NDOF_BUTTON_ENTER: { + return GHOST_kKeyEnter; + } + case NDOF_BUTTON_DELETE: { + return GHOST_kKeyDelete; + } + case NDOF_BUTTON_TAB: { + return GHOST_kKeyTab; + } + case NDOF_BUTTON_SPACE: { + return GHOST_kKeySpace; + } case NDOF_BUTTON_ALT: { return GHOST_kKeyLeftAlt; } @@ -334,7 +415,7 @@ void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, uint64_t time, GHOST_IWindow *window) { - GHOST_ASSERT(button > NDOF_BUTTON_NONE && button < NDOF_BUTTON_LAST, + GHOST_ASSERT(button > NDOF_BUTTON_NONE && button < NDOF_BUTTON_NUM, "rogue button trying to escape NDOF manager"); GHOST_EventNDOFButton *event = new GHOST_EventNDOFButton(time, window); @@ -343,7 +424,7 @@ void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, data->action = press ? GHOST_kPress : GHOST_kRelease; data->button = button; - m_system.pushEvent(event); + system_.pushEvent(event); } void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key, @@ -354,21 +435,21 @@ void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key, GHOST_TEventType type = press ? GHOST_kEventKeyDown : GHOST_kEventKeyUp; GHOST_EventKey *event = new GHOST_EventKey(time, type, window, key, false); - m_system.pushEvent(event); + system_.pushEvent(event); } void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t time) { - if (button_number >= m_buttonCount) { + if (button_number >= hid_map_button_num_) { CLOG_INFO(LOG, 2, "button=%d, press=%d (out of range %d, ignoring!)", button_number, (int)press, - m_buttonCount); + hid_map_button_num_); return; } - const NDOF_ButtonT button = m_hidMap[button_number]; + const NDOF_ButtonT button = hid_map_[button_number]; if (button == NDOF_BUTTON_NONE) { CLOG_INFO( LOG, 2, "button=%d, press=%d (mapped to none, ignoring!)", button_number, (int)press); @@ -382,7 +463,7 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim (int)press, ndof_button_names[button]); - GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow(); + GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow(); const GHOST_TKey key = ghost_map_keyboard_from_ndof_buttom(button); if (key != GHOST_kKeyUnknown) { sendKeyEvent(key, press, time, window); @@ -393,20 +474,20 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim int mask = 1 << button_number; if (press) { - m_buttons |= mask; /* Set this button's bit. */ + button_depressed_ |= mask; /* Set this button's bit. */ } else { - m_buttons &= ~mask; /* Clear this button's bit. */ + button_depressed_ &= ~mask; /* Clear this button's bit. */ } } void GHOST_NDOFManager::updateButtons(int button_bits, uint64_t time) { - button_bits &= m_buttonMask; /* Discard any "garbage" bits. */ + button_bits &= hid_map_button_mask_; /* Discard any "garbage" bits. */ - int diff = m_buttons ^ button_bits; + int diff = button_depressed_ ^ button_bits; - for (int button_number = 0; button_number < m_buttonCount; ++button_number) { + for (int button_number = 0; button_number < hid_map_button_num_; ++button_number) { int mask = 1 << button_number; if (diff & mask) { @@ -433,7 +514,7 @@ void GHOST_NDOFManager::setDeadZone(float dz) /* Negative values don't make sense, so clamp at zero. */ dz = 0.0f; } - m_deadZone = dz; + motion_dead_zone_ = dz; /* Warn the rogue user/developer about high dead-zone, but allow it. */ CLOG_INFO(LOG, 2, "dead zone set to %.2f%s", dz, (dz > 0.5f) ? " (unexpectedly high)" : ""); @@ -458,20 +539,20 @@ static bool nearHomePosition(GHOST_TEventNDOFMotionData *ndof, float threshold) bool GHOST_NDOFManager::sendMotionEvent() { - if (!m_motionEventPending) { + if (!motion_event_pending_) { return false; } - m_motionEventPending = false; /* Any pending motion is handled right now. */ + motion_event_pending_ = false; /* Any pending motion is handled right now. */ - GHOST_IWindow *window = m_system.getWindowManager()->getActiveWindow(); + GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow(); if (window == nullptr) { - m_motionState = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */ + motion_state_ = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */ return false; /* Delivery will fail, so don't bother sending. */ } - GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(m_motionTime, window); + GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(motion_time_, window); GHOST_TEventNDOFMotionData *data = (GHOST_TEventNDOFMotionData *)event->getData(); /* Scale axis values here to normalize them to around +/- 1 @@ -479,26 +560,26 @@ bool GHOST_NDOFManager::sendMotionEvent() const float scale = 1.0f / 350.0f; /* 3Dconnexion devices send +/- 350 usually */ - data->tx = scale * m_translation[0]; - data->ty = scale * m_translation[1]; - data->tz = scale * m_translation[2]; + data->tx = scale * translation_[0]; + data->ty = scale * translation_[1]; + data->tz = scale * translation_[2]; - data->rx = scale * m_rotation[0]; - data->ry = scale * m_rotation[1]; - data->rz = scale * m_rotation[2]; - data->dt = 0.001f * (m_motionTime - m_prevMotionTime); /* In seconds. */ - m_prevMotionTime = m_motionTime; + data->rx = scale * rotation_[0]; + data->ry = scale * rotation_[1]; + data->rz = scale * rotation_[2]; + data->dt = 0.001f * (motion_time_ - motion_time_prev_); /* In seconds. */ + motion_time_prev_ = motion_time_; - bool weHaveMotion = !nearHomePosition(data, m_deadZone); + bool weHaveMotion = !nearHomePosition(data, motion_dead_zone_); /* Determine what kind of motion event to send `(Starting, InProgress, Finishing)` * and where that leaves this NDOF manager `(NotStarted, InProgress, Finished)`. */ - switch (m_motionState) { + switch (motion_state_) { case GHOST_kNotStarted: case GHOST_kFinished: { if (weHaveMotion) { data->progress = GHOST_kStarting; - m_motionState = GHOST_kInProgress; + motion_state_ = GHOST_kInProgress; /* Previous motion time will be ancient, so just make up a reasonable time delta. */ data->dt = 0.0125f; } @@ -517,7 +598,7 @@ bool GHOST_NDOFManager::sendMotionEvent() } else { data->progress = GHOST_kFinishing; - m_motionState = GHOST_kFinished; + motion_state_ = GHOST_kFinished; } break; } @@ -538,21 +619,21 @@ bool GHOST_NDOFManager::sendMotionEvent() data->ry, data->rz, data->dt, - progress_string[data->progress]); + ndof_progress_string[data->progress]); #else /* Raw values, may be useful for debugging. */ CLOG_INFO(LOG, 2, "motion sent, T=(%d,%d,%d) R=(%d,%d,%d) status=%s", - m_translation[0], - m_translation[1], - m_translation[2], - m_rotation[0], - m_rotation[1], - m_rotation[2], - progress_string[data->progress]); + translation_[0], + translation_[1], + translation_[2], + rotation_[0], + rotation_[1], + rotation_[2], + ndof_progress_string[data->progress]); #endif - m_system.pushEvent(event); + system_.pushEvent(event); return true; } diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index 73c1b17f891..2d5bba14aa4 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -9,7 +9,7 @@ #include "GHOST_System.h" typedef enum { - NDOF_UnknownDevice, + NDOF_UnknownDevice = 0, /* Current devices. */ NDOF_SpaceNavigator, @@ -29,8 +29,8 @@ typedef enum { /* NDOF device button event types */ typedef enum { - /* Used internally, never sent. */ - NDOF_BUTTON_NONE = 0, + /* Used internally, never sent or used as an index. */ + NDOF_BUTTON_NONE = -1, /* These two are available from any 3Dconnexion device. */ NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, @@ -58,11 +58,6 @@ typedef enum { NDOF_BUTTON_DOMINANT, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS, - /* Keyboard emulation. */ - NDOF_BUTTON_ESC, - NDOF_BUTTON_ALT, - NDOF_BUTTON_SHIFT, - NDOF_BUTTON_CTRL, /* General-purpose buttons. * Users can assign functions via keymap editor. */ NDOF_BUTTON_1, @@ -79,8 +74,20 @@ typedef enum { NDOF_BUTTON_A, NDOF_BUTTON_B, NDOF_BUTTON_C, - /* The end. */ - NDOF_BUTTON_LAST + /* Store Views. */ + NDOF_BUTTON_V1, + NDOF_BUTTON_V2, + NDOF_BUTTON_V3, + /* Keyboard emulation. */ + NDOF_BUTTON_ESC, + NDOF_BUTTON_ENTER, + NDOF_BUTTON_DELETE, + NDOF_BUTTON_TAB, + NDOF_BUTTON_SPACE, + NDOF_BUTTON_ALT, + NDOF_BUTTON_SHIFT, + NDOF_BUTTON_CTRL, +#define NDOF_BUTTON_NUM (NDOF_BUTTON_CTRL + 1) } NDOF_ButtonT; class GHOST_NDOFManager { @@ -140,25 +147,25 @@ class GHOST_NDOFManager { bool sendMotionEvent(); protected: - GHOST_System &m_system; + GHOST_System &system_; private: void sendButtonEvent(NDOF_ButtonT, bool press, uint64_t time, GHOST_IWindow *); void sendKeyEvent(GHOST_TKey, bool press, uint64_t time, GHOST_IWindow *); - NDOF_DeviceT m_deviceType; - int m_buttonCount; - int m_buttonMask; - const NDOF_ButtonT *m_hidMap; + NDOF_DeviceT device_type_; + int hid_map_button_num_; + int hid_map_button_mask_; + const NDOF_ButtonT *hid_map_; - int m_translation[3]; - int m_rotation[3]; - int m_buttons; /* Bit field. */ + int translation_[3]; + int rotation_[3]; + int button_depressed_; /* Bit field. */ - uint64_t m_motionTime; /* In milliseconds. */ - uint64_t m_prevMotionTime; /* Time of most recent motion event sent. */ + uint64_t motion_time_; /* In milliseconds. */ + uint64_t motion_time_prev_; /* Time of most recent motion event sent. */ - GHOST_TProgress m_motionState; - bool m_motionEventPending; - float m_deadZone; /* Discard motion with each component < this. */ + GHOST_TProgress motion_state_; + bool motion_event_pending_; + float motion_dead_zone_; /* Discard motion with each component < this. */ }; diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp index 94bf0337371..0ccf4dc9bfb 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp +++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp @@ -10,7 +10,7 @@ #define SPNAV_SOCK_PATH "/var/run/spnav.sock" GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys) - : GHOST_NDOFManager(sys), m_available(false) + : GHOST_NDOFManager(sys), available_(false) { if (access(SPNAV_SOCK_PATH, F_OK) != 0) { #ifdef DEBUG @@ -20,7 +20,7 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys) #endif } else if (spnav_open() != -1) { - m_available = true; + available_ = true; /* determine exactly which device (if any) is plugged in */ @@ -45,14 +45,14 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys) GHOST_NDOFManagerUnix::~GHOST_NDOFManagerUnix() { - if (m_available) { + if (available_) { spnav_close(); } } bool GHOST_NDOFManagerUnix::available() { - return m_available; + return available_; } /* @@ -74,7 +74,7 @@ bool GHOST_NDOFManagerUnix::processEvents() { bool anyProcessed = false; - if (m_available) { + if (available_) { spnav_event e; #ifdef USE_FINISH_GLITCH_WORKAROUND @@ -85,7 +85,7 @@ bool GHOST_NDOFManagerUnix::processEvents() switch (e.type) { case SPNAV_EVENT_MOTION: { /* convert to blender view coords */ - uint64_t now = m_system.getMilliSeconds(); + uint64_t now = system_.getMilliSeconds(); const int t[3] = {int(e.motion.x), int(e.motion.y), int(-e.motion.z)}; const int r[3] = {int(-e.motion.rx), int(-e.motion.ry), int(e.motion.rz)}; @@ -97,7 +97,7 @@ bool GHOST_NDOFManagerUnix::processEvents() break; } case SPNAV_EVENT_BUTTON: - uint64_t now = m_system.getMilliSeconds(); + uint64_t now = system_.getMilliSeconds(); updateButton(e.button.bnum, e.button.press, now); break; } @@ -106,7 +106,7 @@ bool GHOST_NDOFManagerUnix::processEvents() #ifdef USE_FINISH_GLITCH_WORKAROUND if (motion_test_prev == true && motion_test == false) { - uint64_t now = m_system.getMilliSeconds(); + uint64_t now = system_.getMilliSeconds(); const int v[3] = {0, 0, 0}; updateTranslation(v, now); diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.h b/intern/ghost/intern/GHOST_NDOFManagerUnix.h index fd603e3cb54..2b98fad974f 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerUnix.h +++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.h @@ -15,5 +15,5 @@ class GHOST_NDOFManagerUnix : public GHOST_NDOFManager { bool processEvents(); private: - bool m_available; + bool available_; }; diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 94d021fd822..670ede35989 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -384,6 +384,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, if (stereoVisual) { glSettings.flags |= GHOST_glStereoVisual; } + glSettings.context_type = GHOST_kDrawingContextTypeOpenGL; /* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may * be zoomed in and the desktop may be bigger than the viewport. */ GHOST_ASSERT(m_displayManager, @@ -395,7 +396,6 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, settings.xPixels, settings.yPixels, GHOST_kWindowStateNormal, - GHOST_kDrawingContextTypeOpenGL, glSettings, true /* exclusive */); return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index 810f828a8a1..924a4bff790 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -76,7 +76,7 @@ class GHOST_System : public GHOST_ISystem { GHOST_ITimerTask *installTimer(uint64_t delay, uint64_t interval, GHOST_TimerProcPtr timerProc, - GHOST_TUserDataPtr userData = NULL); + GHOST_TUserDataPtr userData = nullptr); /** * Removes a timer. diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index dbb41c7fddf..0211694aad4 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -77,7 +77,6 @@ class GHOST_SystemCocoa : public GHOST_System { * \param width: The width the window. * \param height: The height the window. * \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 full-screen). * \param parentWindow: Parent (embedder) window. @@ -89,7 +88,6 @@ class GHOST_SystemCocoa : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index bfa90114e4c..a1016dd4843 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -689,7 +689,6 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -719,7 +718,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, width, height, state, - type, + glSettings.context_type, glSettings.flags & GHOST_glStereoVisual, glSettings.flags & GHOST_glDebugContext, is_dialog, @@ -751,7 +750,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title, */ GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSettings) { - GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL); + GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, glSettings.context_type); if (context->initializeDrawingContext()) return context; else diff --git a/intern/ghost/intern/GHOST_SystemHeadless.h b/intern/ghost/intern/GHOST_SystemHeadless.h index b02a82fc9eb..66af65f763d 100644 --- a/intern/ghost/intern/GHOST_SystemHeadless.h +++ b/intern/ghost/intern/GHOST_SystemHeadless.h @@ -142,7 +142,6 @@ class GHOST_SystemHeadless : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool /*exclusive*/, const bool /*is_dialog*/, @@ -155,7 +154,7 @@ class GHOST_SystemHeadless : public GHOST_System { height, state, parentWindow, - type, + glSettings.context_type, ((glSettings.flags & GHOST_glStereoVisual) != 0)); } diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index ad5c4dc85fb..9174664adc4 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -42,7 +42,6 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool /* is_dialog */, @@ -57,7 +56,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title, width, height, state, - type, + glSettings.context_type, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, parentWindow); diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h index bee277ba674..385bfb841e3 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.h +++ b/intern/ghost/intern/GHOST_SystemSDL.h @@ -71,7 +71,6 @@ class GHOST_SystemSDL : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 04c7e103bde..67270d26ed3 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -10,6 +10,7 @@ #include "GHOST_EventCursor.h" #include "GHOST_EventDragnDrop.h" #include "GHOST_EventKey.h" +#include "GHOST_EventTrackpad.h" #include "GHOST_EventWheel.h" #include "GHOST_PathUtils.h" #include "GHOST_TimerManager.h" @@ -50,6 +51,8 @@ /* Generated by `wayland-scanner`. */ #include <pointer-constraints-unstable-v1-client-protocol.h> +#include <pointer-gestures-unstable-v1-client-protocol.h> +#include <primary-selection-unstable-v1-client-protocol.h> #include <relative-pointer-unstable-v1-client-protocol.h> #include <tablet-unstable-v2-client-protocol.h> #include <xdg-output-unstable-v1-client-protocol.h> @@ -82,10 +85,23 @@ static void keyboard_handle_key_repeat_cancel(struct GWL_Seat *seat); static void output_handle_done(void *data, struct wl_output *wl_output); +static void gwl_seat_capability_pointer_disable(GWL_Seat *seat); +static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat); +static void gwl_seat_capability_touch_disable(GWL_Seat *seat); + +static bool gwl_registry_entry_remove_by_name(GWL_Display *display, + uint32_t name, + int *r_interface_slot); +static void gwl_registry_entry_remove_all(GWL_Display *display); + +struct GWL_RegistryHandler; +static int gwl_registry_handler_interface_slot_max(); +static int gwl_registry_handler_interface_slot_from_string(const char *interface); +static const struct GWL_RegistryHandler *gwl_registry_handler_from_interface_slot( + int interface_slot); + /* -------------------------------------------------------------------- */ -/** \name Local Defines - * - * Control local functionality, compositors specific workarounds. +/** \name Workaround Compositor Specific Bugs * \{ */ /** @@ -116,11 +132,20 @@ static bool use_gnome_confine_hack = false; * This define could be removed without changing any functionality, * it just means GNOME users will see verbose warning messages that alert them about * a known problem that needs to be fixed up-stream. + * + * This has been fixed for GNOME 43. Keep the workaround until support for gnome 42 is dropped. * See: https://gitlab.gnome.org/GNOME/mutter/-/issues/2457 */ #define USE_GNOME_KEYBOARD_SUPPRESS_WARNING /** + * KDE (plasma 5.26.1) has a bug where the cursor surface needs to be committed + * (via `wl_surface_commit`) when it was hidden and is being set to visible again, see: T102048. + * See: https://bugs.kde.org/show_bug.cgi?id=461001 + */ +#define USE_KDE_TABLET_HIDDEN_CURSOR_HACK + +/** * When GNOME is found, require `libdecor`. * This is a hack because it seems there is no way to check if the compositor supports * server side decorations when initializing WAYLAND. @@ -129,6 +154,20 @@ static bool use_gnome_confine_hack = false; # define USE_GNOME_NEEDS_LIBDECOR_HACK #endif +/* -------------------------------------------------------------------- */ +/** \name Local Defines + * + * Control local functionality, compositors specific workarounds. + * \{ */ + +/** + * Fix short-cut part of keyboard reading code not properly handling some keys, see: T102194. + * \note This is similar to X11 workaround by the same name, see: T47228. + */ +#define USE_NON_LATIN_KB_WORKAROUND + +#define WL_NAME_UNSET uint32_t(-1) + /** \} */ /* -------------------------------------------------------------------- */ @@ -140,8 +179,7 @@ static bool use_gnome_confine_hack = false; * \{ */ /** - * The event codes are used to - * to differentiate from which mouse button an event comes from. + * The event codes are used to differentiate from which mouse button an event comes from. */ #define BTN_LEFT 0x110 #define BTN_RIGHT 0x111 @@ -154,9 +192,14 @@ static bool use_gnome_confine_hack = false; /** * Tablet events. + * + * \note Gnome/GTK swap middle/right, where the same application in X11 will swap the middle/right + * mouse button when running under WAYLAND. KDE doesn't do this, and according to artists + * at the Blender studio, having the button closest to the nib be MMB is preferable, + * so use this as a default. If needs be - swapping these could be a preference. */ -#define BTN_STYLUS 0x14b /* Use as right-mouse. */ -#define BTN_STYLUS2 0x14c /* Use as middle-mouse. */ +#define BTN_STYLUS 0x14b /* Use as middle-mouse. */ +#define BTN_STYLUS2 0x14c /* Use as right-mouse. */ /* NOTE(@campbellbarton): Map to an additional button (not sure which hardware uses this). */ #define BTN_STYLUS3 0x149 @@ -165,6 +208,19 @@ static bool use_gnome_confine_hack = false; */ #define KEY_GRAVE 41 +#ifdef USE_NON_LATIN_KB_WORKAROUND +# define KEY_1 2 +# define KEY_2 3 +# define KEY_3 4 +# define KEY_4 5 +# define KEY_5 6 +# define KEY_6 7 +# define KEY_7 8 +# define KEY_8 9 +# define KEY_9 10 +# define KEY_0 11 +#endif + /** \} */ /* -------------------------------------------------------------------- */ @@ -190,48 +246,76 @@ struct GWL_ModifierInfo { }; static const GWL_ModifierInfo g_modifier_info_table[MOD_INDEX_NUM] = { - [MOD_INDEX_SHIFT] = - { - .display_name = "Shift", - .xkb_id = XKB_MOD_NAME_SHIFT, - .key_l = GHOST_kKeyLeftShift, - .key_r = GHOST_kKeyRightShift, - .mod_l = GHOST_kModifierKeyLeftShift, - .mod_r = GHOST_kModifierKeyRightShift, - }, - [MOD_INDEX_ALT] = - { - .display_name = "Alt", - .xkb_id = XKB_MOD_NAME_ALT, - .key_l = GHOST_kKeyLeftAlt, - .key_r = GHOST_kKeyRightAlt, - .mod_l = GHOST_kModifierKeyLeftAlt, - .mod_r = GHOST_kModifierKeyRightAlt, - }, - [MOD_INDEX_CTRL] = - { - .display_name = "Control", - .xkb_id = XKB_MOD_NAME_CTRL, - .key_l = GHOST_kKeyLeftControl, - .key_r = GHOST_kKeyRightControl, - .mod_l = GHOST_kModifierKeyLeftControl, - .mod_r = GHOST_kModifierKeyRightControl, - }, - [MOD_INDEX_OS] = - { - .display_name = "OS", - .xkb_id = XKB_MOD_NAME_LOGO, - .key_l = GHOST_kKeyLeftOS, - .key_r = GHOST_kKeyRightOS, - .mod_l = GHOST_kModifierKeyLeftOS, - .mod_r = GHOST_kModifierKeyRightOS, - }, + /* MOD_INDEX_SHIFT */ + { + /* display_name */ "Shift", + /* xkb_id */ XKB_MOD_NAME_SHIFT, + /* key_l */ GHOST_kKeyLeftShift, + /* key_r */ GHOST_kKeyRightShift, + /* mod_l */ GHOST_kModifierKeyLeftShift, + /* mod_r */ GHOST_kModifierKeyRightShift, + }, + /* MOD_INDEX_ALT */ + { + /* display_name */ "Alt", + /* xkb_id */ XKB_MOD_NAME_ALT, + /* key_l */ GHOST_kKeyLeftAlt, + /* key_r */ GHOST_kKeyRightAlt, + /* mod_l */ GHOST_kModifierKeyLeftAlt, + /* mod_r */ GHOST_kModifierKeyRightAlt, + }, + /* MOD_INDEX_CTRL */ + { + /* display_name */ "Control", + /* xkb_id */ XKB_MOD_NAME_CTRL, + /* key_l */ GHOST_kKeyLeftControl, + /* key_r */ GHOST_kKeyRightControl, + /* mod_l */ GHOST_kModifierKeyLeftControl, + /* mod_r */ GHOST_kModifierKeyRightControl, + }, + /* MOD_INDEX_OS */ + { + /* display_name */ "OS", + /* xkb_id */ XKB_MOD_NAME_LOGO, + /* key_l */ GHOST_kKeyLeftOS, + /* key_r */ GHOST_kKeyRightOS, + /* mod_l */ GHOST_kModifierKeyLeftOS, + /* mod_r */ GHOST_kModifierKeyRightOS, + }, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_SimpleBuffer Type + * \{ */ + +struct GWL_SimpleBuffer { + /** Constant data, but may be freed. */ + const char *data = nullptr; + size_t data_size = 0; }; +static void gwl_simple_buffer_free_data(GWL_SimpleBuffer *buffer) +{ + free(const_cast<char *>(buffer->data)); + buffer->data = nullptr; + buffer->data_size = 0; +} + +static void gwl_simple_buffer_set_from_string(GWL_SimpleBuffer *buffer, const char *str) +{ + free(const_cast<char *>(buffer->data)); + buffer->data_size = strlen(str); + char *data = static_cast<char *>(malloc(buffer->data_size)); + std::memcpy(data, str, buffer->data_size); + buffer->data = data; +} + /** \} */ /* -------------------------------------------------------------------- */ -/** \name Private Types & Defines +/** \name Internal #GWL_Cursor Type * \{ */ /** @@ -249,16 +333,26 @@ struct GWL_Cursor { * the hardware cursor is used. */ bool is_hardware = true; + /** When true, a custom image is used to display the cursor (stored in `wl_image`). */ bool is_custom = false; - struct wl_surface *wl_surface = nullptr; + struct wl_surface *wl_surface_cursor = nullptr; struct wl_buffer *wl_buffer = nullptr; struct wl_cursor_image wl_image = {0}; struct wl_cursor_theme *wl_theme = nullptr; void *custom_data = nullptr; + /** The size of `custom_data` in bytes. */ size_t custom_data_size = 0; - int size = 0; + /** + * The name of the theme (loaded by DBUS, depends on #WITH_GHOST_WAYLAND_DBUS). + * When disabled, leave as an empty string and the default theme will be used. + */ std::string theme_name; - + /** + * The size of the cursor (when looking up a cursor theme). + * This must be scaled by the maximum output scale when passing to wl_cursor_theme_load. + * See #update_cursor_scale. + * */ + int theme_size = 0; int custom_scale = 1; }; @@ -269,6 +363,7 @@ struct GWL_Cursor { */ struct GWL_TabletTool { struct GWL_Seat *seat = nullptr; + /** Tablets have a separate cursor to the 'pointer', this surface is used for cursor drawing. */ struct wl_surface *wl_surface_cursor = nullptr; /** Used to delay clearing tablet focused wl_surface until the frame is handled. */ bool proximity = false; @@ -276,23 +371,55 @@ struct GWL_TabletTool { GHOST_TabletData data = GHOST_TABLET_DATA_NONE; }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_DataOffer Type + * \{ */ + +/** + * Data storage used for clipboard paste & drag-and-drop. + */ struct GWL_DataOffer { - std::unordered_set<std::string> types; - uint32_t source_actions = 0; - uint32_t dnd_action = 0; struct wl_data_offer *id = nullptr; - std::atomic<bool> in_use = false; + std::unordered_set<std::string> types; + struct { + /** + * Prevents freeing after #wl_data_device_listener.leave, + * before #wl_data_device_listener.drop. + */ + bool in_use = false; + /** + * Bit-mask with available drop options. + * #WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, #WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE.. etc. + * The application that initializes the drag may set these depending on modifiers held + * \note when dragging begins. Currently ghost doesn't make use of these. + */ + enum wl_data_device_manager_dnd_action source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + enum wl_data_device_manager_dnd_action action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; /** Compatible with #GWL_Seat.xy coordinates. */ wl_fixed_t xy[2] = {0, 0}; } dnd; }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_DataSource Type + * \{ */ + struct GWL_DataSource { - struct wl_data_source *data_source = nullptr; - char *buffer_out = nullptr; + struct wl_data_source *wl_source = nullptr; + GWL_SimpleBuffer buffer_out; }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_Seat Type (#wl_seat wrapper & associated types) + * \{ */ + /** * Data used to implement client-side key-repeat. * @@ -352,12 +479,58 @@ struct GWL_SeatStatePointer { * The wl_surface last used with this pointing device * (events with this pointing device will be sent here). */ - struct wl_surface *wl_surface = nullptr; + struct wl_surface *wl_surface_window = nullptr; GHOST_Buttons buttons = GHOST_Buttons(); }; /** + * Scroll state, applying to pointer (not tablet) events. + * Otherwise this would be part of #GWL_SeatStatePointer. + */ +struct GWL_SeatStatePointerScroll { + /** Smooth scrolling (handled & reset with pointer "frame" callback). */ + wl_fixed_t smooth_xy[2] = {0, 0}; + /** Discrete scrolling (handled & reset with pointer "frame" callback). */ + int32_t discrete_xy[2] = {0, 0}; + /** The source of scroll event. */ + enum wl_pointer_axis_source axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; +}; + +/** + * Utility struct to access rounded values from a scaled `wl_fixed_t`, + * without loosing information. + * + * As the rounded result is rounded to a lower precision integer, + * the high precision value is accumulated and converted to an integer to + * prevent the accumulation of rounded values giving an inaccurate result. + * + * \note This is simple but doesn't read well when expanded multiple times inline. + */ +struct GWL_ScaledFixedT { + wl_fixed_t value = 0; + wl_fixed_t factor = 1; +}; + +static int gwl_scaled_fixed_t_add_and_calc_rounded_delta(GWL_ScaledFixedT *sf, + const wl_fixed_t add) +{ + const int result_prev = wl_fixed_to_int(sf->value * sf->factor); + sf->value += add; + const int result_curr = wl_fixed_to_int(sf->value * sf->factor); + return result_curr - result_prev; +} + +/** + * Gesture state. + * This is needed so the gesture values can be converted to deltas. + */ +struct GWL_SeatStatePointerGesture_Pinch { + GWL_ScaledFixedT scale; + GWL_ScaledFixedT rotation; +}; + +/** * State of the keyboard (in #GWL_Seat). */ struct GWL_SeatStateKeyboard { @@ -368,7 +541,7 @@ struct GWL_SeatStateKeyboard { * The wl_surface last used with this pointing device * (events with this pointing device will be sent here). */ - struct wl_surface *wl_surface = nullptr; + struct wl_surface *wl_surface_window = nullptr; }; /** @@ -376,48 +549,110 @@ struct GWL_SeatStateKeyboard { * * Needed as #GWL_Seat.xkb_state doesn't store which modifier keys are held. */ -struct WGL_KeyboardDepressedState { +struct GWL_KeyboardDepressedState { int16_t mods[GHOST_KEY_MODIFIER_NUM] = {0}; }; #ifdef WITH_GHOST_WAYLAND_LIBDECOR -struct WGL_LibDecor_System { +struct GWL_LibDecor_System { struct libdecor *context = nullptr; }; -static void wgl_libdecor_system_destroy(WGL_LibDecor_System *decor) +static void gwl_libdecor_system_destroy(GWL_LibDecor_System *decor) { if (decor->context) { libdecor_unref(decor->context); + decor->context = nullptr; } delete decor; } #endif -struct WGL_XDG_Decor_System { +struct GWL_XDG_Decor_System { struct xdg_wm_base *shell = nullptr; + uint32_t shell_name = WL_NAME_UNSET; + struct zxdg_decoration_manager_v1 *manager = nullptr; + uint32_t manager_name = WL_NAME_UNSET; }; -static void wgl_xdg_decor_system_destroy(WGL_XDG_Decor_System *decor) +static void gwl_xdg_decor_system_destroy(struct GWL_Display *display, GWL_XDG_Decor_System *decor) { if (decor->manager) { - zxdg_decoration_manager_v1_destroy(decor->manager); + gwl_registry_entry_remove_by_name(display, decor->manager_name, nullptr); + GHOST_ASSERT(decor->manager == nullptr, "Internal registry error"); } if (decor->shell) { - xdg_wm_base_destroy(decor->shell); + gwl_registry_entry_remove_by_name(display, decor->shell_name, nullptr); + GHOST_ASSERT(decor->shell == nullptr, "Internal registry error"); } delete decor; } +struct GWL_PrimarySelection_DataOffer { + struct zwp_primary_selection_offer_v1 *id = nullptr; + + std::unordered_set<std::string> types; +}; + +struct GWL_PrimarySelection_DataSource { + struct zwp_primary_selection_source_v1 *wp_source = nullptr; + GWL_SimpleBuffer buffer_out; +}; + +/** Primary selection support. */ +struct GWL_PrimarySelection { + + GWL_PrimarySelection_DataSource *data_source = nullptr; + std::mutex data_source_mutex; + + GWL_PrimarySelection_DataOffer *data_offer = nullptr; + std::mutex data_offer_mutex; +}; + +static void gwl_primary_selection_discard_offer(GWL_PrimarySelection *primary) +{ + if (primary->data_offer == nullptr) { + return; + } + zwp_primary_selection_offer_v1_destroy(primary->data_offer->id); + delete primary->data_offer; + primary->data_offer = nullptr; +} + +static void gwl_primary_selection_discard_source(GWL_PrimarySelection *primary) +{ + GWL_PrimarySelection_DataSource *data_source = primary->data_source; + if (data_source == nullptr) { + return; + } + gwl_simple_buffer_free_data(&data_source->buffer_out); + if (data_source->wp_source) { + zwp_primary_selection_source_v1_destroy(data_source->wp_source); + } + delete primary->data_source; + primary->data_source = nullptr; +} + struct GWL_Seat { GHOST_SystemWayland *system = nullptr; std::string name; struct wl_seat *wl_seat = nullptr; struct wl_pointer *wl_pointer = nullptr; + struct wl_touch *wl_touch = nullptr; struct wl_keyboard *wl_keyboard = nullptr; - struct zwp_tablet_seat_v2 *tablet_seat = nullptr; + struct zwp_tablet_seat_v2 *wp_tablet_seat = nullptr; + +#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE + struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold = nullptr; +#endif +#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE + struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch = nullptr; +#endif +#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE + struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe = nullptr; +#endif /** All currently active tablet tools (needed for changing the cursor). */ std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools; @@ -426,6 +661,8 @@ struct GWL_Seat { uint32_t cursor_source_serial = 0; GWL_SeatStatePointer pointer; + GWL_SeatStatePointerScroll pointer_scroll; + GWL_SeatStatePointerGesture_Pinch pointer_gesture_pinch; /** Mostly this can be interchanged with `pointer` however it can't be locked/confined. */ GWL_SeatStatePointer tablet; @@ -440,9 +677,9 @@ struct GWL_Seat { struct GWL_Cursor cursor; - struct zwp_relative_pointer_v1 *relative_pointer = nullptr; - struct zwp_locked_pointer_v1 *locked_pointer = nullptr; - struct zwp_confined_pointer_v1 *confined_pointer = nullptr; + struct zwp_relative_pointer_v1 *wp_relative_pointer = nullptr; + struct zwp_locked_pointer_v1 *wp_locked_pointer = nullptr; + struct zwp_confined_pointer_v1 *wp_confined_pointer = nullptr; struct xkb_context *xkb_context = nullptr; @@ -451,14 +688,24 @@ struct GWL_Seat { * Keep a state with no modifiers active, use for symbol lookups. */ struct xkb_state *xkb_state_empty = nullptr; + + /** + * Keep a state with shift enabled, use to access predictable number access for AZERTY keymaps. + * If shift is not supported by the key-map, this is set to NULL. + */ + struct xkb_state *xkb_state_empty_with_shift = nullptr; /** * Keep a state with number-lock enabled, use to access predictable key-pad symbols. * If number-lock is not supported by the key-map, this is set to NULL. */ struct xkb_state *xkb_state_empty_with_numlock = nullptr; +#ifdef USE_NON_LATIN_KB_WORKAROUND + bool xkb_use_non_latin_workaround = false; +#endif + /** Keys held matching `xkb_state`. */ - struct WGL_KeyboardDepressedState key_depressed; + struct GWL_KeyboardDepressedState key_depressed; #ifdef USE_GNOME_KEYBOARD_SUPPRESS_WARNING struct { @@ -483,9 +730,9 @@ struct GWL_Seat { GHOST_ITimerTask *timer = nullptr; } key_repeat; - struct wl_surface *wl_surface_focus_dnd = nullptr; + struct wl_surface *wl_surface_window_focus_dnd = nullptr; - struct wl_data_device *data_device = nullptr; + struct wl_data_device *wl_data_device = nullptr; /** Drag & Drop. */ struct GWL_DataOffer *data_offer_dnd = nullptr; std::mutex data_offer_dnd_mutex; @@ -497,209 +744,434 @@ struct GWL_Seat { struct GWL_DataSource *data_source = nullptr; std::mutex data_source_mutex; + struct zwp_primary_selection_device_v1 *wp_primary_selection_device = nullptr; + struct GWL_PrimarySelection primary_selection; + /** Last device that was active. */ uint32_t data_source_serial = 0; }; +static GWL_SeatStatePointer *gwl_seat_state_pointer_active(GWL_Seat *seat) +{ + if (seat->pointer.serial == seat->cursor_source_serial) { + return &seat->pointer; + } + if (seat->tablet.serial == seat->cursor_source_serial) { + return &seat->tablet; + } + return nullptr; +} + +static GWL_SeatStatePointer *gwl_seat_state_pointer_from_cursor_surface( + GWL_Seat *seat, const wl_surface *wl_surface) +{ + if (ghost_wl_surface_own_cursor_pointer(wl_surface)) { + return &seat->pointer; + } + if (ghost_wl_surface_own_cursor_tablet(wl_surface)) { + return &seat->tablet; + } + GHOST_ASSERT(0, "Surface found without pointer/tablet tag"); + return nullptr; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_Display Type (#wl_display & #wl_compositor wrapper) + * \{ */ + +struct GWL_RegistryEntry; + struct GWL_Display { GHOST_SystemWayland *system = nullptr; + /** + * True when initializing registration, while updating all other entries wont cause problems, + * it will preform many redundant update calls. + */ + bool registry_skip_update_all = false; + + /** Registry entries, kept to allow updating & removal at run-time. */ + struct GWL_RegistryEntry *registry_entry = nullptr; + + struct wl_registry *wl_registry = nullptr; struct wl_display *wl_display = nullptr; struct wl_compositor *wl_compositor = nullptr; #ifdef WITH_GHOST_WAYLAND_LIBDECOR - WGL_LibDecor_System *libdecor = nullptr; + GWL_LibDecor_System *libdecor = nullptr; bool libdecor_required = false; #endif - WGL_XDG_Decor_System *xdg_decor = nullptr; + GWL_XDG_Decor_System *xdg_decor = nullptr; struct zxdg_output_manager_v1 *xdg_output_manager = nullptr; struct wl_shm *wl_shm = nullptr; std::vector<GWL_Output *> outputs; std::vector<GWL_Seat *> seats; + /** + * Support a single active seat at once, this isn't an exact or correct mapping from WAYLAND. + * Only allow input from different seats, not full concurrent multi-seat support. + * + * The main purpose of having an active seat is an alternative from always using the first + * seat which prevents events from any other seat. + * + * NOTE(@campbellbarton): This could be extended and developed further extended to support + * an active seat per window (for e.g.), basic support is sufficient for now as currently isn't + * a widely used feature. + */ + int seats_active_index = 0; - struct wl_data_device_manager *data_device_manager = nullptr; - struct zwp_tablet_manager_v2 *tablet_manager = nullptr; - struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr; - struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr; -}; - -#undef LOG - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Private Utility Functions - * \{ */ - -static GHOST_WindowManager *window_manager = nullptr; + /* Managers. */ + struct wl_data_device_manager *wl_data_device_manager = nullptr; + struct zwp_tablet_manager_v2 *wp_tablet_manager = nullptr; + struct zwp_relative_pointer_manager_v1 *wp_relative_pointer_manager = nullptr; + struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr; -/** Check this lock before accessing #GHOST_SystemWayland::clipboard_ from a thread. */ -static std::mutex system_clipboard_mutex; + struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr; + struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr; +}; /** - * Callback for WAYLAND to run when there is an error. + * Free the #GWL_Display and it's related members. * - * \note It's useful to set a break-point on this function as some errors are fatal - * (for all intents and purposes) but don't crash the process. + * \note This may run on a partially initialized struct, + * so it can't be assumed all members are set. */ -static void ghost_wayland_log_handler(const char *msg, va_list arg) +static void gwl_display_destroy(GWL_Display *display) { - fprintf(stderr, "GHOST/Wayland: "); - vfprintf(stderr, msg, arg); /* Includes newline. */ + /* For typical WAYLAND use this will always be set. + * However when WAYLAND isn't running, this will early-exit and be null. */ + if (display->wl_registry) { + wl_registry_destroy(display->wl_registry); + display->wl_registry = nullptr; + } - GHOST_TBacktraceFn backtrace_fn = GHOST_ISystem::getBacktraceFn(); - if (backtrace_fn) { - backtrace_fn(stderr); /* Includes newline. */ + /* Unregister items in reverse order. */ + gwl_registry_entry_remove_all(display); + +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (use_libdecor) { + if (display->libdecor) { + gwl_libdecor_system_destroy(display->libdecor); + display->libdecor = nullptr; + } + } + else +#endif + { + if (display->xdg_decor) { + gwl_xdg_decor_system_destroy(display, display->xdg_decor); + display->xdg_decor = nullptr; + } } -} -static GWL_SeatStatePointer *seat_state_pointer_active(GWL_Seat *seat) -{ - if (seat->pointer.serial == seat->cursor_source_serial) { - return &seat->pointer; + if (eglGetDisplay) { + ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(display->wl_display))); } - if (seat->tablet.serial == seat->cursor_source_serial) { - return &seat->tablet; + + if (display->wl_display) { + wl_display_disconnect(display->wl_display); } - return nullptr; + + delete display; } -static GWL_SeatStatePointer *seat_state_pointer_from_cursor_surface(GWL_Seat *seat, - const wl_surface *wl_surface) +static int gwl_display_seat_index(GWL_Display *display, const GWL_Seat *seat) { - if (ghost_wl_surface_own_cursor_pointer(wl_surface)) { - return &seat->pointer; - } - if (ghost_wl_surface_own_cursor_tablet(wl_surface)) { - return &seat->tablet; - } - GHOST_ASSERT(0, "Surface found without pointer/tablet tag"); - return nullptr; + std::vector<GWL_Seat *>::iterator iter = std::find( + display->seats.begin(), display->seats.end(), seat); + const int index = (iter != display->seats.cend()) ? std::distance(display->seats.begin(), iter) : + -1; + GHOST_ASSERT(index != -1, "invalid internal state"); + return index; } -static void display_destroy(GWL_Display *display) +static GWL_Seat *gwl_display_seat_active_get(const GWL_Display *display) { - if (display->data_device_manager) { - wl_data_device_manager_destroy(display->data_device_manager); + if (UNLIKELY(display->seats.empty())) { + return nullptr; } + return display->seats[display->seats_active_index]; +} - if (display->tablet_manager) { - zwp_tablet_manager_v2_destroy(display->tablet_manager); +static bool gwl_display_seat_active_set(GWL_Display *display, const GWL_Seat *seat) +{ + if (UNLIKELY(display->seats.empty())) { + return false; } - - for (GWL_Output *output : display->outputs) { - wl_output_destroy(output->wl_output); - delete output; + const int index = gwl_display_seat_index(display, seat); + if (index == display->seats_active_index) { + return false; } + display->seats_active_index = index; + return true; +} - for (GWL_Seat *seat : display->seats) { +/** \} */ - /* First handle members that require locking. - * While highly unlikely, it's possible they are being used while this function runs. */ - { - std::lock_guard lock{seat->data_source_mutex}; - if (seat->data_source) { - free(seat->data_source->buffer_out); - if (seat->data_source->data_source) { - wl_data_source_destroy(seat->data_source->data_source); - } - delete seat->data_source; - } - } +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_RegistryHandler + * \{ */ - { - std::lock_guard lock{seat->data_offer_dnd_mutex}; - if (seat->data_offer_dnd) { - wl_data_offer_destroy(seat->data_offer_dnd->id); - delete seat->data_offer_dnd; - } - } +struct GWL_RegisteryAdd_Params { + uint32_t name = 0; + /** Index within `gwl_registry_handlers`. */ + int interface_slot = 0; + uint32_t version = 0; +}; - { - std::lock_guard lock{seat->data_offer_copy_paste_mutex}; - if (seat->data_offer_copy_paste) { - wl_data_offer_destroy(seat->data_offer_copy_paste->id); - delete seat->data_offer_copy_paste; - } - } +/** + * Add callback for object registry. + * \note Any operations that depend on other interfaces being registered must be performed in the + * #GWL_RegistryHandler_UpdateFn callback as the order interfaces are added is out of our control. + * + * \param display: The display which holes a reference to the global object. + * \param params: Various arguments needed for registration. + */ +using GWL_RegistryHandler_AddFn = void (*)(GWL_Display *display, + const GWL_RegisteryAdd_Params *params); - if (seat->data_device) { - wl_data_device_release(seat->data_device); - } +struct GWL_RegisteryUpdate_Params { + uint32_t name = 0; + /** Index within `gwl_registry_handlers`. */ + int interface_slot = 0; + uint32_t version = 0; - if (seat->cursor.custom_data) { - munmap(seat->cursor.custom_data, seat->cursor.custom_data_size); - } + /** Set to #GWL_RegistryEntry.user_data. */ + void *user_data = nullptr; +}; - if (seat->wl_pointer) { - if (seat->cursor.wl_surface) { - wl_surface_destroy(seat->cursor.wl_surface); - } - if (seat->cursor.wl_theme) { - wl_cursor_theme_destroy(seat->cursor.wl_theme); - } - if (seat->wl_pointer) { - wl_pointer_destroy(seat->wl_pointer); - } - } - if (seat->wl_keyboard) { - if (seat->key_repeat.timer) { - keyboard_handle_key_repeat_cancel(seat); - } - wl_keyboard_destroy(seat->wl_keyboard); - } +/** + * Optional update callback to refresh internal data when another interface has been added/removed. + * + * \param display: The display which holes a reference to the global object. + * \param params: Various arguments needed for updating. + */ +using GWL_RegistryHandler_UpdateFn = void (*)(GWL_Display *display, + const GWL_RegisteryUpdate_Params *params); - /* Un-referencing checks for NULL case. */ - xkb_state_unref(seat->xkb_state); - xkb_state_unref(seat->xkb_state_empty); - xkb_state_unref(seat->xkb_state_empty_with_numlock); +/** + * Remove callback for object registry. + * \param display: The display which holes a reference to the global object. + * \param user_data: Optional reference to a sub element of `display`, + * use for outputs or seats for e.g. when the display may hold multiple references. + * \param on_exit: Enabled when freeing on exit. + * When true the consistency of references between objects should be kept valid. + * Otherwise it can be assumed that all objects will be freed and none will be used again, + * so there is no need to ensure a valid state. + */ +using GWL_RegistryEntry_RemoveFn = void (*)(GWL_Display *display, void *user_data, bool on_exit); + +struct GWL_RegistryHandler { + /** Pointer to the name (not the name it's self), needed as the values aren't set on startup. */ + const char *const *interface_p = nullptr; + + /** Add the interface. */ + GWL_RegistryHandler_AddFn add_fn = nullptr; + /** Optional update the interface (when other interfaces have been added/removed). */ + GWL_RegistryHandler_UpdateFn update_fn = nullptr; + /** Remove the interface. */ + GWL_RegistryEntry_RemoveFn remove_fn = nullptr; +}; - xkb_context_unref(seat->xkb_context); +/** \} */ - wl_seat_destroy(seat->wl_seat); - delete seat; - } +/* -------------------------------------------------------------------- */ +/** \name Internal #GWL_RegistryEntry + * \{ */ - if (display->wl_shm) { - wl_shm_destroy(display->wl_shm); - } +/** + * Registered global objects can be removed by the compositor, + * these entries are a registry of objects and callbacks to properly remove them. + * These are also used to remove all registered objects before exiting. + */ +struct GWL_RegistryEntry { + GWL_RegistryEntry *next = nullptr; + /** + * Optional pointer passed to `remove_fn`, typically the container in #GWL_Display + * in cases multiple instances of the same interface are supported. + */ + void *user_data = nullptr; + /** + * A unique identifier used as a handle by `wl_registry_listener.global_remove`. + */ + uint32_t name = WL_NAME_UNSET; + /** + * Version passed by the add callback. + */ + uint32_t version; + /** + * The index in `gwl_registry_handlers`, + * useful for accessing the interface name (for logging for example). + */ + int interface_slot = 0; +}; - if (display->relative_pointer_manager) { - zwp_relative_pointer_manager_v1_destroy(display->relative_pointer_manager); - } +static void gwl_registry_entry_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params, + void *user_data) +{ + GWL_RegistryEntry *reg = new GWL_RegistryEntry; - if (display->pointer_constraints) { - zwp_pointer_constraints_v1_destroy(display->pointer_constraints); - } + reg->interface_slot = params->interface_slot; + reg->name = params->name; + reg->version = params->version; + reg->user_data = user_data; + + reg->next = display->registry_entry; + display->registry_entry = reg; +} + +static bool gwl_registry_entry_remove_by_name(GWL_Display *display, + uint32_t name, + int *r_interface_slot) +{ + GWL_RegistryEntry *reg = display->registry_entry; + GWL_RegistryEntry **reg_link_p = &display->registry_entry; + bool found = false; - if (display->wl_compositor) { - wl_compositor_destroy(display->wl_compositor); + if (r_interface_slot) { + *r_interface_slot = -1; } -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor) { - if (display->libdecor) { - wgl_libdecor_system_destroy(display->libdecor); + while (reg) { + if (reg->name == name) { + GWL_RegistryEntry *reg_next = reg->next; + const GWL_RegistryHandler *handler = gwl_registry_handler_from_interface_slot( + reg->interface_slot); + handler->remove_fn(display, reg->user_data, false); + if (r_interface_slot) { + *r_interface_slot = reg->interface_slot; + } + delete reg; + *reg_link_p = reg_next; + found = true; + break; } - } - else -#endif - { - if (display->xdg_decor) { - wgl_xdg_decor_system_destroy(display->xdg_decor); + reg_link_p = ®->next; + reg = reg->next; + } + return found; +} + +static bool gwl_registry_entry_remove_by_interface_slot(GWL_Display *display, + int interface_slot, + bool on_exit) +{ + GWL_RegistryEntry *reg = display->registry_entry; + GWL_RegistryEntry **reg_link_p = &display->registry_entry; + bool found = false; + + while (reg) { + if (reg->interface_slot == interface_slot) { + GWL_RegistryEntry *reg_next = reg->next; + const GWL_RegistryHandler *handler = gwl_registry_handler_from_interface_slot( + interface_slot); + handler->remove_fn(display, reg->user_data, on_exit); + delete reg; + *reg_link_p = reg_next; + reg = reg_next; + found = true; + continue; } + reg_link_p = ®->next; + reg = reg->next; } + return found; +} - if (eglGetDisplay) { - ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(display->wl_display))); +/** + * Remove all global objects (on exit). + */ +static void gwl_registry_entry_remove_all(GWL_Display *display) +{ + const bool on_exit = true; + + /* NOTE(@campbellbarton): Free by slot instead of simply looping over + * `display->registry_entry` so the order of freeing is always predictable. + * Otherwise global objects would be feed in the order they are registered. + * While this works in my tests, it could cause difficult to reproduce bugs + * where lesser used compositors or changes to existing compositors could + * crash on exit based on the order of freeing objects is out of our control. + * + * To give a concrete example of how this could fail, it's possible removing + * a tablet interface could reference the pointer interface, or the output interface. + * Even though references between interfaces shouldn't be necessary in most cases + * when `on_exit` is enabled. */ + int interface_slot = gwl_registry_handler_interface_slot_max(); + while (interface_slot--) { + gwl_registry_entry_remove_by_interface_slot(display, interface_slot, on_exit); } - if (display->wl_display) { - wl_display_disconnect(display->wl_display); + GHOST_ASSERT(display->registry_entry == nullptr, "Failed to remove all entries!"); + display->registry_entry = nullptr; +} + +/** + * Run GWL_RegistryHandler.update_fn an all registered interface instances. + * This is needed to refresh the state of interfaces that may reference other interfaces. + * Called when interfaces are added/removed. + * + * \param interface_slot_exclude: Skip updating slots of this type. + * Note that while harmless dependencies only exist between different types, + * so there is no reason to update all other outputs that an output was removed (for e.g.). + * Pass as -1 to update all slots. + * + * NOTE(@campbellbarton): Updating all other items on a single change is typically worth avoiding. + * In practice this isn't a problem as so there are so few elements in `display->registry_entry`, + * so few use update functions and adding/removal at runtime is rarely called (plugging/unplugging) + * hardware for e.g. So while it's possible to store dependency links to avoid unnecessary + * looping over data - it ends up being a non issue. + */ +static void gwl_registry_entry_update_all(GWL_Display *display, const int interface_slot_exclude) +{ + GHOST_ASSERT(interface_slot_exclude == -1 || (uint(interface_slot_exclude) < + uint(gwl_registry_handler_interface_slot_max())), + "Invalid exclude slot"); + + for (GWL_RegistryEntry *reg = display->registry_entry; reg; reg = reg->next) { + if (reg->interface_slot == interface_slot_exclude) { + continue; + } + const GWL_RegistryHandler *handler = gwl_registry_handler_from_interface_slot( + reg->interface_slot); + if (handler->update_fn == nullptr) { + continue; + } + + GWL_RegisteryUpdate_Params params = { + .name = reg->name, + .interface_slot = reg->interface_slot, + .version = reg->version, + + .user_data = reg->user_data, + }; + handler->update_fn(display, ¶ms); } +} - delete display; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Private Utility Functions + * \{ */ + +/** + * Callback for WAYLAND to run when there is an error. + * + * \note It's useful to set a break-point on this function as some errors are fatal + * (for all intents and purposes) but don't crash the process. + */ +static void ghost_wayland_log_handler(const char *msg, va_list arg) +{ + fprintf(stderr, "GHOST/Wayland: "); + vfprintf(stderr, msg, arg); /* Includes newline. */ + + GHOST_TBacktraceFn backtrace_fn = GHOST_ISystem::getBacktraceFn(); + if (backtrace_fn) { + backtrace_fn(stderr); /* Includes newline. */ + } } static GHOST_TKey xkb_map_gkey(const xkb_keysym_t sym) @@ -837,9 +1309,24 @@ static GHOST_TKey xkb_map_gkey_or_scan_code(const xkb_keysym_t sym, const uint32 return gkey; } -static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_tablet_tool_type) +static int pointer_axis_as_index(const uint32_t axis) +{ + switch (axis) { + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: { + return 0; + } + case WL_POINTER_AXIS_VERTICAL_SCROLL: { + return 1; + } + default: { + return -1; + } + } +} + +static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wp_tablet_tool_type) { - switch (wl_tablet_tool_type) { + switch (wp_tablet_tool_type) { case ZWP_TABLET_TOOL_V2_TYPE_ERASER: { return GHOST_kTabletModeEraser; } @@ -854,13 +1341,13 @@ static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_ta } } - GHOST_PRINT("unknown tablet tool: " << wl_tablet_tool_type << std::endl); + GHOST_PRINT("unknown tablet tool: " << wp_tablet_tool_type << std::endl); return GHOST_kTabletModeStylus; } static const int default_cursor_size = 24; -static const std::unordered_map<GHOST_TStandardCursor, const char *> cursors = { +static const std::unordered_map<GHOST_TStandardCursor, const char *> ghost_wl_cursors = { {GHOST_kStandardCursorDefault, "left_ptr"}, {GHOST_kStandardCursorRightArrow, "right_ptr"}, {GHOST_kStandardCursorLeftArrow, "left_ptr"}, @@ -901,23 +1388,23 @@ static const std::unordered_map<GHOST_TStandardCursor, const char *> cursors = { {GHOST_kStandardCursorCopy, "copy"}, }; -static constexpr const char *mime_text_plain = "text/plain"; -static constexpr const char *mime_text_utf8 = "text/plain;charset=utf-8"; -static constexpr const char *mime_text_uri = "text/uri-list"; +static constexpr const char *ghost_wl_mime_text_plain = "text/plain"; +static constexpr const char *ghost_wl_mime_text_utf8 = "text/plain;charset=utf-8"; +static constexpr const char *ghost_wl_mime_text_uri = "text/uri-list"; -static const std::unordered_map<std::string, GHOST_TDragnDropTypes> mime_dnd = { - {mime_text_plain, GHOST_kDragnDropTypeString}, - {mime_text_utf8, GHOST_kDragnDropTypeString}, - {mime_text_uri, GHOST_kDragnDropTypeFilenames}, +static const char *ghost_wl_mime_preference_order[] = { + ghost_wl_mime_text_uri, + ghost_wl_mime_text_utf8, + ghost_wl_mime_text_plain, }; - -static const std::vector<std::string> mime_preference_order = { - mime_text_uri, - mime_text_utf8, - mime_text_plain, +/* Aligned to `ghost_wl_mime_preference_order`. */ +static const GHOST_TDragnDropTypes ghost_wl_mime_preference_order_type[] = { + GHOST_kDragnDropTypeString, + GHOST_kDragnDropTypeString, + GHOST_kDragnDropTypeFilenames, }; -static const std::vector<std::string> mime_send = { +static const char *ghost_wl_mime_send[] = { "UTF8_STRING", "COMPOUND_TEXT", "TEXT", @@ -1045,9 +1532,9 @@ static void keyboard_depressed_state_key_event(GWL_Seat *seat, } static void keyboard_depressed_state_push_events_from_change( - GWL_Seat *seat, const WGL_KeyboardDepressedState &key_depressed_prev) + GWL_Seat *seat, const GWL_KeyboardDepressedState &key_depressed_prev) { - GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl_surface); + GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl_surface_window); GHOST_SystemWayland *system = seat->system; /* Separate key up and down into separate passes so key down events always come after key up. @@ -1134,7 +1621,7 @@ static void relative_pointer_handle_relative_motion( const wl_fixed_t /*dy_unaccel*/) { GWL_Seat *seat = static_cast<GWL_Seat *>(data); - if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { CLOG_INFO(LOG, 2, "relative_motion"); GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); @@ -1167,7 +1654,7 @@ static CLG_LogRef LOG_WL_DATA_SOURCE = {"ghost.wl.handle.data_source"}; static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event) { /* NOTE: `seat->data_offer_dnd_mutex` must already be locked. */ - if (wl_surface *wl_surface_focus = seat->wl_surface_focus_dnd) { + if (wl_surface *wl_surface_focus = seat->wl_surface_window_focus_dnd) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); const int event_xy[2] = { @@ -1176,40 +1663,144 @@ static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event) }; const uint64_t time = seat->system->getMilliSeconds(); - for (const std::string &type : mime_preference_order) { - seat->system->pushEvent(new GHOST_EventDragnDrop( - time, event, mime_dnd.at(type), win, UNPACK2(event_xy), nullptr)); + for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_preference_order_type); i++) { + const GHOST_TDragnDropTypes type = ghost_wl_mime_preference_order_type[i]; + seat->system->pushEvent( + new GHOST_EventDragnDrop(time, event, type, win, UNPACK2(event_xy), nullptr)); } } } -static std::string read_pipe(GWL_DataOffer *data_offer, - const std::string mime_receive, - std::mutex *mutex) +/** + * Read from `fd` into a buffer which is returned. + * \return the buffer or null on failure. + */ +static char *read_file_as_buffer(const int fd, const bool nil_terminate, size_t *r_len) +{ + struct ByteChunk { + ByteChunk *next; + char data[4096 - sizeof(ByteChunk *)]; + }; + ByteChunk *chunk_first = nullptr, **chunk_link_p = &chunk_first; + bool ok = true; + size_t len = 0; + while (true) { + ByteChunk *chunk = static_cast<typeof(chunk)>(malloc(sizeof(*chunk))); + if (UNLIKELY(chunk == nullptr)) { + CLOG_WARN(LOG, "unable to allocate chunk for file buffer"); + ok = false; + break; + } + chunk->next = nullptr; + const ssize_t len_chunk = read(fd, chunk->data, sizeof(chunk->data)); + if (len_chunk <= 0) { + if (UNLIKELY(len_chunk < 0)) { + CLOG_WARN(LOG, "error reading from pipe: %s", std::strerror(errno)); + ok = false; + } + free(chunk); + break; + } + if (chunk_first == nullptr) { + chunk_first = chunk; + } + *chunk_link_p = chunk; + chunk_link_p = &chunk->next; + len += len_chunk; + } + + char *buf = nullptr; + if (ok) { + buf = static_cast<char *>(malloc(len + (nil_terminate ? 1 : 0))); + if (UNLIKELY(buf == nullptr)) { + CLOG_WARN(LOG, "unable to allocate file buffer: %zu bytes", len); + ok = false; + } + } + + if (ok) { + *r_len = len; + if (nil_terminate) { + buf[len] = '\0'; + } + } + else { + *r_len = 0; + } + + char *buf_stride = buf; + while (chunk_first) { + if (ok) { + const size_t len_chunk = std::min(len, sizeof(chunk_first->data)); + memcpy(buf_stride, chunk_first->data, len_chunk); + buf_stride += len_chunk; + len -= len_chunk; + } + ByteChunk *chunk = chunk_first->next; + free(chunk_first); + chunk_first = chunk; + } + + return buf; +} + +static char *read_buffer_from_data_offer(GWL_DataOffer *data_offer, + const char *mime_receive, + std::mutex *mutex, + const bool nil_terminate, + size_t *r_len) { int pipefd[2]; - if (UNLIKELY(pipe(pipefd) != 0)) { - return {}; + const bool pipefd_ok = pipe(pipefd) == 0; + if (pipefd_ok) { + wl_data_offer_receive(data_offer->id, mime_receive, pipefd[1]); + close(pipefd[1]); + } + else { + CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno)); } - wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]); - close(pipefd[1]); - data_offer->in_use.store(false); + /* Only for DND (A no-op to disable for clipboard data-offer). */ + data_offer->dnd.in_use = false; if (mutex) { mutex->unlock(); } /* WARNING: `data_offer` may be freed from now on. */ + char *buf = nullptr; + if (pipefd_ok) { + buf = read_file_as_buffer(pipefd[0], nil_terminate, r_len); + close(pipefd[0]); + } + return buf; +} - std::string data; - ssize_t len; - char buffer[4096]; - while ((len = read(pipefd[0], buffer, sizeof(buffer))) > 0) { - data.insert(data.end(), buffer, buffer + len); +static char *read_buffer_from_primary_selection_offer(GWL_PrimarySelection_DataOffer *data_offer, + const char *mime_receive, + std::mutex *mutex, + const bool nil_terminate, + size_t *r_len) +{ + int pipefd[2]; + const bool pipefd_ok = pipe(pipefd) == 0; + if (pipefd_ok) { + zwp_primary_selection_offer_v1_receive(data_offer->id, mime_receive, pipefd[1]); + close(pipefd[1]); + } + else { + CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno)); } - close(pipefd[0]); - return data; + if (mutex) { + mutex->unlock(); + } + /* WARNING: `data_offer` may be freed from now on. */ + char *buf = nullptr; + if (pipefd_ok) { + buf = read_file_as_buffer(pipefd[0], nil_terminate, r_len); + close(pipefd[0]); + } + return buf; } /** @@ -1231,20 +1822,33 @@ static void data_source_handle_send(void *data, const int32_t fd) { GWL_Seat *seat = static_cast<GWL_Seat *>(data); - std::lock_guard lock{seat->data_source_mutex}; CLOG_INFO(LOG, 2, "send"); - const char *const buffer = seat->data_source->buffer_out; - if (write(fd, buffer, strlen(buffer)) < 0) { - GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl); - } - close(fd); + auto write_file_fn = [](GWL_Seat *seat, const int fd) { + if (UNLIKELY(write(fd, + seat->data_source->buffer_out.data, + seat->data_source->buffer_out.data_size) < 0)) { + CLOG_WARN(LOG, "error writing to clipboard: %s", std::strerror(errno)); + } + close(fd); + seat->data_source_mutex.unlock(); + }; + + seat->data_source_mutex.lock(); + std::thread write_thread(write_file_fn, seat, fd); + write_thread.detach(); } -static void data_source_handle_cancelled(void * /*data*/, struct wl_data_source *wl_data_source) +static void data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source) { CLOG_INFO(LOG, 2, "cancelled"); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + GWL_DataSource *data_source = seat->data_source; + if (seat->data_source->wl_source == wl_data_source) { + data_source->wl_source = nullptr; + } + wl_data_source_destroy(wl_data_source); } @@ -1313,7 +1917,8 @@ static void data_offer_handle_offer(void *data, const char *mime_type) { CLOG_INFO(LOG, 2, "offer (mime_type=%s)", mime_type); - static_cast<GWL_DataOffer *>(data)->types.insert(mime_type); + GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data); + data_offer->types.insert(mime_type); } static void data_offer_handle_source_actions(void *data, @@ -1321,7 +1926,8 @@ static void data_offer_handle_source_actions(void *data, const uint32_t source_actions) { CLOG_INFO(LOG, 2, "source_actions (%u)", source_actions); - static_cast<GWL_DataOffer *>(data)->source_actions = source_actions; + GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data); + data_offer->dnd.source_actions = (enum wl_data_device_manager_dnd_action)source_actions; } static void data_offer_handle_action(void *data, @@ -1329,7 +1935,8 @@ static void data_offer_handle_action(void *data, const uint32_t dnd_action) { CLOG_INFO(LOG, 2, "actions (%u)", dnd_action); - static_cast<GWL_DataOffer *>(data)->dnd_action = dnd_action; + GWL_DataOffer *data_offer = static_cast<GWL_DataOffer *>(data); + data_offer->dnd.action = (enum wl_data_device_manager_dnd_action)dnd_action; } static const struct wl_data_offer_listener data_offer_listener = { @@ -1381,7 +1988,7 @@ static void data_device_handle_enter(void *data, seat->data_offer_dnd = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id)); GWL_DataOffer *data_offer = seat->data_offer_dnd; - data_offer->in_use.store(true); + data_offer->dnd.in_use = true; data_offer->dnd.xy[0] = x; data_offer->dnd.xy[1] = y; @@ -1390,11 +1997,15 @@ static void data_device_handle_enter(void *data, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); - for (const std::string &type : mime_preference_order) { - wl_data_offer_accept(id, serial, type.c_str()); + for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_preference_order); i++) { + const char *type = ghost_wl_mime_preference_order[i]; + wl_data_offer_accept(id, serial, type); } - seat->wl_surface_focus_dnd = wl_surface; + seat->wl_surface_window_focus_dnd = wl_surface; + + seat->system->seat_active_set(seat); + dnd_events(seat, GHOST_kEventDraggingEntered); } @@ -1406,9 +2017,9 @@ static void data_device_handle_leave(void *data, struct wl_data_device * /*wl_da CLOG_INFO(LOG, 2, "leave"); dnd_events(seat, GHOST_kEventDraggingExited); - seat->wl_surface_focus_dnd = nullptr; + seat->wl_surface_window_focus_dnd = nullptr; - if (seat->data_offer_dnd && !seat->data_offer_dnd->in_use.load()) { + if (seat->data_offer_dnd && !seat->data_offer_dnd->dnd.in_use) { wl_data_offer_destroy(seat->data_offer_dnd->id); delete seat->data_offer_dnd; seat->data_offer_dnd = nullptr; @@ -1439,23 +2050,35 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat GWL_DataOffer *data_offer = seat->data_offer_dnd; - const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(), - mime_preference_order.end(), - data_offer->types.begin(), - data_offer->types.end()); + /* Use a blank string for `mime_receive` to prevent crashes, although could also be `nullptr`. + * Failure to set this to a known type just means the file won't have any special handling. + * GHOST still generates a dropped file event. + * NOTE: this string can be compared with `mime_text_plain`, `mime_text_uri` etc... + * as the this always points to the same values. */ + const char *mime_receive = ""; + for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_preference_order); i++) { + const char *type = ghost_wl_mime_preference_order[i]; + if (data_offer->types.count(type)) { + mime_receive = type; + break; + } + } - CLOG_INFO(LOG, 2, "drop mime_recieve=%s", mime_receive.c_str()); + CLOG_INFO(LOG, 2, "drop mime_recieve=%s", mime_receive); auto read_uris_fn = [](GWL_Seat *const seat, GWL_DataOffer *data_offer, - wl_surface *wl_surface, - const std::string mime_receive) { + wl_surface *wl_surface_window, + const char *mime_receive) { const wl_fixed_t xy[2] = {UNPACK2(data_offer->dnd.xy)}; - const std::string data = read_pipe(data_offer, mime_receive, nullptr); + size_t data_buf_len = 0; + const char *data_buf = read_buffer_from_data_offer( + data_offer, mime_receive, nullptr, false, &data_buf_len); + std::string data = data_buf ? std::string(data_buf, data_buf_len) : ""; + free(const_cast<char *>(data_buf)); - CLOG_INFO( - LOG, 2, "drop_read_uris mime_receive=%s, data=%s", mime_receive.c_str(), data.c_str()); + CLOG_INFO(LOG, 2, "drop_read_uris mime_receive=%s, data=%s", mime_receive, data.c_str()); wl_data_offer_finish(data_offer->id); wl_data_offer_destroy(data_offer->id); @@ -1468,13 +2091,13 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat GHOST_SystemWayland *const system = seat->system; - if (mime_receive == mime_text_uri) { + if (mime_receive == ghost_wl_mime_text_uri) { static constexpr const char *file_proto = "file://"; /* NOTE: some applications CRLF (`\r\n`) GTK3 for e.g. & others don't `pcmanfm-qt`. * So support both, once `\n` is found, strip the preceding `\r` if found. */ static constexpr const char *lf = "\n"; - GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_window); std::vector<std::string> uris; size_t pos = 0; @@ -1513,7 +2136,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat wl_fixed_to_int(scale * xy[1]), flist)); } - else if (ELEM(mime_receive, mime_text_plain, mime_text_utf8)) { + else if (ELEM(mime_receive, ghost_wl_mime_text_plain, ghost_wl_mime_text_utf8)) { /* TODO: enable use of internal functions 'txt_insert_buf' and * 'text_update_edited' to behave like dropped text was pasted. */ CLOG_INFO(LOG, 2, "drop_read_uris_fn (text_plain, text_utf8), unhandled!"); @@ -1521,10 +2144,10 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat wl_display_roundtrip(system->wl_display()); }; - /* Pass in `seat->wl_surface_focus_dnd` instead of accessing it from `seat` since the leave - * callback (#data_device_handle_leave) will clear the value once this function starts. */ + /* Pass in `seat->wl_surface_window_focus_dnd` instead of accessing it from `seat` since the + * leave callback (#data_device_handle_leave) will clear the value once this function starts. */ std::thread read_thread( - read_uris_fn, seat, data_offer, seat->wl_surface_focus_dnd, mime_receive); + read_uris_fn, seat, data_offer, seat->wl_surface_window_focus_dnd, mime_receive); read_thread.detach(); } @@ -1554,30 +2177,6 @@ static void data_device_handle_selection(void *data, /* Get new data offer. */ data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id)); seat->data_offer_copy_paste = data_offer; - - auto read_selection_fn = [](GWL_Seat *seat) { - GHOST_SystemWayland *const system = seat->system; - seat->data_offer_copy_paste_mutex.lock(); - - GWL_DataOffer *data_offer = seat->data_offer_copy_paste; - std::string mime_receive; - for (const std::string type : {mime_text_utf8, mime_text_plain}) { - if (data_offer->types.count(type)) { - mime_receive = type; - break; - } - } - const std::string data = read_pipe( - data_offer, mime_receive, &seat->data_offer_copy_paste_mutex); - - { - std::lock_guard lock{system_clipboard_mutex}; - system->clipboard_set(data); - } - }; - - std::thread read_thread(read_selection_fn, seat); - read_thread.detach(); } static const struct wl_data_device_listener data_device_listener = { @@ -1631,7 +2230,7 @@ static CLG_LogRef LOG_WL_CURSOR_SURFACE = {"ghost.wl.handle.cursor_surface"}; static bool update_cursor_scale(GWL_Cursor &cursor, wl_shm *shm, GWL_SeatStatePointer *seat_state_pointer, - wl_surface *wl_cursor_surface) + wl_surface *wl_surface_cursor) { int scale = 0; for (const GWL_Output *output : seat_state_pointer->outputs) { @@ -1643,10 +2242,11 @@ static bool update_cursor_scale(GWL_Cursor &cursor, if (scale > 0 && seat_state_pointer->theme_scale != scale) { seat_state_pointer->theme_scale = scale; if (!cursor.is_custom) { - wl_surface_set_buffer_scale(wl_cursor_surface, scale); + wl_surface_set_buffer_scale(wl_surface_cursor, scale); } wl_cursor_theme_destroy(cursor.wl_theme); - cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm); + cursor.wl_theme = wl_cursor_theme_load( + cursor.theme_name.c_str(), scale * cursor.theme_size, shm); return true; } return false; @@ -1663,8 +2263,8 @@ static void cursor_surface_handle_enter(void *data, CLOG_INFO(LOG, 2, "handle_enter"); GWL_Seat *seat = static_cast<GWL_Seat *>(data); - GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_from_cursor_surface(seat, - wl_surface); + GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_from_cursor_surface( + seat, wl_surface); const GWL_Output *reg_output = ghost_wl_output_user_data(wl_output); seat_state_pointer->outputs.insert(reg_output); update_cursor_scale(seat->cursor, seat->system->wl_shm(), seat_state_pointer, wl_surface); @@ -1681,8 +2281,8 @@ static void cursor_surface_handle_leave(void *data, CLOG_INFO(LOG, 2, "handle_leave"); GWL_Seat *seat = static_cast<GWL_Seat *>(data); - GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_from_cursor_surface(seat, - wl_surface); + GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_from_cursor_surface( + seat, wl_surface); const GWL_Output *reg_output = ghost_wl_output_user_data(wl_output); seat_state_pointer->outputs.erase(reg_output); update_cursor_scale(seat->cursor, seat->system->wl_shm(), seat_state_pointer, wl_surface); @@ -1726,7 +2326,18 @@ static void pointer_handle_enter(void *data, seat->pointer.serial = serial; seat->pointer.xy[0] = surface_x; seat->pointer.xy[1] = surface_y; - seat->pointer.wl_surface = wl_surface; + + /* Resetting scroll events is likely unnecessary, + * do this to avoid any possible problems as it's harmless. */ + seat->pointer_scroll.smooth_xy[0] = 0; + seat->pointer_scroll.smooth_xy[1] = 0; + seat->pointer_scroll.discrete_xy[0] = 0; + seat->pointer_scroll.discrete_xy[1] = 0; + seat->pointer_scroll.axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; + + seat->pointer.wl_surface_window = wl_surface; + + seat->system->seat_active_set(seat); win->setCursorShape(win->getCursorShape()); @@ -1745,7 +2356,7 @@ static void pointer_handle_leave(void *data, struct wl_surface *wl_surface) { /* First clear the `pointer.wl_surface`, since the window won't exist when closing the window. */ - static_cast<GWL_Seat *>(data)->pointer.wl_surface = nullptr; + static_cast<GWL_Seat *>(data)->pointer.wl_surface_window = nullptr; if (wl_surface && ghost_wl_surface_own(wl_surface)) { CLOG_INFO(LOG, 2, "leave"); GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface); @@ -1766,7 +2377,7 @@ static void pointer_handle_motion(void *data, seat->pointer.xy[0] = surface_x; seat->pointer.xy[1] = surface_y; - if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { CLOG_INFO(LOG, 2, "motion"); GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); @@ -1830,31 +2441,99 @@ static void pointer_handle_button(void *data, seat->data_source_serial = serial; seat->pointer.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); - if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); seat->system->pushEvent(new GHOST_EventButton( seat->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE)); } } -static void pointer_handle_axis(void * /*data*/, +static void pointer_handle_axis(void *data, struct wl_pointer * /*wl_pointer*/, const uint32_t /*time*/, const uint32_t axis, const wl_fixed_t value) { + /* NOTE: this is used for touch based scrolling - or other input that doesn't scroll with + * discrete "steps". This allows supporting smooth-scrolling without "touch" gesture support. */ CLOG_INFO(LOG, 2, "axis (axis=%u, value=%d)", axis, value); + const int index = pointer_axis_as_index(axis); + if (UNLIKELY(index == -1)) { + return; + } + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->pointer_scroll.smooth_xy[index] = value; } -static void pointer_handle_frame(void * /*data*/, struct wl_pointer * /*wl_pointer*/) +static void pointer_handle_frame(void *data, struct wl_pointer * /*wl_pointer*/) { CLOG_INFO(LOG, 2, "frame"); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + + /* Both discrete and smooth events may be set at once, never generate events for both + * as this will be handling the same event in to different ways. + * Prioritize discrete axis events for the mouse wheel, otherwise smooth scroll. */ + if (seat->pointer_scroll.axis_source == WL_POINTER_AXIS_SOURCE_WHEEL) { + if (seat->pointer_scroll.discrete_xy[0]) { + seat->pointer_scroll.smooth_xy[0] = 0; + } + if (seat->pointer_scroll.discrete_xy[1]) { + seat->pointer_scroll.smooth_xy[1] = 0; + } + } + else { + if (seat->pointer_scroll.smooth_xy[0]) { + seat->pointer_scroll.discrete_xy[0] = 0; + } + if (seat->pointer_scroll.smooth_xy[1]) { + seat->pointer_scroll.discrete_xy[1] = 0; + } + } + + /* Discrete X axis currently unsupported. */ + if (seat->pointer_scroll.discrete_xy[1]) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + const int32_t discrete = seat->pointer_scroll.discrete_xy[1]; + seat->system->pushEvent(new GHOST_EventWheel( + seat->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1)); + } + seat->pointer_scroll.discrete_xy[0] = 0; + seat->pointer_scroll.discrete_xy[1] = 0; + } + + if (seat->pointer_scroll.smooth_xy[0] || seat->pointer_scroll.smooth_xy[1]) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + const wl_fixed_t scale = win->scale(); + seat->system->pushEvent(new GHOST_EventTrackpad( + seat->system->getMilliSeconds(), + win, + GHOST_kTrackpadEventScroll, + wl_fixed_to_int(scale * seat->pointer.xy[0]), + wl_fixed_to_int(scale * seat->pointer.xy[1]), + /* NOTE: scaling the delta doesn't seem necessary. + * NOTE: inverting delta gives correct results, see: QTBUG-85767. + * NOTE: the preference to invert scrolling (in GNOME at least) + * has already been applied so there is no need to read this preference. */ + -wl_fixed_to_int(seat->pointer_scroll.smooth_xy[0]), + -wl_fixed_to_int(seat->pointer_scroll.smooth_xy[1]), + false)); + } + + seat->pointer_scroll.smooth_xy[0] = 0; + seat->pointer_scroll.smooth_xy[1] = 0; + } + + seat->pointer_scroll.axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; } -static void pointer_handle_axis_source(void * /*data*/, +static void pointer_handle_axis_source(void *data, struct wl_pointer * /*wl_pointer*/, uint32_t axis_source) { CLOG_INFO(LOG, 2, "axis_source (axis_source=%u)", axis_source); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->pointer_scroll.axis_source = (enum wl_pointer_axis_source)axis_source; } static void pointer_handle_axis_stop(void * /*data*/, struct wl_pointer * /*wl_pointer*/, @@ -1868,18 +2547,15 @@ static void pointer_handle_axis_discrete(void *data, uint32_t axis, int32_t discrete) { + /* NOTE: a discrete axis are typically mouse wheel events. + * The non-discrete version of this function is used for touch-pad. */ CLOG_INFO(LOG, 2, "axis_discrete (axis=%u, discrete=%d)", axis, discrete); - - GWL_Seat *seat = static_cast<GWL_Seat *>(data); - if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) { + const int index = pointer_axis_as_index(axis); + if (UNLIKELY(index == -1)) { return; } - - if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); - seat->system->pushEvent(new GHOST_EventWheel( - seat->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1)); - } + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->pointer_scroll.discrete_xy[index] = discrete; } static const struct wl_pointer_listener pointer_listener = { @@ -1899,6 +2575,325 @@ static const struct wl_pointer_listener pointer_listener = { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Listener (Pointer Gesture: Hold), #zwp_pointer_gesture_hold_v1_listener + * \{ */ + +#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE +static CLG_LogRef LOG_WL_POINTER_GESTURE_HOLD = {"ghost.wl.handle.pointer_gesture.hold"}; +# define LOG (&LOG_WL_POINTER_GESTURE_HOLD) + +static void gesture_hold_handle_begin( + void * /*data*/, + struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*surface*/, + uint32_t fingers) +{ + CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers); +} + +static void gesture_hold_handle_end( + void * /*data*/, + struct zwp_pointer_gesture_hold_v1 * /*zwp_pointer_gesture_hold_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t cancelled) +{ + CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled); +} + +static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = { + gesture_hold_handle_begin, + gesture_hold_handle_end, +}; + +# undef LOG +#endif /* ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Pointer Gesture: Pinch), #zwp_pointer_gesture_pinch_v1_listener + * \{ */ + +#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE +static CLG_LogRef LOG_WL_POINTER_GESTURE_PINCH = {"ghost.wl.handle.pointer_gesture.pinch"}; +# define LOG (&LOG_WL_POINTER_GESTURE_PINCH) + +static void gesture_pinch_handle_begin(void *data, + struct zwp_pointer_gesture_pinch_v1 * /*pinch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*surface*/, + uint32_t fingers) +{ + CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + /* Reset defaults. */ + seat->pointer_gesture_pinch = GWL_SeatStatePointerGesture_Pinch{}; + + GHOST_WindowWayland *win = nullptr; + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { + win = ghost_wl_surface_user_data(wl_surface_focus); + } + /* NOTE(@campbellbarton): Blender's use of track-pad coordinates is inconsistent and needs work. + * This isn't specific to WAYLAND, in practice they tend to work well enough in most cases. + * Some operators scale by the UI scale, some don't. + * Even this window scale is not correct because it doesn't account for: + * 1) Fractional window scale. + * 2) Blender's UI scale preference (which GHOST doesn't know about). + * + * If support for this were all that was needed it could be handled in GHOST, + * however as the operators are not even using coordinates compatible with each other, + * it would be better to resolve this by passing rotation & zoom levels directly, + * instead of attempting to handle them as cursor coordinates. + */ + const wl_fixed_t win_scale = win ? win->scale() : 1; + + /* NOTE(@campbellbarton): Scale factors match Blender's operators & default preferences. + * For these values to work correctly, operator logic will need to be changed not to scale input + * by the region size (as with 3D view zoom) or preference for 3D view orbit sensitivity. + * + * By working "correctly" I mean that a rotation action where the users fingers rotate to + * opposite locations should always rotate the viewport 180d, since users will expect the + * physical location of their fingers to match the viewport. + * Similarly with zoom, the scale value from the pinch action can be mapped to a zoom level + * although unlike rotation, an inexact mapping is less noticeable. + * Users may even prefer the zoom level to be scaled - which could be a preference. */ + seat->pointer_gesture_pinch.scale.value = wl_fixed_from_int(1); + /* The value 300 matches a value used in clip & image zoom operators. + * It seems OK for the 3D view too. */ + seat->pointer_gesture_pinch.scale.factor = 300 * win_scale; + /* The value 5 is used on macOS and roughly maps 1:1 with turntable rotation, + * although preferences can scale the sensitivity (which would be skipped ideally). */ + seat->pointer_gesture_pinch.rotation.factor = 5 * win_scale; +} + +static void gesture_pinch_handle_update(void *data, + struct zwp_pointer_gesture_pinch_v1 * /*pinch*/, + uint32_t /*time*/, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t scale, + wl_fixed_t rotation) +{ + CLOG_INFO(LOG, + 2, + "update (dx=%.3f, dy=%.3f, scale=%.3f, rotation=%.3f)", + wl_fixed_to_double(dx), + wl_fixed_to_double(dy), + wl_fixed_to_double(scale), + wl_fixed_to_double(rotation)); + + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + + GHOST_WindowWayland *win = nullptr; + + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { + win = ghost_wl_surface_user_data(wl_surface_focus); + } + + /* Scale defaults to `wl_fixed_from_int(1)` which may change while pinching. + * This needs to be converted to a delta. */ + const wl_fixed_t scale_delta = scale - seat->pointer_gesture_pinch.scale.value; + const int scale_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta( + &seat->pointer_gesture_pinch.scale, scale_delta); + + /* Rotation in degrees, unlike scale this is a delta. */ + const int rotation_as_delta_px = gwl_scaled_fixed_t_add_and_calc_rounded_delta( + &seat->pointer_gesture_pinch.rotation, rotation); + + if (win) { + const wl_fixed_t win_scale = win->scale(); + const int32_t event_xy[2] = { + wl_fixed_to_int(win_scale * seat->pointer.xy[0]), + wl_fixed_to_int(win_scale * seat->pointer.xy[1]), + }; + if (scale_as_delta_px) { + seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(), + win, + GHOST_kTrackpadEventMagnify, + event_xy[0], + event_xy[1], + scale_as_delta_px, + 0, + false)); + } + + if (rotation_as_delta_px) { + seat->system->pushEvent(new GHOST_EventTrackpad(seat->system->getMilliSeconds(), + win, + GHOST_kTrackpadEventRotate, + event_xy[0], + event_xy[1], + rotation_as_delta_px, + 0, + false)); + } + } +} + +static void gesture_pinch_handle_end(void * /*data*/, + struct zwp_pointer_gesture_pinch_v1 * /*pinch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t cancelled) +{ + CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled); +} + +static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = { + gesture_pinch_handle_begin, + gesture_pinch_handle_update, + gesture_pinch_handle_end, +}; + +# undef LOG +#endif /* ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Pointer Gesture: Swipe), #zwp_pointer_gesture_swipe_v1 + * + * \note In both Gnome-Shell & KDE this gesture isn't emitted at time of writing, + * instead, high resolution 2D #wl_pointer_listener.axis data is generated which works well. + * There may be some situations where WAYLAND compositors generate this gesture + * (swiping with 3+ fingers, for e.g.). So keep this to allow logging & testing gestures. + * \{ */ + +#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE +static CLG_LogRef LOG_WL_POINTER_GESTURE_SWIPE = {"ghost.wl.handle.pointer_gesture.swipe"}; +# define LOG (&LOG_WL_POINTER_GESTURE_SWIPE) + +static void gesture_swipe_handle_begin( + void * /*data*/, + struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*surface*/, + uint32_t fingers) +{ + CLOG_INFO(LOG, 2, "begin (fingers=%u)", fingers); +} + +static void gesture_swipe_handle_update( + void * /*data*/, + struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/, + uint32_t /*time*/, + wl_fixed_t dx, + wl_fixed_t dy) +{ + CLOG_INFO(LOG, 2, "update (dx=%.3f, dy=%.3f)", wl_fixed_to_double(dx), wl_fixed_to_double(dy)); +} + +static void gesture_swipe_handle_end( + void * /*data*/, + struct zwp_pointer_gesture_swipe_v1 * /*zwp_pointer_gesture_swipe_v1*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t cancelled) +{ + CLOG_INFO(LOG, 2, "end (cancelled=%i)", cancelled); +} + +static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener = { + gesture_swipe_handle_begin, + gesture_swipe_handle_update, + gesture_swipe_handle_end, +}; + +# undef LOG +#endif /* ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Touch Seat), #wl_touch_listener + * + * NOTE(@campbellbarton): It's not clear if this interface is used by popular compositors. + * It looks like GNOME/KDE only support `zwp_pointer_gestures_v1_interface`. + * If this isn't used anywhere, it could be removed. + * \{ */ + +static CLG_LogRef LOG_WL_TOUCH = {"ghost.wl.handle.touch"}; +#define LOG (&LOG_WL_TOUCH) + +static void touch_seat_handle_down(void * /*data*/, + struct wl_touch * /*wl_touch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + struct wl_surface * /*wl_surface*/, + int32_t /*id*/, + wl_fixed_t /*x*/, + wl_fixed_t /*y*/) +{ + CLOG_INFO(LOG, 2, "down"); +} + +static void touch_seat_handle_up(void * /*data*/, + struct wl_touch * /*wl_touch*/, + uint32_t /*serial*/, + uint32_t /*time*/, + int32_t /*id*/) +{ + CLOG_INFO(LOG, 2, "up"); +} + +static void touch_seat_handle_motion(void * /*data*/, + struct wl_touch * /*wl_touch*/, + uint32_t /*time*/, + int32_t /*id*/, + wl_fixed_t /*x*/, + wl_fixed_t /*y*/) +{ + CLOG_INFO(LOG, 2, "motion"); +} + +static void touch_seat_handle_frame(void * /*data*/, struct wl_touch * /*wl_touch*/) +{ + CLOG_INFO(LOG, 2, "frame"); +} + +static void touch_seat_handle_cancel(void * /*data*/, struct wl_touch * /*wl_touch*/) +{ + + CLOG_INFO(LOG, 2, "cancel"); +} + +static void touch_seat_handle_shape(void * /*data*/, + struct wl_touch * /*touch*/, + int32_t /*id*/, + wl_fixed_t /*major*/, + wl_fixed_t /*minor*/) +{ + CLOG_INFO(LOG, 2, "shape"); +} + +static void touch_seat_handle_orientation(void * /*data*/, + struct wl_touch * /*touch*/, + int32_t /*id*/, + wl_fixed_t /*orientation*/) +{ + CLOG_INFO(LOG, 2, "orientation"); +} + +static const struct wl_touch_listener touch_seat_listener = { + touch_seat_handle_down, + touch_seat_handle_up, + touch_seat_handle_motion, + touch_seat_handle_frame, + touch_seat_handle_cancel, + touch_seat_handle_shape, + touch_seat_handle_orientation, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Listener (Tablet Tool), #zwp_tablet_tool_v2_listener * \{ */ @@ -1983,11 +2978,13 @@ static void tablet_tool_handle_proximity_in(void *data, GWL_Seat *seat = tablet_tool->seat; seat->cursor_source_serial = serial; - seat->tablet.wl_surface = wl_surface; + seat->tablet.wl_surface_window = wl_surface; seat->tablet.serial = serial; seat->data_source_serial = serial; + seat->system->seat_active_set(seat); + /* Update #GHOST_TabletData. */ GHOST_TabletData &td = tablet_tool->data; /* Reset, to avoid using stale tilt/pressure. */ @@ -1996,7 +2993,7 @@ static void tablet_tool_handle_proximity_in(void *data, /* In case pressure isn't supported. */ td.Pressure = 1.0f; - GHOST_WindowWayland *win = ghost_wl_surface_user_data(seat->tablet.wl_surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(seat->tablet.wl_surface_window); win->activate(); @@ -2026,7 +3023,7 @@ static void tablet_tool_handle_down(void *data, seat->data_source_serial = serial; seat->tablet.buttons.set(ebutton, true); - if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); seat->system->pushEvent(new GHOST_EventButton( seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data)); @@ -2044,7 +3041,7 @@ static void tablet_tool_handle_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_ seat->tablet.buttons.set(ebutton, false); - if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); seat->system->pushEvent(new GHOST_EventButton( seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data)); @@ -2129,7 +3126,7 @@ static void tablet_tool_handle_wheel(void *data, GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); GWL_Seat *seat = tablet_tool->seat; - if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); seat->system->pushEvent(new GHOST_EventWheel(seat->system->getMilliSeconds(), win, clicks)); } @@ -2158,10 +3155,10 @@ static void tablet_tool_handle_button(void *data, GHOST_TButton ebutton = GHOST_kButtonMaskLeft; switch (button) { case BTN_STYLUS: - ebutton = GHOST_kButtonMaskRight; + ebutton = GHOST_kButtonMaskMiddle; break; case BTN_STYLUS2: - ebutton = GHOST_kButtonMaskMiddle; + ebutton = GHOST_kButtonMaskRight; break; case BTN_STYLUS3: ebutton = GHOST_kButtonMaskButton4; @@ -2171,7 +3168,7 @@ static void tablet_tool_handle_button(void *data, seat->data_source_serial = serial; seat->tablet.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); - if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); seat->system->pushEvent(new GHOST_EventButton( seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data)); @@ -2187,7 +3184,7 @@ static void tablet_tool_handle_frame(void *data, GWL_Seat *seat = tablet_tool->seat; /* No need to check the surfaces origin, it's already known to be owned by GHOST. */ - if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); seat->system->pushEvent(new GHOST_EventCursor(seat->system->getMilliSeconds(), @@ -2202,7 +3199,7 @@ static void tablet_tool_handle_frame(void *data, } if (tablet_tool->proximity == false) { - seat->tablet.wl_surface = nullptr; + seat->tablet.wl_surface_window = nullptr; } } @@ -2330,9 +3327,23 @@ static void keyboard_handle_keymap(void *data, xkb_state_unref(seat->xkb_state_empty); seat->xkb_state_empty = xkb_state_new(keymap); + for (int i = 0; i < MOD_INDEX_NUM; i++) { + const GWL_ModifierInfo &mod_info = g_modifier_info_table[i]; + seat->xkb_keymap_mod_index[i] = xkb_keymap_mod_get_index(keymap, mod_info.xkb_id); + } + + xkb_state_unref(seat->xkb_state_empty_with_shift); + seat->xkb_state_empty_with_shift = nullptr; + { + const xkb_mod_index_t mod_shift = seat->xkb_keymap_mod_index[MOD_INDEX_SHIFT]; + if (mod_shift != XKB_MOD_INVALID) { + seat->xkb_state_empty_with_shift = xkb_state_new(keymap); + xkb_state_update_mask(seat->xkb_state_empty_with_shift, (1 << mod_shift), 0, 0, 0, 0, 0); + } + } + xkb_state_unref(seat->xkb_state_empty_with_numlock); seat->xkb_state_empty_with_numlock = nullptr; - { const xkb_mod_index_t mod2 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM); const xkb_mod_index_t num = xkb_keymap_mod_get_index(keymap, "NumLock"); @@ -2343,10 +3354,21 @@ static void keyboard_handle_keymap(void *data, } } - for (int i = 0; i < MOD_INDEX_NUM; i++) { - const GWL_ModifierInfo &mod_info = g_modifier_info_table[i]; - seat->xkb_keymap_mod_index[i] = xkb_keymap_mod_get_index(keymap, mod_info.xkb_id); +#ifdef USE_NON_LATIN_KB_WORKAROUND + seat->xkb_use_non_latin_workaround = false; + if (seat->xkb_state_empty_with_shift) { + seat->xkb_use_non_latin_workaround = true; + for (xkb_keycode_t key_code = KEY_1 + EVDEV_OFFSET; key_code <= KEY_0 + EVDEV_OFFSET; + key_code++) { + const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(seat->xkb_state_empty_with_shift, + key_code); + if (!(sym_test >= XKB_KEY_0 && sym_test <= XKB_KEY_9)) { + seat->xkb_use_non_latin_workaround = false; + break; + } + } } +#endif keyboard_depressed_state_reset(seat); @@ -2372,12 +3394,14 @@ static void keyboard_handle_enter(void *data, GWL_Seat *seat = static_cast<GWL_Seat *>(data); seat->keyboard.serial = serial; - seat->keyboard.wl_surface = wl_surface; + seat->keyboard.wl_surface_window = wl_surface; + + seat->system->seat_active_set(seat); /* If there are any keys held when activating the window, * modifiers will be compared against the seat state, * only enabling modifiers that were previously disabled. */ - WGL_KeyboardDepressedState key_depressed_prev = seat->key_depressed; + GWL_KeyboardDepressedState key_depressed_prev = seat->key_depressed; keyboard_depressed_state_reset(seat); uint32_t *key; @@ -2415,7 +3439,7 @@ static void keyboard_handle_leave(void *data, CLOG_INFO(LOG, 2, "leave"); GWL_Seat *seat = static_cast<GWL_Seat *>(data); - seat->keyboard.wl_surface = nullptr; + seat->keyboard.wl_surface_window = nullptr; /* Losing focus must stop repeating text. */ if (seat->key_repeat.timer) { @@ -2435,6 +3459,8 @@ static void keyboard_handle_leave(void *data, static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers( struct xkb_state *xkb_state_empty, struct xkb_state *xkb_state_empty_with_numlock, + struct xkb_state *xkb_state_empty_with_shift, + const bool xkb_use_non_latin_workaround, const xkb_keycode_t key) { /* Use an empty keyboard state to access key symbol without modifiers. */ @@ -2448,11 +3474,30 @@ static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers( /* Accounts for key-pad keys typically swapped for numbers when number-lock is enabled: * `Home Left Up Right Down Prior Page_Up Next Page_Dow End Begin Insert Delete`. */ - if (xkb_state_empty_with_numlock && (sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete)) { - const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(xkb_state_empty_with_numlock, key); - if (sym_test != XKB_KEY_NoSymbol) { - sym = sym_test; + if (sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete) { + if (xkb_state_empty_with_numlock) { + const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(xkb_state_empty_with_numlock, key); + if (sym_test != XKB_KEY_NoSymbol) { + sym = sym_test; + } + } + } + else { +#ifdef USE_NON_LATIN_KB_WORKAROUND + if (key >= (KEY_1 + EVDEV_OFFSET) && key <= (KEY_0 + EVDEV_OFFSET)) { + if (xkb_state_empty_with_shift && xkb_use_non_latin_workaround) { + const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(xkb_state_empty_with_shift, key); + if (sym_test != XKB_KEY_NoSymbol) { + /* Should never happen as enabling `xkb_use_non_latin_workaround` checks this. */ + GHOST_ASSERT(sym_test >= XKB_KEY_0 && sym_test <= XKB_KEY_9, "Unexpected key"); + sym = sym_test; + } + } } +#else + (void)xkb_state_empty_with_shift; + (void)xkb_use_non_latin_workaround; +#endif } return sym; @@ -2495,7 +3540,15 @@ static void keyboard_handle_key(void *data, const xkb_keycode_t key_code = key + EVDEV_OFFSET; const xkb_keysym_t sym = xkb_state_key_get_one_sym_without_modifiers( - seat->xkb_state_empty, seat->xkb_state_empty_with_numlock, key_code); + seat->xkb_state_empty, + seat->xkb_state_empty_with_numlock, + seat->xkb_state_empty_with_shift, +#ifdef USE_NON_LATIN_KB_WORKAROUND + seat->xkb_use_non_latin_workaround, +#else + false, +#endif + key_code); if (sym == XKB_KEY_NoSymbol) { CLOG_INFO(LOG, 2, "key (code=%d, state=%u, no symbol, skipped)", int(key_code), state); return; @@ -2576,7 +3629,7 @@ static void keyboard_handle_key(void *data, keyboard_depressed_state_key_event(seat, gkey, etype); - if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface) { + if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface_window) { GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus); seat->system->pushEvent( new GHOST_EventKey(seat->system->getMilliSeconds(), etype, win, gkey, false, utf8_buf)); @@ -2587,11 +3640,10 @@ static void keyboard_handle_key(void *data, /* Start timer for repeating key, if applicable. */ if ((seat->key_repeat.rate > 0) && (etype == GHOST_kEventKeyDown) && xkb_keymap_key_repeats(xkb_state_get_keymap(seat->xkb_state), key_code)) { - key_repeat_payload = new GWL_KeyRepeatPlayload({ - .seat = seat, - .key_code = key_code, - .key_data = {.gkey = gkey}, - }); + key_repeat_payload = new GWL_KeyRepeatPlayload(); + key_repeat_payload->seat = seat; + key_repeat_payload->key_code = key_code; + key_repeat_payload->key_data.gkey = gkey; } } @@ -2601,7 +3653,7 @@ static void keyboard_handle_key(void *data, task->getUserData()); GWL_Seat *seat = payload->seat; - if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface) { + if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface_window) { GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus); GHOST_SystemWayland *system = seat->system; /* Calculate this value every time in case modifier keys are pressed. */ @@ -2681,12 +3733,285 @@ static const struct wl_keyboard_listener keyboard_listener = { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Listener (Primary Selection Offer), #zwp_primary_selection_offer_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_PRIMARY_SELECTION_OFFER = {"ghost.wl.handle.primary_selection_offer"}; +#define LOG (&LOG_WL_PRIMARY_SELECTION_OFFER) + +static void primary_selection_offer_offer(void *data, + struct zwp_primary_selection_offer_v1 *id, + const char *type) +{ + GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>(data); + if (data_offer->id != id) { + CLOG_INFO(LOG, 2, "offer: %p: offer for unknown selection %p of %s (skipped)", data, id, type); + return; + } + + data_offer->types.insert(std::string(type)); +} + +static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = { + primary_selection_offer_offer, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Primary Selection Device), #zwp_primary_selection_device_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_PRIMARY_SELECTION_DEVICE = {"ghost.wl.handle.primary_selection_device"}; +#define LOG (&LOG_WL_PRIMARY_SELECTION_DEVICE) + +static void primary_selection_device_handle_data_offer( + void * /*data*/, + struct zwp_primary_selection_device_v1 * /*zwp_primary_selection_device_v1*/, + struct zwp_primary_selection_offer_v1 *id) +{ + CLOG_INFO(LOG, 2, "data_offer"); + + GWL_PrimarySelection_DataOffer *data_offer = new GWL_PrimarySelection_DataOffer; + data_offer->id = id; + zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, data_offer); +} + +static void primary_selection_device_handle_selection( + void *data, + struct zwp_primary_selection_device_v1 * /*zwp_primary_selection_device_v1*/, + struct zwp_primary_selection_offer_v1 *id) +{ + GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data); + + std::lock_guard lock{primary->data_offer_mutex}; + + /* Delete old data offer. */ + if (primary->data_offer != nullptr) { + gwl_primary_selection_discard_offer(primary); + } + + if (id == nullptr) { + CLOG_INFO(LOG, 2, "selection: (skipped)"); + return; + } + CLOG_INFO(LOG, 2, "selection"); + /* Get new data offer. */ + GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>( + zwp_primary_selection_offer_v1_get_user_data(id)); + primary->data_offer = data_offer; +} + +static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = { + primary_selection_device_handle_data_offer, + primary_selection_device_handle_selection, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Listener (Primary Selection Source), #zwp_primary_selection_source_v1_listener + * \{ */ + +static CLG_LogRef LOG_WL_PRIMARY_SELECTION_SOURCE = {"ghost.wl.handle.primary_selection_source"}; +#define LOG (&LOG_WL_PRIMARY_SELECTION_SOURCE) + +static void primary_selection_source_send(void *data, + struct zwp_primary_selection_source_v1 * /*source*/, + const char * /*mime_type*/, + int32_t fd) +{ + CLOG_INFO(LOG, 2, "send"); + + GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data); + + auto write_file_fn = [](GWL_PrimarySelection *primary, const int fd) { + if (UNLIKELY(write(fd, + primary->data_source->buffer_out.data, + primary->data_source->buffer_out.data_size) < 0)) { + CLOG_WARN(LOG, "error writing to primary clipboard: %s", std::strerror(errno)); + } + close(fd); + primary->data_source_mutex.unlock(); + }; + + primary->data_source_mutex.lock(); + std::thread write_thread(write_file_fn, primary, fd); + write_thread.detach(); +} + +static void primary_selection_source_cancelled(void *data, + struct zwp_primary_selection_source_v1 *source) +{ + CLOG_INFO(LOG, 2, "cancelled"); + + GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data); + + if (source == primary->data_source->wp_source) { + gwl_primary_selection_discard_source(primary); + } +} + +static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = { + primary_selection_source_send, + primary_selection_source_cancelled, +}; + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Listener (Seat), #wl_seat_listener * \{ */ static CLG_LogRef LOG_WL_SEAT = {"ghost.wl.handle.seat"}; #define LOG (&LOG_WL_SEAT) +static void gwl_seat_capability_pointer_enable(GWL_Seat *seat) +{ + if (seat->wl_pointer) { + return; + } + seat->wl_pointer = wl_seat_get_pointer(seat->wl_seat); + seat->cursor.wl_surface_cursor = wl_compositor_create_surface(seat->system->wl_compositor()); + seat->cursor.visible = true; + seat->cursor.wl_buffer = nullptr; + if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.theme_size)) { + seat->cursor.theme_name = std::string(); + seat->cursor.theme_size = default_cursor_size; + } + wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat); + + wl_surface_add_listener(seat->cursor.wl_surface_cursor, &cursor_surface_listener, seat); + ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface_cursor); + + zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures(); + if (pointer_gestures) { +#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE + { /* Hold gesture. */ + struct zwp_pointer_gesture_hold_v1 *gesture = zwp_pointer_gestures_v1_get_hold_gesture( + pointer_gestures, seat->wl_pointer); + zwp_pointer_gesture_hold_v1_set_user_data(gesture, seat); + zwp_pointer_gesture_hold_v1_add_listener(gesture, &gesture_hold_listener, seat); + seat->wp_pointer_gesture_hold = gesture; + } +#endif +#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE + { /* Pinch gesture. */ + struct zwp_pointer_gesture_pinch_v1 *gesture = zwp_pointer_gestures_v1_get_pinch_gesture( + pointer_gestures, seat->wl_pointer); + zwp_pointer_gesture_pinch_v1_set_user_data(gesture, seat); + zwp_pointer_gesture_pinch_v1_add_listener(gesture, &gesture_pinch_listener, seat); + seat->wp_pointer_gesture_pinch = gesture; + } +#endif +#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE + { /* Swipe gesture. */ + struct zwp_pointer_gesture_swipe_v1 *gesture = zwp_pointer_gestures_v1_get_swipe_gesture( + pointer_gestures, seat->wl_pointer); + zwp_pointer_gesture_swipe_v1_set_user_data(gesture, seat); + zwp_pointer_gesture_swipe_v1_add_listener(gesture, &gesture_swipe_listener, seat); + seat->wp_pointer_gesture_swipe = gesture; + } +#endif + } +} + +static void gwl_seat_capability_pointer_disable(GWL_Seat *seat) +{ + if (!seat->wl_pointer) { + return; + } + + zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures(); + if (pointer_gestures) { +#ifdef ZWP_POINTER_GESTURE_HOLD_V1_INTERFACE + { /* Hold gesture. */ + struct zwp_pointer_gesture_hold_v1 **gesture_p = &seat->wp_pointer_gesture_hold; + if (*gesture_p) { + zwp_pointer_gesture_hold_v1_destroy(*gesture_p); + *gesture_p = nullptr; + } + } +#endif +#ifdef ZWP_POINTER_GESTURE_PINCH_V1_INTERFACE + { /* Pinch gesture. */ + struct zwp_pointer_gesture_pinch_v1 **gesture_p = &seat->wp_pointer_gesture_pinch; + if (*gesture_p) { + zwp_pointer_gesture_pinch_v1_destroy(*gesture_p); + *gesture_p = nullptr; + } + } +#endif +#ifdef ZWP_POINTER_GESTURE_SWIPE_V1_INTERFACE + { /* Swipe gesture. */ + struct zwp_pointer_gesture_swipe_v1 **gesture_p = &seat->wp_pointer_gesture_swipe; + if (*gesture_p) { + zwp_pointer_gesture_swipe_v1_destroy(*gesture_p); + *gesture_p = nullptr; + } + } +#endif + } + + if (seat->cursor.wl_surface_cursor) { + wl_surface_destroy(seat->cursor.wl_surface_cursor); + seat->cursor.wl_surface_cursor = nullptr; + } + if (seat->cursor.wl_theme) { + wl_cursor_theme_destroy(seat->cursor.wl_theme); + seat->cursor.wl_theme = nullptr; + } + + wl_pointer_destroy(seat->wl_pointer); + seat->wl_pointer = nullptr; +} + +static void gwl_seat_capability_keyboard_enable(GWL_Seat *seat) +{ + if (seat->wl_keyboard) { + return; + } + seat->wl_keyboard = wl_seat_get_keyboard(seat->wl_seat); + wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, seat); +} + +static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat) +{ + if (!seat->wl_keyboard) { + return; + } + if (seat->key_repeat.timer) { + keyboard_handle_key_repeat_cancel(seat); + } + wl_keyboard_destroy(seat->wl_keyboard); + seat->wl_keyboard = nullptr; +} + +static void gwl_seat_capability_touch_enable(GWL_Seat *seat) +{ + if (seat->wl_touch) { + return; + } + seat->wl_touch = wl_seat_get_touch(seat->wl_seat); + wl_touch_set_user_data(seat->wl_touch, seat); + wl_touch_add_listener(seat->wl_touch, &touch_seat_listener, seat); +} + +static void gwl_seat_capability_touch_disable(GWL_Seat *seat) +{ + if (!seat->wl_touch) { + return; + } + wl_touch_destroy(seat->wl_touch); + seat->wl_touch = nullptr; +} + static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, const uint32_t capabilities) @@ -2699,27 +4024,27 @@ static void seat_handle_capabilities(void *data, (capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0); GWL_Seat *seat = static_cast<GWL_Seat *>(data); - seat->wl_pointer = nullptr; - seat->wl_keyboard = nullptr; + GHOST_ASSERT(seat->wl_seat == wl_seat, "Seat mismatch"); if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - seat->wl_pointer = wl_seat_get_pointer(wl_seat); - seat->cursor.wl_surface = wl_compositor_create_surface(seat->system->wl_compositor()); - seat->cursor.visible = true; - seat->cursor.wl_buffer = nullptr; - if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.size)) { - seat->cursor.theme_name = std::string(); - seat->cursor.size = default_cursor_size; - } - wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, data); - - wl_surface_add_listener(seat->cursor.wl_surface, &cursor_surface_listener, data); - ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface); + gwl_seat_capability_pointer_enable(seat); + } + else { + gwl_seat_capability_pointer_disable(seat); } if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - seat->wl_keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, data); + gwl_seat_capability_keyboard_enable(seat); + } + else { + gwl_seat_capability_keyboard_disable(seat); + } + + if (capabilities & WL_SEAT_CAPABILITY_TOUCH) { + gwl_seat_capability_touch_enable(seat); + } + else { + gwl_seat_capability_touch_disable(seat); } } @@ -2929,11 +4254,17 @@ static void output_handle_done(void *data, struct wl_output * /*wl_output*/) static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, const int32_t factor) { CLOG_INFO(LOG, 2, "scale"); - static_cast<GWL_Output *>(data)->scale = factor; + GWL_Output *output = static_cast<GWL_Output *>(data); + output->scale = factor; + GHOST_WindowManager *window_manager = output->system->getWindowManager(); if (window_manager) { for (GHOST_IWindow *iwin : window_manager->getWindows()) { GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin); + const std::vector<GWL_Output *> &outputs = win->outputs(); + if (std::find(outputs.begin(), outputs.end(), output) == outputs.cend()) { + continue; + } win->outputs_changed_update_scale(); } } @@ -3011,89 +4342,573 @@ static struct libdecor_interface libdecor_interface = { static CLG_LogRef LOG_WL_REGISTRY = {"ghost.wl.handle.registry"}; #define LOG (&LOG_WL_REGISTRY) -static void global_handle_add(void *data, - struct wl_registry *wl_registry, - const uint32_t name, - const char *interface, - const uint32_t version) +/* #GWL_Display.wl_compositor */ + +static void gwl_registry_compositor_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + display->wl_compositor = static_cast<wl_compositor *>( + wl_registry_bind(display->wl_registry, params->name, &wl_compositor_interface, 3)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_compositor_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct wl_compositor **value_p = &display->wl_compositor; + wl_compositor_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.xdg_decor.shell */ + +static void gwl_registry_xdg_wm_base_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + GWL_XDG_Decor_System &decor = *display->xdg_decor; + decor.shell = static_cast<xdg_wm_base *>( + wl_registry_bind(display->wl_registry, params->name, &xdg_wm_base_interface, 1)); + xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr); + decor.shell_name = params->name; + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_xdg_wm_base_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + GWL_XDG_Decor_System &decor = *display->xdg_decor; + struct xdg_wm_base **value_p = &decor.shell; + uint32_t *name_p = &decor.shell_name; + xdg_wm_base_destroy(*value_p); + *value_p = nullptr; + *name_p = WL_NAME_UNSET; +} + +/* #GWL_Display.xdg_decor.manager */ + +static void gwl_registry_xdg_decoration_manager_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + GWL_XDG_Decor_System &decor = *display->xdg_decor; + decor.manager = static_cast<zxdg_decoration_manager_v1 *>(wl_registry_bind( + display->wl_registry, params->name, &zxdg_decoration_manager_v1_interface, 1)); + decor.manager_name = params->name; + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_xdg_decoration_manager_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + GWL_XDG_Decor_System &decor = *display->xdg_decor; + struct zxdg_decoration_manager_v1 **value_p = &decor.manager; + uint32_t *name_p = &decor.manager_name; + zxdg_decoration_manager_v1_destroy(*value_p); + *value_p = nullptr; + *name_p = WL_NAME_UNSET; +} + +/* #GWL_Display.xdg_output_manager */ + +static void gwl_registry_xdg_output_manager_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>( + wl_registry_bind(display->wl_registry, params->name, &zxdg_output_manager_v1_interface, 2)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_xdg_output_manager_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct zxdg_output_manager_v1 **value_p = &display->xdg_output_manager; + zxdg_output_manager_v1_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.wl_output */ + +static void gwl_registry_wl_output_add(GWL_Display *display, const GWL_RegisteryAdd_Params *params) +{ + GWL_Output *output = new GWL_Output; + output->system = display->system; + output->wl_output = static_cast<wl_output *>( + wl_registry_bind(display->wl_registry, params->name, &wl_output_interface, 2)); + ghost_wl_output_tag(output->wl_output); + wl_output_set_user_data(output->wl_output, output); + + display->outputs.push_back(output); + wl_output_add_listener(output->wl_output, &output_listener, output); + gwl_registry_entry_add(display, params, static_cast<void *>(output)); +} +static void gwl_registry_wl_output_update(GWL_Display *display, + const GWL_RegisteryUpdate_Params *params) { - /* Log last since it can be noted if the interface was handled or not. */ - bool found = true; - - struct GWL_Display *display = static_cast<struct GWL_Display *>(data); - if (STREQ(interface, wl_compositor_interface.name)) { - display->wl_compositor = static_cast<wl_compositor *>( - wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3)); - } - else if (STREQ(interface, xdg_wm_base_interface.name)) { - WGL_XDG_Decor_System &decor = *display->xdg_decor; - decor.shell = static_cast<xdg_wm_base *>( - wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1)); - xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr); - } - else if (STREQ(interface, zxdg_decoration_manager_v1_interface.name)) { - WGL_XDG_Decor_System &decor = *display->xdg_decor; - decor.manager = static_cast<zxdg_decoration_manager_v1 *>( - wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1)); - } - else if (STREQ(interface, zxdg_output_manager_v1_interface.name)) { - display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>( - wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 2)); - for (GWL_Output *output : display->outputs) { + GWL_Output *output = static_cast<GWL_Output *>(params->user_data); + if (display->xdg_output_manager) { + if (output->xdg_output == nullptr) { output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager, output->wl_output); zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); } } - else if (STREQ(interface, wl_output_interface.name)) { - GWL_Output *output = new GWL_Output; - output->wl_output = static_cast<wl_output *>( - wl_registry_bind(wl_registry, name, &wl_output_interface, 2)); - ghost_wl_output_tag(output->wl_output); - wl_output_set_user_data(output->wl_output, output); + else { + output->xdg_output = nullptr; + } +} +static void gwl_registry_wl_output_remove(GWL_Display *display, + void *user_data, + const bool /*on_exit*/) +{ + /* While windows & cursors hold references to outputs, there is no need to manually remove + * these references as the compositor will remove references via #wl_surface_listener.leave. */ + GWL_Output *output = static_cast<GWL_Output *>(user_data); + wl_output_destroy(output->wl_output); + std::vector<GWL_Output *>::iterator iter = std::find( + display->outputs.begin(), display->outputs.end(), output); + const int index = (iter != display->outputs.cend()) ? + std::distance(display->outputs.begin(), iter) : + -1; + GHOST_ASSERT(index != -1, "invalid internal state"); + /* NOTE: always erase even when `on_exit` because `output->xdg_output` is cleared later. */ + display->outputs.erase(display->outputs.begin() + index); + delete output; +} + +/* #GWL_Display.seats */ + +static void gwl_registry_wl_seat_add(GWL_Display *display, const GWL_RegisteryAdd_Params *params) +{ + GWL_Seat *seat = new GWL_Seat; + seat->system = display->system; + seat->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + seat->data_source = new GWL_DataSource; + seat->wl_seat = static_cast<wl_seat *>( + wl_registry_bind(display->wl_registry, params->name, &wl_seat_interface, 5)); + display->seats.push_back(seat); + wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); + gwl_registry_entry_add(display, params, static_cast<void *>(seat)); +} +static void gwl_registry_wl_seat_update(GWL_Display *display, + const GWL_RegisteryUpdate_Params *params) +{ + GWL_Seat *seat = static_cast<GWL_Seat *>(params->user_data); + + /* Register data device per seat for IPC between WAYLAND clients. */ + if (display->wl_data_device_manager) { + if (seat->wl_data_device == nullptr) { + seat->wl_data_device = wl_data_device_manager_get_data_device( + display->wl_data_device_manager, seat->wl_seat); + wl_data_device_add_listener(seat->wl_data_device, &data_device_listener, seat); + } + } + else { + seat->wl_data_device = nullptr; + } - display->outputs.push_back(output); - wl_output_add_listener(output->wl_output, &output_listener, output); + if (display->wp_tablet_manager) { + if (seat->wp_tablet_seat == nullptr) { + seat->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display->wp_tablet_manager, + seat->wl_seat); + zwp_tablet_seat_v2_add_listener(seat->wp_tablet_seat, &tablet_seat_listener, seat); + } + } + else { + seat->wp_tablet_seat = nullptr; + } - if (display->xdg_output_manager) { - output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager, - output->wl_output); - zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); + if (display->wp_primary_selection_device_manager) { + if (seat->wp_primary_selection_device == nullptr) { + seat->wp_primary_selection_device = zwp_primary_selection_device_manager_v1_get_device( + display->wp_primary_selection_device_manager, seat->wl_seat); + + zwp_primary_selection_device_v1_add_listener(seat->wp_primary_selection_device, + &primary_selection_device_listener, + &seat->primary_selection); + } + } + else { + seat->wp_primary_selection_device = nullptr; + } +} +static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, const bool on_exit) +{ + GWL_Seat *seat = static_cast<GWL_Seat *>(user_data); + + /* First handle members that require locking. + * While highly unlikely, it's possible they are being used while this function runs. */ + { + std::lock_guard lock{seat->data_source_mutex}; + if (seat->data_source) { + gwl_simple_buffer_free_data(&seat->data_source->buffer_out); + if (seat->data_source->wl_source) { + wl_data_source_destroy(seat->data_source->wl_source); + } + delete seat->data_source; + } + } + + { + std::lock_guard lock{seat->data_offer_dnd_mutex}; + if (seat->data_offer_dnd) { + wl_data_offer_destroy(seat->data_offer_dnd->id); + delete seat->data_offer_dnd; + } + } + + { + std::lock_guard lock{seat->data_offer_copy_paste_mutex}; + if (seat->data_offer_copy_paste) { + wl_data_offer_destroy(seat->data_offer_copy_paste->id); + delete seat->data_offer_copy_paste; } } - else if (STREQ(interface, wl_seat_interface.name)) { - GWL_Seat *seat = new GWL_Seat; - seat->system = display->system; - seat->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - seat->data_source = new GWL_DataSource; - seat->wl_seat = static_cast<wl_seat *>( - wl_registry_bind(wl_registry, name, &wl_seat_interface, 5)); - display->seats.push_back(seat); - wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); + + { + GWL_PrimarySelection *primary = &seat->primary_selection; + std::lock_guard lock{primary->data_offer_mutex}; + gwl_primary_selection_discard_offer(primary); } - else if (STREQ(interface, wl_shm_interface.name)) { - display->wl_shm = static_cast<wl_shm *>( - wl_registry_bind(wl_registry, name, &wl_shm_interface, 1)); + + { + GWL_PrimarySelection *primary = &seat->primary_selection; + std::lock_guard lock{primary->data_source_mutex}; + gwl_primary_selection_discard_source(primary); } - else if (STREQ(interface, wl_data_device_manager_interface.name)) { - display->data_device_manager = static_cast<wl_data_device_manager *>( - wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3)); + + if (seat->wp_primary_selection_device) { + zwp_primary_selection_device_v1_destroy(seat->wp_primary_selection_device); } - else if (STREQ(interface, zwp_tablet_manager_v2_interface.name)) { - display->tablet_manager = static_cast<zwp_tablet_manager_v2 *>( - wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1)); + + if (seat->wl_data_device) { + wl_data_device_release(seat->wl_data_device); } - else if (STREQ(interface, zwp_relative_pointer_manager_v1_interface.name)) { - display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>( - wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1)); + + if (seat->cursor.custom_data) { + munmap(seat->cursor.custom_data, seat->cursor.custom_data_size); } - else if (STREQ(interface, zwp_pointer_constraints_v1_interface.name)) { - display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>( - wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1)); + + /* Disable all capabilities as a way to free: + * - `seat.wl_pointer` (and related cursor variables). + * - `seat.wl_touch`. + * - `seat.wl_keyboard`. + */ + gwl_seat_capability_pointer_disable(seat); + gwl_seat_capability_keyboard_disable(seat); + gwl_seat_capability_touch_disable(seat); + + /* Un-referencing checks for NULL case. */ + xkb_state_unref(seat->xkb_state); + xkb_state_unref(seat->xkb_state_empty); + xkb_state_unref(seat->xkb_state_empty_with_shift); + xkb_state_unref(seat->xkb_state_empty_with_numlock); + + xkb_context_unref(seat->xkb_context); + + /* Remove the seat. */ + wl_seat_destroy(seat->wl_seat); + + std::vector<GWL_Seat *>::iterator iter = std::find( + display->seats.begin(), display->seats.end(), seat); + const int index = (iter != display->seats.cend()) ? std::distance(display->seats.begin(), iter) : + -1; + GHOST_ASSERT(index != -1, "invalid internal state"); + + if (!on_exit) { + if (display->seats_active_index >= index) { + display->seats_active_index -= 1; + } + display->seats.erase(display->seats.begin() + index); } - else { - found = false; + delete seat; +} + +/* #GWL_Display.wl_shm */ +static void gwl_registry_wl_shm_add(GWL_Display *display, const GWL_RegisteryAdd_Params *params) +{ + display->wl_shm = static_cast<wl_shm *>( + wl_registry_bind(display->wl_registry, params->name, &wl_shm_interface, 1)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_wl_shm_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct wl_shm **value_p = &display->wl_shm; + wl_shm_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.wl_data_device_manager */ + +static void gwl_registry_wl_data_device_manager_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + display->wl_data_device_manager = static_cast<wl_data_device_manager *>( + wl_registry_bind(display->wl_registry, params->name, &wl_data_device_manager_interface, 3)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_wl_data_device_manager_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct wl_data_device_manager **value_p = &display->wl_data_device_manager; + wl_data_device_manager_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.wp_tablet_manager */ + +static void gwl_registry_wp_tablet_manager_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + display->wp_tablet_manager = static_cast<zwp_tablet_manager_v2 *>( + wl_registry_bind(display->wl_registry, params->name, &zwp_tablet_manager_v2_interface, 1)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_wp_tablet_manager_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct zwp_tablet_manager_v2 **value_p = &display->wp_tablet_manager; + zwp_tablet_manager_v2_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.wp_relative_pointer_manager */ + +static void gwl_registry_wp_relative_pointer_manager_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + display->wp_relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>( + wl_registry_bind( + display->wl_registry, params->name, &zwp_relative_pointer_manager_v1_interface, 1)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_wp_relative_pointer_manager_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct zwp_relative_pointer_manager_v1 **value_p = &display->wp_relative_pointer_manager; + zwp_relative_pointer_manager_v1_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.wp_pointer_constraints */ + +static void gwl_registry_wp_pointer_constraints_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + display->wp_pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(wl_registry_bind( + display->wl_registry, params->name, &zwp_pointer_constraints_v1_interface, 1)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_wp_pointer_constraints_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct zwp_pointer_constraints_v1 **value_p = &display->wp_pointer_constraints; + zwp_pointer_constraints_v1_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.wp_pointer_gestures */ + +static void gwl_registry_wp_pointer_gestures_add(GWL_Display *display, + const GWL_RegisteryAdd_Params *params) +{ + display->wp_pointer_gestures = static_cast<zwp_pointer_gestures_v1 *>( + wl_registry_bind(display->wl_registry, params->name, &zwp_pointer_gestures_v1_interface, 3)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_wp_pointer_gestures_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct zwp_pointer_gestures_v1 **value_p = &display->wp_pointer_gestures; + zwp_pointer_gestures_v1_destroy(*value_p); + *value_p = nullptr; +} + +/* #GWL_Display.wp_primary_selection_device_manager */ + +static void gwl_registry_wp_primary_selection_device_manager_add( + struct GWL_Display *display, const GWL_RegisteryAdd_Params *params) +{ + display->wp_primary_selection_device_manager = + static_cast<zwp_primary_selection_device_manager_v1 *>( + wl_registry_bind(display->wl_registry, + params->name, + &zwp_primary_selection_device_manager_v1_interface, + 1)); + gwl_registry_entry_add(display, params, nullptr); +} +static void gwl_registry_wp_primary_selection_device_manager_remove(GWL_Display *display, + void * /*user_data*/, + const bool /*on_exit*/) +{ + struct zwp_primary_selection_device_manager_v1 **value_p = + &display->wp_primary_selection_device_manager; + zwp_primary_selection_device_manager_v1_destroy(*value_p); + *value_p = nullptr; +} + +/** + * Map interfaces to initialization functions. + * + * \note This list also defines the order interfaces are removed. + * On exit interface removal runs from last to first to avoid potential bugs + * caused by undefined order of removal. + * + * In general fundamental, low level objects such as the compositor and shared memory + * should be declared earlier and other interfaces that may use them should be declared later. + */ +static const GWL_RegistryHandler gwl_registry_handlers[] = { + /* Low level interfaces. */ + { + &wl_compositor_interface.name, + gwl_registry_compositor_add, + nullptr, + gwl_registry_compositor_remove, + }, + { + &wl_shm_interface.name, + gwl_registry_wl_shm_add, + nullptr, + gwl_registry_wl_shm_remove, + }, + { + &xdg_wm_base_interface.name, + gwl_registry_xdg_wm_base_add, + nullptr, + gwl_registry_xdg_wm_base_remove, + }, + /* Managers. */ + { + &zxdg_decoration_manager_v1_interface.name, + gwl_registry_xdg_decoration_manager_add, + nullptr, + gwl_registry_xdg_decoration_manager_remove, + }, + { + &zxdg_output_manager_v1_interface.name, + gwl_registry_xdg_output_manager_add, + nullptr, + gwl_registry_xdg_output_manager_remove, + }, + { + &wl_data_device_manager_interface.name, + gwl_registry_wl_data_device_manager_add, + nullptr, + gwl_registry_wl_data_device_manager_remove, + }, + { + &zwp_primary_selection_device_manager_v1_interface.name, + gwl_registry_wp_primary_selection_device_manager_add, + nullptr, + gwl_registry_wp_primary_selection_device_manager_remove, + }, + { + &zwp_tablet_manager_v2_interface.name, + gwl_registry_wp_tablet_manager_add, + nullptr, + gwl_registry_wp_tablet_manager_remove, + }, + { + &zwp_relative_pointer_manager_v1_interface.name, + gwl_registry_wp_relative_pointer_manager_add, + nullptr, + gwl_registry_wp_relative_pointer_manager_remove, + }, + /* Higher level interfaces. */ + { + &zwp_pointer_constraints_v1_interface.name, + gwl_registry_wp_pointer_constraints_add, + nullptr, + gwl_registry_wp_pointer_constraints_remove, + }, + { + &zwp_pointer_gestures_v1_interface.name, + gwl_registry_wp_pointer_gestures_add, + nullptr, + gwl_registry_wp_pointer_gestures_remove, + }, + /* Display outputs. */ + { + &wl_output_interface.name, + gwl_registry_wl_output_add, + gwl_registry_wl_output_update, + gwl_registry_wl_output_remove, + }, + /* Seats. + * Keep the seat near the end to ensure other types are created first. + * as the seat creates data based on other interfaces. */ + { + &wl_seat_interface.name, + gwl_registry_wl_seat_add, + gwl_registry_wl_seat_update, + gwl_registry_wl_seat_remove, + }, + {nullptr, nullptr, nullptr}, +}; + +/** + * Workaround for `gwl_registry_handlers` order of declaration, + * preventing `ARRAY_SIZE(gwl_registry_handlers) - 1` being used. + */ +static int gwl_registry_handler_interface_slot_max() +{ + return ARRAY_SIZE(gwl_registry_handlers) - 1; +} + +static int gwl_registry_handler_interface_slot_from_string(const char *interface) +{ + for (const GWL_RegistryHandler *handler = gwl_registry_handlers; handler->interface_p != nullptr; + handler++) { + if (STREQ(interface, *handler->interface_p)) { + return int(handler - gwl_registry_handlers); + } + } + return -1; +} + +static const GWL_RegistryHandler *gwl_registry_handler_from_interface_slot(int interface_slot) +{ + GHOST_ASSERT(uint32_t(interface_slot) < uint32_t(gwl_registry_handler_interface_slot_max()), + "Index out of range"); + return &gwl_registry_handlers[interface_slot]; +} + +static void global_handle_add(void *data, + [[maybe_unused]] struct wl_registry *wl_registry, + const uint32_t name, + const char *interface, + const uint32_t version) +{ + /* Log last since it's useful to know if the interface was handled or not. */ + GWL_Display *display = static_cast<GWL_Display *>(data); + GHOST_ASSERT(display->wl_registry == wl_registry, "Registry argument must match!"); + + const int interface_slot = gwl_registry_handler_interface_slot_from_string(interface); + bool added = false; + + if (interface_slot != -1) { + const GWL_RegistryHandler *handler = &gwl_registry_handlers[interface_slot]; + const GWL_RegistryEntry *registry_entry_prev = display->registry_entry; + + /* The interface name that is ensured not to be freed. */ + GWL_RegisteryAdd_Params params = { + .name = name, + .interface_slot = interface_slot, + .version = version, + }; + + handler->add_fn(display, ¶ms); + + added = display->registry_entry != registry_entry_prev; + } + else { + /* Not found. */ #ifdef USE_GNOME_NEEDS_LIBDECOR_HACK if (STRPREFIX(interface, "gtk_shell")) { /* `gtk_shell1` at time of writing. */ /* Only require `libdecor` when built with X11 support, @@ -3106,10 +4921,18 @@ static void global_handle_add(void *data, CLOG_INFO(LOG, 2, "add %s(interface=%s, version=%u, name=%u)", - found ? "" : "(skipped), ", + (interface_slot != -1) ? (added ? "" : "(found but not added)") : "(skipped), ", interface, version, name); + + /* Initialization avoids excessive calls by calling update after all have been initialized. */ + if (added) { + if (display->registry_skip_update_all == false) { + /* See doc-string for rationale on updating all on add/removal. */ + gwl_registry_entry_update_all(display, interface_slot); + } + } } /** @@ -3121,11 +4944,28 @@ static void global_handle_add(void *data, * name is no longer available. If the client bound to the global * using the bind request, the client should now destroy that object. */ -static void global_handle_remove(void * /*data*/, - struct wl_registry * /*wl_registry*/, +static void global_handle_remove(void *data, + [[maybe_unused]] struct wl_registry *wl_registry, const uint32_t name) { - CLOG_INFO(LOG, 2, "remove (name=%u)", name); + GWL_Display *display = static_cast<GWL_Display *>(data); + GHOST_ASSERT(display->wl_registry == wl_registry, "Registry argument must match!"); + + int interface_slot = 0; + const bool removed = gwl_registry_entry_remove_by_name(display, name, &interface_slot); + + CLOG_INFO(LOG, + 2, + "remove (name=%u, interface=%s)", + name, + removed ? *gwl_registry_handlers[interface_slot].interface_p : "(unknown)"); + + if (removed) { + if (display->registry_skip_update_all == false) { + /* See doc-string for rationale on updating all on add/removal. */ + gwl_registry_entry_update_all(display, interface_slot); + } + } } static const struct wl_registry_listener registry_listener = { @@ -3143,7 +4983,8 @@ static const struct wl_registry_listener registry_listener = { * WAYLAND specific implementation of the #GHOST_System interface. * \{ */ -GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Display) +GHOST_SystemWayland::GHOST_SystemWayland(bool background) + : GHOST_System(), display_(new GWL_Display) { wl_log_set_handler_client(ghost_wayland_log_handler); @@ -3151,25 +4992,41 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di /* Connect to the Wayland server. */ display_->wl_display = wl_display_connect(nullptr); if (!display_->wl_display) { - display_destroy(display_); + gwl_display_destroy(display_); throw std::runtime_error("Wayland: unable to connect to display!"); } /* This may be removed later if decorations are required, needed as part of registration. */ - display_->xdg_decor = new WGL_XDG_Decor_System; + display_->xdg_decor = new GWL_XDG_Decor_System; /* Register interfaces. */ - struct wl_registry *registry = wl_display_get_registry(display_->wl_display); - wl_registry_add_listener(registry, ®istry_listener, display_); - /* Call callback for registry listener. */ - wl_display_roundtrip(display_->wl_display); - /* Call callbacks for registered listeners. */ - wl_display_roundtrip(display_->wl_display); - wl_registry_destroy(registry); + { + display_->registry_skip_update_all = true; + struct wl_registry *registry = wl_display_get_registry(display_->wl_display); + display_->wl_registry = registry; + wl_registry_add_listener(registry, ®istry_listener, display_); + /* First round-trip to receive all registry objects. */ + wl_display_roundtrip(display_->wl_display); + /* Second round-trip to receive all output events. */ + wl_display_roundtrip(display_->wl_display); + + /* Account for dependencies between interfaces. */ + gwl_registry_entry_update_all(display_, -1); + + display_->registry_skip_update_all = false; + } #ifdef WITH_GHOST_WAYLAND_LIBDECOR + /* Ignore windowing requirements when running in background mode, + * as it doesn't make sense to fall back to X11 because of windowing functionality + * in background mode, also LIBDECOR is crashing in background mode `blender -b -f 1` + * for e.g. while it could be fixed, requiring the library at all makes no sense . */ + if (background) { + display_->libdecor_required = false; + } + if (display_->libdecor_required) { - wgl_xdg_decor_system_destroy(display_->xdg_decor); + gwl_xdg_decor_system_destroy(display_, display_->xdg_decor); display_->xdg_decor = nullptr; if (!has_libdecor) { @@ -3179,8 +5036,10 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di "WAYLAND found but libdecor was not, install libdecor for Wayland support, " "falling back to X11\n"); # endif - display_destroy(display_); + gwl_display_destroy(display_); throw std::runtime_error("Wayland: unable to find libdecor!"); + + use_libdecor = true; } } else { @@ -3190,45 +5049,28 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), display_(new GWL_Di #ifdef WITH_GHOST_WAYLAND_LIBDECOR if (use_libdecor) { - display_->libdecor = new WGL_LibDecor_System; - WGL_LibDecor_System &decor = *display_->libdecor; + display_->libdecor = new GWL_LibDecor_System; + GWL_LibDecor_System &decor = *display_->libdecor; decor.context = libdecor_new(display_->wl_display, &libdecor_interface); if (!decor.context) { - display_destroy(display_); + gwl_display_destroy(display_); throw std::runtime_error("Wayland: unable to create window decorations!"); } } else #endif { - WGL_XDG_Decor_System &decor = *display_->xdg_decor; + GWL_XDG_Decor_System &decor = *display_->xdg_decor; if (!decor.shell) { - display_destroy(display_); + gwl_display_destroy(display_); throw std::runtime_error("Wayland: unable to access xdg_shell!"); } } - - /* Register data device per seat for IPC between Wayland clients. */ - if (display_->data_device_manager) { - for (GWL_Seat *seat : display_->seats) { - seat->data_device = wl_data_device_manager_get_data_device(display_->data_device_manager, - seat->wl_seat); - wl_data_device_add_listener(seat->data_device, &data_device_listener, seat); - } - } - - if (display_->tablet_manager) { - for (GWL_Seat *seat : display_->seats) { - seat->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display_->tablet_manager, - seat->wl_seat); - zwp_tablet_seat_v2_add_listener(seat->tablet_seat, &tablet_seat_listener, seat); - } - } } GHOST_SystemWayland::~GHOST_SystemWayland() { - display_destroy(display_); + gwl_display_destroy(display_); } GHOST_TSuccess GHOST_SystemWayland::init() @@ -3283,12 +5125,11 @@ bool GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*acti GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Seat *seat = display_->seats[0]; - const xkb_mod_mask_t state = xkb_state_serialize_mods(seat->xkb_state, XKB_STATE_MODS_DEPRESSED); bool show_warning = true; @@ -3300,7 +5141,7 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co } #endif - /* Use local #WGL_KeyboardDepressedState to check which key is pressed. + /* Use local #GWL_KeyboardDepressedState to check which key is pressed. * Use XKB as the source of truth, if there is any discrepancy. */ for (int i = 0; i < MOD_INDEX_NUM; i++) { if (UNLIKELY(seat->xkb_keymap_mod_index[i] == XKB_MOD_INVALID)) { @@ -3345,11 +5186,11 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Seat *seat = display_->seats[0]; - GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat); + GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat); if (!seat_state_pointer) { return GHOST_kFailure; } @@ -3358,43 +5199,208 @@ GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const return GHOST_kSuccess; } -char *GHOST_SystemWayland::getClipboard(bool /*selection*/) const +/** + * Return a mime type which is supported by GHOST and exists in `types` + * (defined by the data offer). + */ +static const char *system_clipboard_text_mime_type( + const std::unordered_set<std::string> &data_offer_types) +{ + const char *ghost_supported_types[] = {ghost_wl_mime_text_utf8, ghost_wl_mime_text_plain}; + for (size_t i = 0; i < ARRAY_SIZE(ghost_supported_types); i++) { + if (data_offer_types.count(ghost_supported_types[i])) { + return ghost_supported_types[i]; + } + } + return nullptr; +} + +static char *system_clipboard_get_primary_selection(GWL_Display *display) +{ + GWL_Seat *seat = gwl_display_seat_active_get(display); + if (UNLIKELY(!seat)) { + return nullptr; + } + GWL_PrimarySelection *primary = &seat->primary_selection; + std::mutex &mutex = primary->data_offer_mutex; + + mutex.lock(); + bool mutex_locked = true; + char *data = nullptr; + + GWL_PrimarySelection_DataOffer *data_offer = primary->data_offer; + if (data_offer != nullptr) { + const char *mime_receive = system_clipboard_text_mime_type(data_offer->types); + if (mime_receive) { + /* Receive the clipboard in a thread, performing round-trips while waiting. + * This is needed so pasting contents from our own `primary->data_source` doesn't hang. */ + struct ThreadResult { + char *data = nullptr; + std::atomic<bool> done = false; + } thread_result; + auto read_clipboard_fn = [](GWL_PrimarySelection_DataOffer *data_offer, + const char *mime_receive, + std::mutex *mutex, + struct ThreadResult *thread_result) { + size_t data_len = 0; + thread_result->data = read_buffer_from_primary_selection_offer( + data_offer, mime_receive, mutex, true, &data_len); + thread_result->done = true; + }; + std::thread read_thread(read_clipboard_fn, data_offer, mime_receive, &mutex, &thread_result); + read_thread.detach(); + + while (!thread_result.done) { + wl_display_roundtrip(display->wl_display); + } + data = thread_result.data; + + /* Reading the data offer unlocks the mutex. */ + mutex_locked = false; + } + } + if (mutex_locked) { + mutex.unlock(); + } + return data; +} + +static char *system_clipboard_get(GWL_Display *display) +{ + GWL_Seat *seat = gwl_display_seat_active_get(display); + if (UNLIKELY(!seat)) { + return nullptr; + } + std::mutex &mutex = seat->data_offer_copy_paste_mutex; + + mutex.lock(); + bool mutex_locked = true; + char *data = nullptr; + + GWL_DataOffer *data_offer = seat->data_offer_copy_paste; + if (data_offer != nullptr) { + const char *mime_receive = system_clipboard_text_mime_type(data_offer->types); + if (mime_receive) { + /* Receive the clipboard in a thread, performing round-trips while waiting. + * This is needed so pasting contents from our own `seat->data_source` doesn't hang. */ + struct ThreadResult { + char *data = nullptr; + std::atomic<bool> done = false; + } thread_result; + auto read_clipboard_fn = [](GWL_DataOffer *data_offer, + const char *mime_receive, + std::mutex *mutex, + struct ThreadResult *thread_result) { + size_t data_len = 0; + thread_result->data = read_buffer_from_data_offer( + data_offer, mime_receive, mutex, true, &data_len); + thread_result->done = true; + }; + std::thread read_thread(read_clipboard_fn, data_offer, mime_receive, &mutex, &thread_result); + read_thread.detach(); + + while (!thread_result.done) { + wl_display_roundtrip(display->wl_display); + } + data = thread_result.data; + + /* Reading the data offer unlocks the mutex. */ + mutex_locked = false; + } + } + if (mutex_locked) { + mutex.unlock(); + } + return data; +} + +char *GHOST_SystemWayland::getClipboard(bool selection) const { - char *clipboard = static_cast<char *>(malloc(clipboard_.size() + 1)); - memcpy(clipboard, clipboard_.data(), clipboard_.size() + 1); - return clipboard; + char *data = nullptr; + if (selection) { + data = system_clipboard_get_primary_selection(display_); + } + else { + data = system_clipboard_get(display_); + } + return data; } -void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) const +static void system_clipboard_put_primary_selection(GWL_Display *display, const char *buffer) { - if (UNLIKELY(!display_->data_device_manager || display_->seats.empty())) { + if (!display->wp_primary_selection_device_manager) { + return; + } + GWL_Seat *seat = gwl_display_seat_active_get(display); + if (UNLIKELY(!seat)) { return; } + GWL_PrimarySelection *primary = &seat->primary_selection; + + std::lock_guard lock{primary->data_source_mutex}; + + gwl_primary_selection_discard_source(primary); + + GWL_PrimarySelection_DataSource *data_source = new GWL_PrimarySelection_DataSource; + primary->data_source = data_source; + + /* Copy buffer. */ + gwl_simple_buffer_set_from_string(&data_source->buffer_out, buffer); + + data_source->wp_source = zwp_primary_selection_device_manager_v1_create_source( + display->wp_primary_selection_device_manager); + + zwp_primary_selection_source_v1_add_listener( + data_source->wp_source, &primary_selection_source_listener, primary); + + for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_send); i++) { + zwp_primary_selection_source_v1_offer(data_source->wp_source, ghost_wl_mime_send[i]); + } - GWL_Seat *seat = display_->seats[0]; + if (seat->wp_primary_selection_device) { + zwp_primary_selection_device_v1_set_selection( + seat->wp_primary_selection_device, data_source->wp_source, seat->data_source_serial); + } +} +static void system_clipboard_put(GWL_Display *display, const char *buffer) +{ + if (!display->wl_data_device_manager) { + return; + } + GWL_Seat *seat = gwl_display_seat_active_get(display); + if (UNLIKELY(!seat)) { + return; + } std::lock_guard lock{seat->data_source_mutex}; GWL_DataSource *data_source = seat->data_source; /* Copy buffer. */ - free(data_source->buffer_out); - const size_t buffer_size = strlen(buffer) + 1; - data_source->buffer_out = static_cast<char *>(malloc(buffer_size)); - std::memcpy(data_source->buffer_out, buffer, buffer_size); + gwl_simple_buffer_set_from_string(&data_source->buffer_out, buffer); - data_source->data_source = wl_data_device_manager_create_data_source( - display_->data_device_manager); + data_source->wl_source = wl_data_device_manager_create_data_source( + display->wl_data_device_manager); - wl_data_source_add_listener(data_source->data_source, &data_source_listener, seat); + wl_data_source_add_listener(data_source->wl_source, &data_source_listener, seat); - for (const std::string &type : mime_send) { - wl_data_source_offer(data_source->data_source, type.c_str()); + for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_send); i++) { + wl_data_source_offer(data_source->wl_source, ghost_wl_mime_send[i]); } - if (seat->data_device) { + if (seat->wl_data_device) { wl_data_device_set_selection( - seat->data_device, data_source->data_source, seat->data_source_serial); + seat->wl_data_device, data_source->wl_source, seat->data_source_serial); + } +} + +void GHOST_SystemWayland::putClipboard(const char *buffer, bool selection) const +{ + if (selection) { + system_clipboard_put_primary_selection(display_, buffer); + } + else { + system_clipboard_put(display_, buffer); } } @@ -3423,7 +5429,7 @@ static GHOST_TSuccess setCursorPositionClientRelative_impl(GWL_Seat *seat, /* NOTE: WAYLAND doesn't support warping the cursor. * However when grab is enabled, we already simulate a cursor location * so that can be set to a new location. */ - if (!seat->relative_pointer) { + if (!seat->wp_relative_pointer) { return GHOST_kFailure; } const wl_fixed_t scale = win->scale(); @@ -3442,12 +5448,12 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPositionClientRelative(const GHOST_ int32_t &x, int32_t &y) const { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Seat *seat = display_->seats[0]; - GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat); - if (!seat_state_pointer || !seat_state_pointer->wl_surface) { + GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat); + if (!seat_state_pointer || !seat_state_pointer->wl_surface_window) { return GHOST_kFailure; } const GHOST_WindowWayland *win = static_cast<const GHOST_WindowWayland *>(window); @@ -3458,26 +5464,26 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorPositionClientRelative(GHOST_IWindo const int32_t x, const int32_t y) { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Seat *seat = display_->seats[0]; GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(window); return setCursorPositionClientRelative_impl(seat, win, x, y); } GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Seat *seat = display_->seats[0]; - GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat); + GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat); if (!seat_state_pointer) { return GHOST_kFailure; } - if (wl_surface *wl_surface_focus = seat_state_pointer->wl_surface) { + if (wl_surface *wl_surface_focus = seat_state_pointer->wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); return getCursorPositionClientRelative_impl(seat_state_pointer, win, x, y); } @@ -3486,14 +5492,14 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) co GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(const int32_t x, const int32_t y) { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Seat *seat = display_->seats[0]; /* Intentionally different from `getCursorPosition` which supports both tablet & pointer. * In the case of setting the cursor location, tablets don't support this. */ - if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) { GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); return setCursorPositionClientRelative_impl(seat, win, x, y); } @@ -3616,17 +5622,12 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, const uint32_t width, const uint32_t height, const GHOST_TWindowState state, - const GHOST_TDrawingContextType type, const GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, const GHOST_IWindow *parentWindow) { /* Globally store pointer to window manager. */ - if (!window_manager) { - window_manager = getWindowManager(); - } - GHOST_WindowWayland *window = new GHOST_WindowWayland( this, title, @@ -3636,7 +5637,7 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, height, state, parentWindow, - type, + glSettings.context_type, is_dialog, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive); @@ -3664,22 +5665,22 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, */ static void cursor_buffer_show(const GWL_Seat *seat) { - const GWL_Cursor *c = &seat->cursor; + const GWL_Cursor *cursor = &seat->cursor; if (seat->wl_pointer) { - const int scale = c->is_custom ? c->custom_scale : seat->pointer.theme_scale; - const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale; - const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale; + const int scale = cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale; + const int32_t hotspot_x = int32_t(cursor->wl_image.hotspot_x) / scale; + const int32_t hotspot_y = int32_t(cursor->wl_image.hotspot_y) / scale; if (seat->wl_pointer) { wl_pointer_set_cursor( - seat->wl_pointer, seat->pointer.serial, c->wl_surface, hotspot_x, hotspot_y); + seat->wl_pointer, seat->pointer.serial, cursor->wl_surface_cursor, hotspot_x, hotspot_y); } } if (!seat->tablet_tools.empty()) { - const int scale = c->is_custom ? c->custom_scale : seat->tablet.theme_scale; - const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale; - const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale; + const int scale = cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale; + const int32_t hotspot_x = int32_t(cursor->wl_image.hotspot_x) / scale; + const int32_t hotspot_y = int32_t(cursor->wl_image.hotspot_y) / scale; for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) { GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>( zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2)); @@ -3688,6 +5689,9 @@ static void cursor_buffer_show(const GWL_Seat *seat) tablet_tool->wl_surface_cursor, hotspot_x, hotspot_y); +#ifdef USE_KDE_TABLET_HIDDEN_CURSOR_HACK + wl_surface_commit(tablet_tool->wl_surface_cursor); +#endif } } } @@ -3742,21 +5746,21 @@ static void cursor_buffer_set_surface_impl(const GWL_Seat *seat, static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer) { - const GWL_Cursor *c = &seat->cursor; + const GWL_Cursor *cursor = &seat->cursor; const wl_cursor_image *wl_image = &seat->cursor.wl_image; - const bool visible = (c->visible && c->is_hardware); + const bool visible = (cursor->visible && cursor->is_hardware); /* This is a requirement of WAYLAND, when this isn't the case, * it causes Blender's window to close intermittently. */ if (seat->wl_pointer) { const int scale = cursor_buffer_compatible_scale_from_image( - wl_image, c->is_custom ? c->custom_scale : seat->pointer.theme_scale); + wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale); const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale; const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale; - cursor_buffer_set_surface_impl(seat, buffer, c->wl_surface, scale); + cursor_buffer_set_surface_impl(seat, buffer, cursor->wl_surface_cursor, scale); wl_pointer_set_cursor(seat->wl_pointer, seat->pointer.serial, - visible ? c->wl_surface : nullptr, + visible ? cursor->wl_surface_cursor : nullptr, hotspot_x, hotspot_y); } @@ -3764,7 +5768,7 @@ static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer) /* Set the cursor for all tablet tools as well. */ if (!seat->tablet_tools.empty()) { const int scale = cursor_buffer_compatible_scale_from_image( - wl_image, c->is_custom ? c->custom_scale : seat->tablet.theme_scale); + wl_image, cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale); const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale; const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale; for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) { @@ -3842,40 +5846,40 @@ static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor shape) { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - auto cursor_find = cursors.find(shape); - const char *cursor_name = (cursor_find == cursors.end()) ? - cursors.at(GHOST_kStandardCursorDefault) : + auto cursor_find = ghost_wl_cursors.find(shape); + const char *cursor_name = (cursor_find == ghost_wl_cursors.end()) ? + ghost_wl_cursors.at(GHOST_kStandardCursorDefault) : (*cursor_find).second; - GWL_Seat *seat = display_->seats[0]; - GWL_Cursor *c = &seat->cursor; + GWL_Cursor *cursor = &seat->cursor; - if (!c->wl_theme) { + if (!cursor->wl_theme) { /* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */ - c->wl_theme = wl_cursor_theme_load( - c->theme_name.c_str(), c->size, display_->seats[0]->system->wl_shm()); + cursor->wl_theme = wl_cursor_theme_load( + cursor->theme_name.c_str(), cursor->theme_size, wl_shm()); } - wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name); + wl_cursor *wl_cursor = wl_cursor_theme_get_cursor(cursor->wl_theme, cursor_name); - if (!cursor) { + if (!wl_cursor) { GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl); return GHOST_kFailure; } - struct wl_cursor_image *image = cursor->images[0]; + struct wl_cursor_image *image = wl_cursor->images[0]; struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); if (!buffer) { return GHOST_kFailure; } - c->visible = true; - c->is_custom = false; - c->wl_buffer = buffer; - c->wl_image = *image; + cursor->visible = true; + cursor->is_custom = false; + cursor->wl_buffer = buffer; + cursor->wl_image = *image; cursor_buffer_set(seat, buffer); @@ -3884,8 +5888,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor s GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(const GHOST_TStandardCursor cursorShape) { - auto cursor_find = cursors.find(cursorShape); - if (cursor_find == cursors.end()) { + auto cursor_find = ghost_wl_cursors.find(cursorShape); + if (cursor_find == ghost_wl_cursors.end()) { return GHOST_kFailure; } const char *value = (*cursor_find).second; @@ -3903,12 +5907,12 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap, const int hotY, const bool /*canInvertColor*/) { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Cursor *cursor = &display_->seats[0]->cursor; - + GWL_Cursor *cursor = &seat->cursor; if (cursor->custom_data) { munmap(cursor->custom_data, cursor->custom_data_size); cursor->custom_data = nullptr; @@ -3966,14 +5970,19 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap, cursor->wl_image.hotspot_x = uint32_t(hotX); cursor->wl_image.hotspot_y = uint32_t(hotY); - cursor_buffer_set(display_->seats[0], buffer); + cursor_buffer_set(seat, buffer); return GHOST_kSuccess; } GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap) { - GWL_Cursor *cursor = &display_->seats[0]->cursor; + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { + return GHOST_kFailure; + } + + GWL_Cursor *cursor = &seat->cursor; if (cursor->custom_data == nullptr) { return GHOST_kFailure; } @@ -3994,11 +6003,11 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(const bool visible) { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } - GWL_Seat *seat = display_->seats[0]; cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET); return GHOST_kSuccess; } @@ -4018,12 +6027,12 @@ bool GHOST_SystemWayland::supportsWindowPosition() bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode) { - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return false; } #ifdef USE_GNOME_CONFINE_HACK - GWL_Seat *seat = display_->seats[0]; const bool use_software_confine = seat->use_pointer_software_confine; #else const bool use_software_confine = false; @@ -4062,11 +6071,10 @@ static GWL_SeatStateGrab seat_grab_state_from_mode(const GHOST_TGrabCursorMode m const bool use_software_confine) { /* Initialize all members. */ - const struct GWL_SeatStateGrab grab_state = { - /* Warping happens to require software cursor which also hides. */ - .use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine, - .use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false), - }; + GWL_SeatStateGrab grab_state; + /* Warping happens to require software cursor which also hides. */ + grab_state.use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine; + grab_state.use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false); return grab_state; } @@ -4140,6 +6148,16 @@ wl_compositor *GHOST_SystemWayland::wl_compositor() return display_->wl_compositor; } +struct zwp_primary_selection_device_manager_v1 *GHOST_SystemWayland::wp_primary_selection_manager() +{ + return display_->wp_primary_selection_device_manager; +} + +struct zwp_pointer_gestures_v1 *GHOST_SystemWayland::wp_pointer_gestures() +{ + return display_->wp_pointer_gestures; +} + #ifdef WITH_GHOST_WAYLAND_LIBDECOR libdecor *GHOST_SystemWayland::libdecor_context() @@ -4202,9 +6220,9 @@ GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface) * Functionality only used for the WAYLAND implementation. * \{ */ -void GHOST_SystemWayland::clipboard_set(const std::string &clipboard) +void GHOST_SystemWayland::seat_active_set(const struct GWL_Seat *seat) { - clipboard_ = clipboard; + gwl_display_seat_active_set(display_, seat); } void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface) @@ -4217,10 +6235,10 @@ void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface) /* Only clear window surfaces (not cursors, off-screen surfaces etc). */ for (GWL_Seat *seat : display_->seats) { - SURFACE_CLEAR_PTR(seat->pointer.wl_surface); - SURFACE_CLEAR_PTR(seat->tablet.wl_surface); - SURFACE_CLEAR_PTR(seat->keyboard.wl_surface); - SURFACE_CLEAR_PTR(seat->wl_surface_focus_dnd); + SURFACE_CLEAR_PTR(seat->pointer.wl_surface_window); + SURFACE_CLEAR_PTR(seat->tablet.wl_surface_window); + SURFACE_CLEAR_PTR(seat->keyboard.wl_surface_window); + SURFACE_CLEAR_PTR(seat->wl_surface_window_focus_dnd); } #undef SURFACE_CLEAR_PTR } @@ -4234,11 +6252,12 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod const int scale) { /* Ignore, if the required protocols are not supported. */ - if (UNLIKELY(!display_->relative_pointer_manager || !display_->pointer_constraints)) { + if (UNLIKELY(!display_->wp_relative_pointer_manager || !display_->wp_pointer_constraints)) { return GHOST_kFailure; } - if (UNLIKELY(display_->seats.empty())) { + GWL_Seat *seat = gwl_display_seat_active_get(display_); + if (UNLIKELY(!seat)) { return GHOST_kFailure; } /* No change, success. */ @@ -4246,8 +6265,6 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod return GHOST_kSuccess; } - GWL_Seat *seat = display_->seats[0]; - #ifdef USE_GNOME_CONFINE_HACK const bool was_software_confine = seat->use_pointer_software_confine; const bool use_software_confine = setCursorGrab_use_software_confine(mode, wl_surface); @@ -4273,11 +6290,11 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod * in this case disable the current locks as it makes logic confusing, * postpone changing the cursor to avoid flickering. */ if (!grab_state_next.use_lock) { - if (seat->relative_pointer) { - zwp_relative_pointer_v1_destroy(seat->relative_pointer); - seat->relative_pointer = nullptr; + if (seat->wp_relative_pointer) { + zwp_relative_pointer_v1_destroy(seat->wp_relative_pointer); + seat->wp_relative_pointer = nullptr; } - if (seat->locked_pointer) { + if (seat->wp_locked_pointer) { /* Potentially add a motion event so the application has updated X/Y coordinates. */ int32_t xy_motion[2] = {0, 0}; bool xy_motion_create_event = false; @@ -4306,7 +6323,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod seat->pointer.xy[0] = xy_next[0]; seat->pointer.xy[1] = xy_next[1]; - zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next)); + zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer, UNPACK2(xy_next)); wl_surface_commit(wl_surface); } else if (mode_current == GHOST_kGrabHide) { @@ -4316,7 +6333,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod wl_fixed_from_int(init_grab_xy[0]) / scale, wl_fixed_from_int(init_grab_xy[1]) / scale, }; - zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next)); + zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer, + UNPACK2(xy_next)); wl_surface_commit(wl_surface); /* NOTE(@campbellbarton): The new cursor position is a hint, @@ -4330,7 +6348,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod #ifdef USE_GNOME_CONFINE_HACK else if (mode_current == GHOST_kGrabNormal) { if (was_software_confine) { - zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, + zwp_locked_pointer_v1_set_cursor_position_hint(seat->wp_locked_pointer, UNPACK2(seat->pointer.xy)); wl_surface_commit(wl_surface); } @@ -4346,15 +6364,15 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod GHOST_TABLET_DATA_NONE)); } - zwp_locked_pointer_v1_destroy(seat->locked_pointer); - seat->locked_pointer = nullptr; + zwp_locked_pointer_v1_destroy(seat->wp_locked_pointer); + seat->wp_locked_pointer = nullptr; } } if (!grab_state_next.use_confine) { - if (seat->confined_pointer) { - zwp_confined_pointer_v1_destroy(seat->confined_pointer); - seat->confined_pointer = nullptr; + if (seat->wp_confined_pointer) { + zwp_confined_pointer_v1_destroy(seat->wp_confined_pointer); + seat->wp_confined_pointer = nullptr; } } @@ -4365,12 +6383,12 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod * possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates. * An alternative could be to draw the cursor in software (and hide the real cursor), * or just accept a locked cursor on WAYLAND. */ - seat->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( - display_->relative_pointer_manager, seat->wl_pointer); + seat->wp_relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( + display_->wp_relative_pointer_manager, seat->wl_pointer); zwp_relative_pointer_v1_add_listener( - seat->relative_pointer, &relative_pointer_listener, seat); - seat->locked_pointer = zwp_pointer_constraints_v1_lock_pointer( - display_->pointer_constraints, + seat->wp_relative_pointer, &relative_pointer_listener, seat); + seat->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer( + display_->wp_pointer_constraints, wl_surface, seat->wl_pointer, nullptr, @@ -4387,8 +6405,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod } else if (grab_state_next.use_confine) { if (!grab_state_prev.use_confine) { - seat->confined_pointer = zwp_pointer_constraints_v1_confine_pointer( - display_->pointer_constraints, + seat->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer( + display_->wp_pointer_constraints, wl_surface, seat->wl_pointer, nullptr, diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index 5d2cfe45582..a8e8d8ddc45 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -23,6 +23,7 @@ # include <libdecor.h> #endif +#include <mutex> #include <string> class GHOST_WindowWayland; @@ -51,6 +52,8 @@ void ghost_wl_dynload_libraries_exit(); #endif struct GWL_Output { + GHOST_SystemWayland *system = nullptr; + struct wl_output *wl_output = nullptr; struct zxdg_output_v1 *xdg_output = nullptr; /** Dimensions in pixels. */ @@ -84,11 +87,12 @@ struct GWL_Output { class GHOST_SystemWayland : public GHOST_System { public: - GHOST_SystemWayland(); + GHOST_SystemWayland(bool background); + GHOST_SystemWayland() : GHOST_SystemWayland(true){}; ~GHOST_SystemWayland() override; - GHOST_TSuccess init(); + GHOST_TSuccess init() override; bool processEvents(bool waitForEvent) override; @@ -128,7 +132,6 @@ class GHOST_SystemWayland : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -150,8 +153,8 @@ class GHOST_SystemWayland : public GHOST_System { GHOST_TSuccess setCursorVisibility(bool visible); - bool supportsCursorWarp(); - bool supportsWindowPosition(); + bool supportsCursorWarp() override; + bool supportsWindowPosition() override; bool getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode); @@ -159,6 +162,8 @@ class GHOST_SystemWayland : public GHOST_System { struct wl_display *wl_display(); struct wl_compositor *wl_compositor(); + struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_manager(); + struct zwp_pointer_gestures_v1 *wp_pointer_gestures(); #ifdef WITH_GHOST_WAYLAND_LIBDECOR libdecor *libdecor_context(); @@ -173,7 +178,8 @@ class GHOST_SystemWayland : public GHOST_System { /* WAYLAND utility functions. */ - void clipboard_set(const std::string &clipboard); + /** Set this seat to be active. */ + void seat_active_set(const struct GWL_Seat *seat); /** Clear all references to this surface to prevent accessing NULL pointers. */ void window_surface_unref(const wl_surface *wl_surface); @@ -192,5 +198,4 @@ class GHOST_SystemWayland : public GHOST_System { private: struct GWL_Display *display_; - std::string clipboard_; }; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 667198241f0..54c892d296e 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -213,7 +213,6 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -227,7 +226,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title, width, height, state, - type, + glSettings.context_type, ((glSettings.flags & GHOST_glStereoVisual) != 0), false, (GHOST_WindowWin32 *)parentWindow, diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index f5cd0055b34..98a7e5dfb35 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -103,7 +103,6 @@ class GHOST_SystemWin32 : public GHOST_System { * \param width: The width the window. * \param height: The height the window. * \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 full-screen). * \param parentWindow: Parent window. @@ -115,7 +114,6 @@ class GHOST_SystemWin32 : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 4523f6fa37c..5c89febe97c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -308,7 +308,6 @@ void GHOST_SystemX11::getAllDisplayDimensions(uint32_t &width, uint32_t &height) * \param width: The width the window. * \param height: The height the window. * \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 full-screen). * \param parentWindow: Parent window. @@ -320,7 +319,6 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive, const bool is_dialog, @@ -341,7 +339,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, height, state, (GHOST_WindowX11 *)parentWindow, - type, + glSettings.context_type, is_dialog, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 572be30174d..1f071da6da7 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -113,7 +113,6 @@ class GHOST_SystemX11 : public GHOST_System { * \param width: The width the window. * \param height: The height the window. * \param state: The state of the window when opened. - * \param type: The type of drawing context installed in this window. * \param stereoVisual: Create a stereo visual for quad buffered stereo. * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent (embedder) window. @@ -125,7 +124,6 @@ class GHOST_SystemX11 : public GHOST_System { uint32_t width, uint32_t height, GHOST_TWindowState state, - GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive = false, const bool is_dialog = false, diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 1c0991bba30..396691fa161 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -74,7 +74,7 @@ class GHOST_Window : public GHOST_IWindow { */ virtual bool getValid() const override { - return m_context != NULL; + return m_context != nullptr; } /** @@ -283,8 +283,9 @@ class GHOST_Window : public GHOST_IWindow { float getNativePixelSize(void) override { - if (m_nativePixelSize > 0.0f) + if (m_nativePixelSize > 0.0f) { return m_nativePixelSize; + } return 1.0f; } @@ -298,7 +299,8 @@ class GHOST_Window : public GHOST_IWindow { } #ifdef WITH_INPUT_IME - virtual void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) override + virtual void beginIME( + int32_t /*x*/, int32_t /*y*/, int32_t /*w*/, int32_t /*h*/, bool /*completed*/) override { /* do nothing temporarily if not in windows */ } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 737fd64bdf0..bc1f1e99a3a 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -803,10 +803,10 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type) { - if (type == GHOST_kDrawingContextTypeOpenGL) { + if (type == GHOST_kDrawingContextTypeOpenGL || type == GHOST_kDrawingContextTypeMetal) { GHOST_Context *context = new GHOST_ContextCGL( - m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView); + m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView, type); if (context->initializeDrawingContext()) return context; diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index b29c5efd8d4..ad94a02b514 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -53,7 +53,7 @@ struct WGL_LibDecor_Window { bool configured = false; }; -static void wgl_libdecor_window_destroy(WGL_LibDecor_Window *decor) +static void gwl_libdecor_window_destroy(WGL_LibDecor_Window *decor) { libdecor_frame_unref(decor->frame); delete decor; @@ -67,7 +67,7 @@ struct WGL_XDG_Decor_Window { enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0; }; -static void wgl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor) +static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor) { if (decor->toplevel_decor) { zxdg_toplevel_decoration_v1_destroy(decor->toplevel_decor); @@ -91,12 +91,10 @@ struct GWL_Window { /** The scale value written to #wl_surface_set_buffer_scale. */ int scale = 0; /** - * The DPI, either: - * - `scale * base_dpi` - * - `wl_fixed_to_int(scale_fractional * base_dpi)` - * When fractional scaling is available. + * The fractional scale used to calculate the DPI. + * (always set, even when scaling is rounded to whole units). */ - uint32_t dpi = 0; + wl_fixed_t scale_fractional = 0; #ifdef WITH_GHOST_WAYLAND_LIBDECOR WGL_LibDecor_Window *libdecor = nullptr; @@ -147,7 +145,7 @@ static int output_scale_cmp(const GWL_Output *output_a, const GWL_Output *output static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs, const int32_t scale_default, - uint32_t *r_dpi) + wl_fixed_t *r_scale_fractional) { const GWL_Output *output_max = nullptr; for (const GWL_Output *reg_output : outputs) { @@ -157,18 +155,16 @@ static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs } if (output_max) { - if (r_dpi) { - *r_dpi = output_max->has_scale_fractional ? - /* Fractional DPI. */ - wl_fixed_to_int(output_max->scale_fractional * base_dpi) : - /* Simple non-fractional DPI. */ - (output_max->scale * base_dpi); + if (r_scale_fractional) { + *r_scale_fractional = output_max->has_scale_fractional ? + output_max->scale_fractional : + wl_fixed_from_int(output_max->scale); } return output_max->scale; } - if (r_dpi) { - *r_dpi = scale_default * base_dpi; + if (r_scale_fractional) { + *r_scale_fractional = wl_fixed_from_int(scale_default); } return scale_default; } @@ -479,7 +475,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, * * Using the maximum scale is best as it results in the window first being smaller, * avoiding a large window flashing before it's made smaller. */ - window_->scale = outputs_max_scale_or_default(system_->outputs(), 1, &window_->dpi); + window_->scale = outputs_max_scale_or_default(system_->outputs(), 1, &window_->scale_fractional); /* Window surfaces. */ window_->wl_surface = wl_compositor_create_surface(system_->wl_compositor()); @@ -727,12 +723,12 @@ GHOST_WindowWayland::~GHOST_WindowWayland() #ifdef WITH_GHOST_WAYLAND_LIBDECOR if (use_libdecor) { - wgl_libdecor_window_destroy(window_->libdecor); + gwl_libdecor_window_destroy(window_->libdecor); } else #endif { - wgl_xdg_decor_window_destroy(window_->xdg_decor); + gwl_xdg_decor_window_destroy(window_->xdg_decor); } /* Clear any pointers to this window. This is needed because there are no guarantees @@ -751,7 +747,9 @@ GHOST_WindowWayland::~GHOST_WindowWayland() uint16_t GHOST_WindowWayland::getDPIHint() { - return window_->dpi; + /* Using the physical DPI will cause wrong scaling of the UI + * use a multiplier for the default DPI as a workaround. */ + return wl_fixed_to_int(window_->scale_fractional * base_dpi); } GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible) @@ -946,7 +944,12 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType EGL_OPENGL_API); } - return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr; + if (context->initializeDrawingContext()) { + return context; + } + + delete context; + return nullptr; } /** \} */ @@ -957,14 +960,14 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType * Expose some members via methods. * \{ */ -uint16_t GHOST_WindowWayland::dpi() const +int GHOST_WindowWayland::scale() const { - return window_->dpi; + return window_->scale; } -int GHOST_WindowWayland::scale() const +wl_fixed_t GHOST_WindowWayland::scale_fractional() const { - return window_->scale; + return window_->scale_fractional; } wl_surface *GHOST_WindowWayland::wl_surface() const @@ -1030,30 +1033,39 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size() */ bool GHOST_WindowWayland::outputs_changed_update_scale() { - uint32_t dpi_next; - const int scale_next = outputs_max_scale_or_default(outputs(), 0, &dpi_next); + wl_fixed_t scale_fractional_next = 0; + const int scale_next = outputs_max_scale_or_default(outputs(), 0, &scale_fractional_next); if (UNLIKELY(scale_next == 0)) { return false; } - const uint32_t dpi_curr = window_->dpi; + const wl_fixed_t scale_fractional_curr = window_->scale_fractional; const int scale_curr = window_->scale; bool changed = false; if (scale_next != scale_curr) { - /* Unlikely but possible there is a pending size change is set. */ - window_->size_pending[0] = (window_->size_pending[0] / scale_curr) * scale_next; - window_->size_pending[1] = (window_->size_pending[1] / scale_curr) * scale_next; - window_->scale = scale_next; wl_surface_set_buffer_scale(window_->wl_surface, scale_next); + + /* It's important to resize the window immediately, to avoid the window changing size + * and flickering in a constant feedback loop (in some bases). */ + if ((window_->size_pending[0] != 0) && (window_->size_pending[1] != 0)) { + /* Unlikely but possible there is a pending size change is set. */ + window_->size[0] = window_->size_pending[0]; + window_->size[1] = window_->size_pending[1]; + window_->size_pending[0] = 0; + window_->size_pending[1] = 0; + } + window_->size[0] = (window_->size[0] / scale_curr) * scale_next; + window_->size[1] = (window_->size[1] / scale_curr) * scale_next; + wl_egl_window_resize(window_->egl_window, UNPACK2(window_->size), 0, 0); + window_->ghost_window->notify_size(); + changed = true; } - if (dpi_next != dpi_curr) { - /* Using the real DPI will cause wrong scaling of the UI - * use a multiplier for the default DPI as workaround. */ - window_->dpi = dpi_next; + if (scale_fractional_next != scale_fractional_curr) { + window_->scale_fractional = scale_fractional_next; changed = true; /* As this is a low-level function, we might want adding this event to be optional, diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h index e95f5386310..ec473c4a710 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.h +++ b/intern/ghost/intern/GHOST_WindowWayland.h @@ -12,6 +12,8 @@ #include <vector> +#include <wayland-util.h> /* For #wl_fixed_t */ + class GHOST_SystemWayland; struct GWL_Output; @@ -95,8 +97,8 @@ class GHOST_WindowWayland : public GHOST_Window { /* WAYLAND direct-data access. */ - uint16_t dpi() const; int scale() const; + wl_fixed_t scale_fractional() const; struct wl_surface *wl_surface() const; const std::vector<GWL_Output *> &outputs(); diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp index 1891f1eca77..3c9206b2010 100644 --- a/intern/ghost/test/gears/GHOST_Test.cpp +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -407,17 +407,12 @@ Application::Application(GHOST_ISystem *system) stereo(false) { GHOST_GLSettings glSettings = {0}; + glSettings.context_type = GHOST_kDrawingContextTypeOpenGL; fApp = this; // Create the main window - m_mainWindow = system->createWindow("gears - main window", - 10, - 64, - 320, - 200, - GHOST_kWindowStateNormal, - GHOST_kDrawingContextTypeOpenGL, - glSettings); + m_mainWindow = system->createWindow( + "gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, glSettings); if (!m_mainWindow) { std::cout << "could not create main window\n"; @@ -425,14 +420,8 @@ Application::Application(GHOST_ISystem *system) } // Create a secondary window - m_secondaryWindow = system->createWindow("gears - secondary window", - 340, - 64, - 320, - 200, - GHOST_kWindowStateNormal, - GHOST_kDrawingContextTypeOpenGL, - glSettings); + m_secondaryWindow = system->createWindow( + "gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, glSettings); if (!m_secondaryWindow) { std::cout << "could not create secondary window\n"; exit(-1); diff --git a/intern/guardedalloc/intern/leak_detector.cc b/intern/guardedalloc/intern/leak_detector.cc index 288d78fd206..5b565b15920 100644 --- a/intern/guardedalloc/intern/leak_detector.cc +++ b/intern/guardedalloc/intern/leak_detector.cc @@ -41,7 +41,7 @@ class MemLeakPrinter { if (fail_on_memleak) { /* There are many other ways to change the exit code to failure here: - * - Make the destructor noexcept(false) and throw an exception. + * - Make the destructor `noexcept(false)` and throw an exception. * - Call exit(EXIT_FAILURE). * - Call terminate(). */ diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 1dddd70928a..920b8d5c542 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -81,12 +81,6 @@ if(WITH_OPENSUBDIV) ) endif() - opensubdiv_define_component(OPENSUBDIV_HAS_OPENMP) - opensubdiv_define_component(OPENSUBDIV_HAS_OPENCL) - opensubdiv_define_component(OPENSUBDIV_HAS_CUDA) - opensubdiv_define_component(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK) - opensubdiv_define_component(OPENSUBDIV_HAS_GLSL_COMPUTE) - if(WIN32) add_definitions(-DNOMINMAX) add_definitions(-D_USE_MATH_DEFINES) diff --git a/intern/wayland_dynload/extern/wayland_dynload_client.h b/intern/wayland_dynload/extern/wayland_dynload_client.h index 8e9dddd91a3..d80ef5c9f0c 100644 --- a/intern/wayland_dynload/extern/wayland_dynload_client.h +++ b/intern/wayland_dynload/extern/wayland_dynload_client.h @@ -41,6 +41,7 @@ WAYLAND_DYNLOAD_IFACE(wl_seat_interface) WAYLAND_DYNLOAD_IFACE(wl_shm_interface) WAYLAND_DYNLOAD_IFACE(wl_shm_pool_interface) WAYLAND_DYNLOAD_IFACE(wl_surface_interface) +WAYLAND_DYNLOAD_IFACE(wl_touch_interface) #else /* Header guard. */ @@ -62,9 +62,19 @@ if "%SVN_FIX%" == "1" ( ) if "%BUILD_UPDATE%" == "1" ( + REM First see if the SVN libs are there and check them out if they are not. call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd" if errorlevel 1 goto EOF - + if "%BUILD_UPDATE_SVN%" == "1" ( + REM Then update SVN platform libraries, since updating python while python is + REM running tends to be problematic. The python script that update_sources + REM calls later on may still try to switch branches and run into trouble, + REM but for *most* people this will side step the problem. + call "%BLENDER_DIR%\build_files\windows\svn_update.cmd" + ) + REM Finally call the python script shared between all platforms that updates git + REM and does any other SVN work like update the tests or branch switches + REM if required. call "%BLENDER_DIR%\build_files\windows\update_sources.cmd" goto EOF ) diff --git a/release/scripts/modules/gpu_extras/batch.py b/release/scripts/modules/gpu_extras/batch.py index ba8e3879a8e..6c9ab52c1a3 100644 --- a/release/scripts/modules/gpu_extras/batch.py +++ b/release/scripts/modules/gpu_extras/batch.py @@ -34,13 +34,13 @@ def batch_for_shader(shader, type, content, *, indices=None): return 'I32' def recommended_attr_len(attr_name): - item = content[attr_name][0] attr_len = 1 try: + item = content[attr_name][0] while True: attr_len *= len(item) item = item[0] - except TypeError: + except (TypeError, IndexError): pass return attr_len diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py index 7f6d0b1e9bf..5bd38acb19c 100644 --- a/release/scripts/modules/sys_info.py +++ b/release/scripts/modules/sys_info.py @@ -184,6 +184,7 @@ def write_sysinfo(filepath): output.write("vendor:\t\t%r\n" % gpu.platform.vendor_get()) output.write("version:\t%r\n" % gpu.platform.version_get()) output.write("device type:\t%r\n" % gpu.platform.device_type_get()) + output.write("backend type:\t%r\n" % gpu.platform.backend_type_get()) output.write("extensions:\n") glext = sorted(gpu.capabilities.extensions_get()) diff --git a/release/scripts/startup/bl_ui/node_add_menu.py b/release/scripts/startup/bl_ui/node_add_menu.py index 31b84b8f08a..873dbd533a5 100644 --- a/release/scripts/startup/bl_ui/node_add_menu.py +++ b/release/scripts/startup/bl_ui/node_add_menu.py @@ -59,6 +59,14 @@ def draw_node_group_add_menu(context, layout): ops.value = "bpy.data.node_groups[%r]" % group.name +def draw_assets_for_catalog(layout, catalog_path): + layout.template_node_asset_menu_items(catalog_path=catalog_path) + + +def draw_root_assets(layout): + layout.menu_contents("NODE_MT_node_add_root_catalogs") + + classes = ( ) diff --git a/release/scripts/startup/bl_ui/node_add_menu_geometry.py b/release/scripts/startup/bl_ui/node_add_menu_geometry.py index e1b57ec4f43..c076cd7395a 100644 --- a/release/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/release/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -16,6 +16,7 @@ class NODE_MT_geometry_node_GEO_ATTRIBUTE(Menu): node_add_menu.add_node_type(layout, "GeometryNodeAttributeDomainSize") node_add_menu.add_node_type(layout, "GeometryNodeRemoveAttribute") node_add_menu.add_node_type(layout, "GeometryNodeStoreNamedAttribute") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_COLOR(Menu): @@ -32,6 +33,7 @@ class NODE_MT_geometry_node_GEO_COLOR(Menu): ops.value = "'RGBA'" node_add_menu.add_node_type(layout, "ShaderNodeRGBCurve") node_add_menu.add_node_type(layout, "FunctionNodeSeparateColor") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_CURVE(Menu): @@ -70,6 +72,7 @@ class NODE_MT_geometry_node_GEO_CURVE(Menu): node_add_menu.add_node_type(layout, "GeometryNodeSetSplineCyclic") node_add_menu.add_node_type(layout, "GeometryNodeSetSplineResolution") node_add_menu.add_node_type(layout, "GeometryNodeCurveSplineType") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE(Menu): @@ -86,6 +89,7 @@ class NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE(Menu): node_add_menu.add_node_type(layout, "GeometryNodeCurveQuadraticBezier") node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveQuadrilateral") node_add_menu.add_node_type(layout, "GeometryNodeCurveStar") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_curve_topology(Menu): @@ -97,6 +101,7 @@ class NODE_MT_geometry_node_curve_topology(Menu): node_add_menu.add_node_type(layout, "GeometryNodeOffsetPointInCurve") node_add_menu.add_node_type(layout, "GeometryNodeCurveOfPoint") node_add_menu.add_node_type(layout, "GeometryNodePointsOfCurve") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_GEOMETRY(Menu): @@ -122,6 +127,7 @@ class NODE_MT_geometry_node_GEO_GEOMETRY(Menu): layout.separator() node_add_menu.add_node_type(layout, "GeometryNodeSetID") node_add_menu.add_node_type(layout, "GeometryNodeSetPosition") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_INPUT(Menu): @@ -149,6 +155,7 @@ class NODE_MT_geometry_node_GEO_INPUT(Menu): node_add_menu.add_node_type(layout, "GeometryNodeInputPosition") node_add_menu.add_node_type(layout, "GeometryNodeInputRadius") node_add_menu.add_node_type(layout, "GeometryNodeInputSceneTime") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_INSTANCE(Menu): @@ -166,6 +173,7 @@ class NODE_MT_geometry_node_GEO_INSTANCE(Menu): layout.separator() node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceRotation") node_add_menu.add_node_type(layout, "GeometryNodeInputInstanceScale") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_MATERIAL(Menu): @@ -181,6 +189,7 @@ class NODE_MT_geometry_node_GEO_MATERIAL(Menu): layout.separator() node_add_menu.add_node_type(layout, "GeometryNodeSetMaterial") node_add_menu.add_node_type(layout, "GeometryNodeSetMaterialIndex") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_GEO_MESH(Menu): @@ -219,6 +228,7 @@ class NODE_MT_geometry_node_GEO_MESH(Menu): node_add_menu.add_node_type(layout, "GeometryNodeInputMeshVertexNeighbors") layout.separator() node_add_menu.add_node_type(layout, "GeometryNodeSetShadeSmooth") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_PRIMITIVES_MESH(Menu): @@ -235,6 +245,7 @@ class NODE_MT_category_PRIMITIVES_MESH(Menu): node_add_menu.add_node_type(layout, "GeometryNodeMeshCircle") node_add_menu.add_node_type(layout, "GeometryNodeMeshLine") node_add_menu.add_node_type(layout, "GeometryNodeMeshUVSphere") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_mesh_topology(Menu): @@ -250,6 +261,7 @@ class NODE_MT_geometry_node_mesh_topology(Menu): node_add_menu.add_node_type(layout, "GeometryNodeFaceOfCorner"), node_add_menu.add_node_type(layout, "GeometryNodeOffsetCornerInFace"), node_add_menu.add_node_type(layout, "GeometryNodeVertexOfCorner"), + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_OUTPUT(Menu): @@ -259,6 +271,7 @@ class NODE_MT_category_GEO_OUTPUT(Menu): def draw(self, _context): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeViewer") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_POINT(Menu): @@ -274,6 +287,7 @@ class NODE_MT_category_GEO_POINT(Menu): node_add_menu.add_node_type(layout, "GeometryNodePointsToVolume") layout.separator() node_add_menu.add_node_type(layout, "GeometryNodeSetPointRadius") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_TEXT(Menu): @@ -290,6 +304,7 @@ class NODE_MT_category_GEO_TEXT(Menu): node_add_menu.add_node_type(layout, "FunctionNodeValueToString") layout.separator() node_add_menu.add_node_type(layout, "FunctionNodeInputSpecialCharacters") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_TEXTURE(Menu): @@ -308,6 +323,7 @@ class NODE_MT_category_GEO_TEXTURE(Menu): node_add_menu.add_node_type(layout, "ShaderNodeTexVoronoi") node_add_menu.add_node_type(layout, "ShaderNodeTexWave") node_add_menu.add_node_type(layout, "ShaderNodeTexWhiteNoise") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_UTILITIES(Menu): @@ -331,6 +347,7 @@ class NODE_MT_category_GEO_UTILITIES(Menu): node_add_menu.add_node_type(layout, "FunctionNodeRandomValue") node_add_menu.add_node_type(layout, "FunctionNodeRotateEuler") node_add_menu.add_node_type(layout, "GeometryNodeSwitch") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_UV(Menu): @@ -341,6 +358,7 @@ class NODE_MT_category_GEO_UV(Menu): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeUVPackIslands") node_add_menu.add_node_type(layout, "GeometryNodeUVUnwrap") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_VECTOR(Menu): @@ -354,6 +372,7 @@ class NODE_MT_category_GEO_VECTOR(Menu): node_add_menu.add_node_type(layout, "ShaderNodeVectorCurve") node_add_menu.add_node_type(layout, "ShaderNodeVectorMath") node_add_menu.add_node_type(layout, "ShaderNodeVectorRotate") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_VOLUME(Menu): @@ -364,6 +383,7 @@ class NODE_MT_category_GEO_VOLUME(Menu): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeVolumeCube") node_add_menu.add_node_type(layout, "GeometryNodeVolumeToMesh") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_GROUP(Menu): @@ -373,6 +393,7 @@ class NODE_MT_category_GEO_GROUP(Menu): def draw(self, context): layout = self.layout node_add_menu.draw_node_group_add_menu(context, layout) + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_category_GEO_LAYOUT(Menu): @@ -383,6 +404,7 @@ class NODE_MT_category_GEO_LAYOUT(Menu): layout = self.layout node_add_menu.add_node_type(layout, "NodeFrame") node_add_menu.add_node_type(layout, "NodeReroute") + node_add_menu.draw_assets_for_catalog(layout, self.bl_label) class NODE_MT_geometry_node_add_all(Menu): @@ -413,6 +435,7 @@ class NODE_MT_geometry_node_add_all(Menu): layout.menu("NODE_MT_category_GEO_VOLUME") layout.menu("NODE_MT_category_GEO_GROUP") layout.menu("NODE_MT_category_GEO_LAYOUT") + node_add_menu.draw_root_assets(layout) classes = ( diff --git a/release/scripts/startup/bl_ui/properties_data_curves.py b/release/scripts/startup/bl_ui/properties_data_curves.py index ff0eabeb7d9..df80bdb4552 100644 --- a/release/scripts/startup/bl_ui/properties_data_curves.py +++ b/release/scripts/startup/bl_ui/properties_data_curves.py @@ -44,7 +44,13 @@ class DATA_PT_curves_surface(DataButtonsPanel, Panel): layout.use_property_split = True layout.prop(ob.data, "surface") - layout.prop(ob.data, "surface_uv_map", text="UV Map") + has_surface = ob.data.surface is not None + if has_surface: + layout.prop_search(ob.data, "surface_uv_map", ob.data.surface.data, "uv_layers", text="UV Map") + else: + row = layout.row() + row.prop(ob.data, "surface_uv_map", text="UV Map") + row.enabled = has_surface class CURVES_MT_add_attribute(Menu): diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index a775a3cfa1b..a6b97fbdc85 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -586,7 +586,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): def draw_attribute_warnings(self, context, layout): ob = context.object - mesh = ob.data + mesh = context.mesh unique_names = set() colliding_names = [] @@ -595,8 +595,11 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): {"position": None, "shade_smooth": None, "normal": None, "crease": None}, mesh.attributes, mesh.uv_layers, - ob.vertex_groups, + None if ob is None else ob.vertex_groups, ): + if collection is None: + colliding_names.append("Cannot check for object vertex groups when pinning mesh") + continue for name in collection.keys(): unique_names_len = len(unique_names) unique_names.add(name) diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py index ca0e698500e..61384f25afb 100644 --- a/release/scripts/startup/bl_ui/properties_output.py +++ b/release/scripts/startup/bl_ui/properties_output.py @@ -380,7 +380,14 @@ class RENDER_PT_encoding_video(RenderOutputButtonsPanel, Panel): layout = self.layout ffmpeg = context.scene.render.ffmpeg - needs_codec = ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG', 'MPEG4', 'WEBM'} + needs_codec = ffmpeg.format in { + 'AVI', + 'QUICKTIME', + 'MKV', + 'OGG', + 'MPEG4', + 'WEBM' + } if needs_codec: layout.prop(ffmpeg, "codec") @@ -391,7 +398,12 @@ class RENDER_PT_encoding_video(RenderOutputButtonsPanel, Panel): layout.prop(ffmpeg, "use_lossless_output") # Output quality - use_crf = needs_codec and ffmpeg.codec in {'H264', 'MPEG4', 'WEBM'} + use_crf = needs_codec and ffmpeg.codec in { + 'H264', + 'MPEG4', + 'WEBM', + 'AV1' + } if use_crf: layout.prop(ffmpeg, "constant_rate_factor") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index ea257498e11..39684aaf161 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3018,6 +3018,7 @@ class VIEW3D_MT_brush_paint_modes(Menu): layout.prop(brush, "use_paint_vertex", text="Vertex Paint") layout.prop(brush, "use_paint_weight", text="Weight Paint") layout.prop(brush, "use_paint_image", text="Texture Paint") + layout.prop(brush, "use_paint_sculpt_curves", text="Sculpt Curves") class VIEW3D_MT_paint_vertex(Menu): diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 328e45f79b9..fec156580cf 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -52,6 +52,8 @@ class VIEW3D_MT_brush_context_menu(Menu): elif context.sculpt_object: layout.prop_menu_enum(brush, "sculpt_tool") layout.operator("brush.reset") + elif context.tool_settings.curves_sculpt: + layout.prop_menu_enum(brush, "curves_sculpt_tool") class VIEW3D_MT_brush_gpencil_context_menu(Menu): @@ -81,22 +83,6 @@ class VIEW3D_MT_brush_gpencil_context_menu(Menu): layout.operator("gpencil.brush_reset_all") -class VIEW3D_MT_brush_context_menu_paint_modes(Menu): - bl_label = "Enabled Modes" - - def draw(self, context): - layout = self.layout - - settings = UnifiedPaintPanel.paint_settings(context) - brush = settings.brush - - layout.prop(brush, "use_paint_sculpt", text="Sculpt") - layout.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt") - layout.prop(brush, "use_paint_vertex", text="Vertex Paint") - layout.prop(brush, "use_paint_weight", text="Weight Paint") - layout.prop(brush, "use_paint_image", text="Texture Paint") - - class View3DPanel: bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -2373,7 +2359,6 @@ class VIEW3D_PT_gpencil_brush_presets(Panel, PresetPanel): classes = ( VIEW3D_MT_brush_context_menu, VIEW3D_MT_brush_gpencil_context_menu, - VIEW3D_MT_brush_context_menu_paint_modes, VIEW3D_PT_tools_object_options, VIEW3D_PT_tools_object_options_transform, VIEW3D_PT_tools_meshedit_options, diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index ee0f41937e2..eff05e471aa 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -34,9 +34,9 @@ typedef struct EditBone { /** User-Defined Properties on this Bone */ struct IDProperty *prop; /** - * Editbones have a one-way link (i.e. children refer + * Edit-bones have a one-way link (i.e. children refer * to parents. This is converted to a two-way link for - * normal bones when leaving editmode. + * normal bones when leaving edit-mode. */ struct EditBone *parent; /** (64 == MAXBONENAME) */ diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh index caed12d4fdf..73c2e00c4c4 100644 --- a/source/blender/blenkernel/BKE_asset_catalog.hh +++ b/source/blender/blenkernel/BKE_asset_catalog.hh @@ -307,7 +307,7 @@ class AssetCatalogTreeItem { /** Iterate over children calling \a callback for each of them, but do not recurse into their * children. */ - void foreach_child(const ItemIterFn callback); + void foreach_child(ItemIterFn callback); protected: /** Child tree items, ordered by their names. */ @@ -345,10 +345,15 @@ class AssetCatalogTree { /** Ensure an item representing \a path is in the tree, adding it if necessary. */ void insert_item(const AssetCatalog &catalog); - void foreach_item(const AssetCatalogTreeItem::ItemIterFn callback); + void foreach_item(ItemIterFn callback); /** Iterate over root items calling \a callback for each of them, but do not recurse into their * children. */ - void foreach_root_item(const ItemIterFn callback); + void foreach_root_item(ItemIterFn callback); + + bool is_empty() const; + + AssetCatalogTreeItem *find_item(const AssetCatalogPath &path); + AssetCatalogTreeItem *find_root_item(const AssetCatalogPath &path); protected: /** Child tree items, ordered by their names. */ diff --git a/source/blender/blenkernel/BKE_asset_catalog_path.hh b/source/blender/blenkernel/BKE_asset_catalog_path.hh index 135906dd064..93ab0389daf 100644 --- a/source/blender/blenkernel/BKE_asset_catalog_path.hh +++ b/source/blender/blenkernel/BKE_asset_catalog_path.hh @@ -49,7 +49,7 @@ class AssetCatalogPath { AssetCatalogPath() = default; AssetCatalogPath(StringRef path); - AssetCatalogPath(const std::string &path); + AssetCatalogPath(std::string path); AssetCatalogPath(const char *path); AssetCatalogPath(const AssetCatalogPath &other_path) = default; AssetCatalogPath(AssetCatalogPath &&other_path) noexcept; diff --git a/source/blender/blenkernel/BKE_asset_library.hh b/source/blender/blenkernel/BKE_asset_library.hh index e0a39e3aee8..2058df71f6a 100644 --- a/source/blender/blenkernel/BKE_asset_library.hh +++ b/source/blender/blenkernel/BKE_asset_library.hh @@ -10,6 +10,8 @@ # error This is a C++-only header file. Use BKE_asset_library.h instead. #endif +#include "DNA_asset_types.h" + #include "BKE_asset_library.h" #include "BKE_asset_catalog.hh" @@ -44,19 +46,24 @@ struct AssetLibrary { * No-op if the catalog cannot be found. This could be the kind of "the * catalog definition file is corrupt/lost" scenario that the simple name is * meant to help recover from. */ - void refresh_catalog_simplename(struct AssetMetaData *asset_data); + void refresh_catalog_simplename(AssetMetaData *asset_data); void on_blend_save_handler_register(); void on_blend_save_handler_unregister(); - void on_blend_save_post(struct Main *, struct PointerRNA **pointers, int num_pointers); + void on_blend_save_post(Main *bmain, PointerRNA **pointers, int num_pointers); private: bCallbackFuncStore on_save_callback_store_{}; }; +Vector<AssetLibraryReference> all_valid_asset_library_refs(); + } // namespace blender::bke +blender::bke::AssetLibrary *BKE_asset_library_load(const Main *bmain, + const AssetLibraryReference &library_reference); + blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service( const ::AssetLibrary *library); blender::bke::AssetCatalogTree *BKE_asset_library_get_catalog_tree(const ::AssetLibrary *library); diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index 7b13b8a2b09..a4f9d73c31e 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -793,7 +793,9 @@ class CustomDataAttributes { ~CustomDataAttributes(); CustomDataAttributes(const CustomDataAttributes &other); CustomDataAttributes(CustomDataAttributes &&other); + CustomDataAttributes &operator=(const CustomDataAttributes &other); + CustomDataAttributes &operator=(CustomDataAttributes &&other); void reallocate(int size); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 96df8f7a443..806fff2099e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 4 +#define BLENDER_FILE_SUBVERSION 5 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h index bc60b6f050e..5b1dea0833a 100644 --- a/source/blender/blenkernel/BKE_bpath.h +++ b/source/blender/blenkernel/BKE_bpath.h @@ -55,15 +55,18 @@ typedef enum eBPathForeachFlag { * This is needed for directory manipulation callbacks which might otherwise modify the same * directory multiple times. */ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE = (1 << 8), - /** Reload data (when the path is edited). - * \note Only used by Image IDType currently. */ + /** + * Reload data (when the path is edited). + * \note Only used by Image #IDType currently. + */ BKE_BPATH_FOREACH_PATH_RELOAD_EDITED = (1 << 9), } eBPathForeachFlag; ENUM_OPERATORS(eBPathForeachFlag, BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) struct BPathForeachPathData; -/** Callback used to iterate over an ID's file paths. +/** + * Callback used to iterate over an ID's file paths. * * \note `path`s parameters should be considered as having a maximal `FILE_MAX` string length. * @@ -145,8 +148,9 @@ bool BKE_bpath_foreach_path_allocated_process(struct BPathForeachPathData *bpath /** Check for missing files. */ void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports); -/** Recursively search into given search directory, for all file paths of all IDs in given \a - * bmain, and replace existing paths as needed. +/** + * Recursively search into given search directory, for all file paths of all IDs in given + * \a bmain, and replace existing paths as needed. * * \note The search will happen into the whole search directory tree recursively (with a limit of * MAX_DIR_RECURSE), if several files are found matching a searched filename, the biggest one will @@ -156,7 +160,7 @@ void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *report * \param searchpath: The root directory in which the new filepaths should be searched for. * \param find_all: If `true`, also search for files which current path is still valid, if `false` * skip those still valid paths. - * */ + */ void BKE_bpath_missing_files_find(struct Main *bmain, const char *searchpath, struct ReportList *reports, @@ -178,23 +182,28 @@ void BKE_bpath_absolute_convert(struct Main *bmain, const char *basedir, struct ReportList *reports); -/** Temp backup of paths from all IDs in given \a bmain. +/** + * Temp backup of paths from all IDs in given \a bmain. * - * \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free. + * \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free. */ void *BKE_bpath_list_backup(struct Main *bmain, eBPathForeachFlag flag); -/** Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain. +/** + * Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain. * * \note This function assumes that the data in given Main did not change (no * addition/deletion/re-ordering of IDs, or their file paths) since the call to - * #BKE_bpath_list_backup that generated the given \a path_list_handle. */ + * #BKE_bpath_list_backup that generated the given \a path_list_handle. + */ void BKE_bpath_list_restore(struct Main *bmain, eBPathForeachFlag flag, void *path_list_handle); -/** Free the temp backup of paths in \a path_list_handle. +/** + * Free the temp backup of paths in \a path_list_handle. * * \note This function assumes that the path list has already been restored with a call to - * #BKE_bpath_list_restore, and is therefore empty. */ + * #BKE_bpath_list_restore, and is therefore empty. + */ void BKE_bpath_list_free(void *path_list_handle); /** \} */ diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 4d728002c87..a763b3d12c2 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -18,7 +18,9 @@ extern "C" { struct Brush; struct ImBuf; struct ImagePool; +struct Object; struct Main; +struct MTex; struct Scene; struct ToolSettings; struct UnifiedPaintSettings; @@ -109,6 +111,7 @@ float BKE_brush_curve_strength(const struct Brush *br, float p, float len); */ float BKE_brush_sample_tex_3d(const struct Scene *scene, const struct Brush *br, + const struct MTex *mtex, const float point[3], float rgba[4], int thread, @@ -120,6 +123,24 @@ float BKE_brush_sample_masktex(const struct Scene *scene, struct ImagePool *pool); /** + * Get the mask texture for this given object mode. + * + * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these + * attributes got switched in sculpt mode. + */ +const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush, + const eObjectMode object_mode); + +/** + * Get the color texture for this given object mode. + * + * This is preferred above using mtex/mask_mtex attributes directly as due to legacy these + * attributes got switched in sculpt mode. + */ +const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush, + const eObjectMode object_mode); + +/** * Radial control. */ struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 4b9d78e45ec..512982adb7c 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -288,7 +288,7 @@ bool CTX_data_dir(const char *member); CTX_DATA_BEGIN (C, Type, instance, member) \ Type_id instance_id = (Type_id)ctx_link->ptr.owner_id; -int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBase *)); +int ctx_data_list_count(const bContext *C, bool (*func)(const bContext *, ListBase *)); #define CTX_DATA_COUNT(C, member) ctx_data_list_count(C, CTX_data_##member) @@ -319,22 +319,22 @@ void CTX_data_main_set(bContext *C, struct Main *bmain); void CTX_data_scene_set(bContext *C, struct Scene *scene); /* Only Outliner currently! */ -int CTX_data_selected_ids(const bContext *C, ListBase *list); +bool CTX_data_selected_ids(const bContext *C, ListBase *list); -int CTX_data_selected_editable_objects(const bContext *C, ListBase *list); -int CTX_data_selected_editable_bases(const bContext *C, ListBase *list); +bool CTX_data_selected_editable_objects(const bContext *C, ListBase *list); +bool CTX_data_selected_editable_bases(const bContext *C, ListBase *list); -int CTX_data_editable_objects(const bContext *C, ListBase *list); -int CTX_data_editable_bases(const bContext *C, ListBase *list); +bool CTX_data_editable_objects(const bContext *C, ListBase *list); +bool CTX_data_editable_bases(const bContext *C, ListBase *list); -int CTX_data_selected_objects(const bContext *C, ListBase *list); -int CTX_data_selected_bases(const bContext *C, ListBase *list); +bool CTX_data_selected_objects(const bContext *C, ListBase *list); +bool CTX_data_selected_bases(const bContext *C, ListBase *list); -int CTX_data_visible_objects(const bContext *C, ListBase *list); -int CTX_data_visible_bases(const bContext *C, ListBase *list); +bool CTX_data_visible_objects(const bContext *C, ListBase *list); +bool CTX_data_visible_bases(const bContext *C, ListBase *list); -int CTX_data_selectable_objects(const bContext *C, ListBase *list); -int CTX_data_selectable_bases(const bContext *C, ListBase *list); +bool CTX_data_selectable_objects(const bContext *C, ListBase *list); +bool CTX_data_selectable_bases(const bContext *C, ListBase *list); struct Object *CTX_data_active_object(const bContext *C); struct Base *CTX_data_active_base(const bContext *C); @@ -348,25 +348,25 @@ struct Mask *CTX_data_edit_mask(const bContext *C); struct CacheFile *CTX_data_edit_cachefile(const bContext *C); -int CTX_data_selected_nodes(const bContext *C, ListBase *list); +bool CTX_data_selected_nodes(const bContext *C, ListBase *list); struct EditBone *CTX_data_active_bone(const bContext *C); -int CTX_data_selected_bones(const bContext *C, ListBase *list); -int CTX_data_selected_editable_bones(const bContext *C, ListBase *list); -int CTX_data_visible_bones(const bContext *C, ListBase *list); -int CTX_data_editable_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_editable_bones(const bContext *C, ListBase *list); +bool CTX_data_visible_bones(const bContext *C, ListBase *list); +bool CTX_data_editable_bones(const bContext *C, ListBase *list); struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C); -int CTX_data_selected_pose_bones(const bContext *C, ListBase *list); -int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list); -int CTX_data_visible_pose_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_pose_bones(const bContext *C, ListBase *list); +bool CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list); +bool CTX_data_visible_pose_bones(const bContext *C, ListBase *list); struct bGPdata *CTX_data_gpencil_data(const bContext *C); struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C); struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C); -int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); -int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); -int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); +bool CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); +bool CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); +bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); const struct AssetLibraryReference *CTX_wm_asset_library_ref(const bContext *C); struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid); diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index 44c4df1fc2e..a0732bf39cf 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -76,16 +76,20 @@ typedef struct DupliObject { unsigned int random_id; } DupliObject; -/** Look up the RGBA value of a uniform shader attribute. - * \return true if the attribute was found; if not, r_value is also set to zero. */ +/** + * Look up the RGBA value of a uniform shader attribute. + * \return true if the attribute was found; if not, r_value is also set to zero. + */ bool BKE_object_dupli_find_rgba_attribute(struct Object *ob, struct DupliObject *dupli, struct Object *dupli_parent, const char *name, float r_value[4]); -/** Look up the RGBA value of a view layer/scene/world shader attribute. - * \return true if the attribute was found; if not, r_value is also set to zero. */ +/** + * Look up the RGBA value of a view layer/scene/world shader attribute. + * \return true if the attribute was found; if not, r_value is also set to zero. + */ bool BKE_view_layer_find_rgba_attribute(struct Scene *scene, struct ViewLayer *layer, const char *name, diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index b9219814c08..976961f27ae 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -332,8 +332,12 @@ bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps, * \param gps: Target stroke. * \param index_from: the index of the first point to be used in the trimmed result. * \param index_to: the index of the last point to be used in the trimmed result. + * \param keep_point: Keep strokes with one point. False remove the single points strokes */ -bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps, int index_from, int index_to); +bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps, + int index_from, + int index_to, + const bool keep_point); /** * Split the given stroke into several new strokes, partitioning * it based on whether the stroke points have a particular flag diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh index 6502fefec88..f17ebba0dfa 100644 --- a/source/blender/blenkernel/BKE_instances.hh +++ b/source/blender/blenkernel/BKE_instances.hh @@ -5,7 +5,7 @@ /** \file * \ingroup bke * - * #Instances is a container for geometry instances. It fullfills some key requirements: + * #Instances is a container for geometry instances. It fulfills some key requirements: * - Support nested instances. * - Support instance attributes. * - Support referencing different kinds of instances (objects, collections, geometry sets). diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 0fe351c0aa4..6cae56b775f 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -167,9 +167,9 @@ void BKE_keyblock_update_from_offset(const struct Object *ob, * Move shape key from org_index to new_index. Safe, clamps index to valid range, * updates reference keys, the object's active shape index, * the 'frame' value in case of absolute keys, etc. - * Note indices are expected in real values (not 'fake' shapenr +1 ones). + * Note indices are expected in real values (not *fake* `shapenr +1` ones). * - * \param org_index: if < 0, current object's active shape will be used as skey to move. + * \param org_index: if < 0, current object's active shape will be used as shape-key to move. * \return true if something was done, else false. */ bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index); diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index efadd5c11d6..2913beee759 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -249,8 +249,8 @@ float BKE_nlastrip_compute_frame_to_next_strip(struct NlaStrip *strip); /** * Returns the next strip in this strip's NLA track, or a null pointer. * - * \param strip The strip to find the next trip from. - * \param check_transitions Whether or not to skip transitions. + * \param strip: The strip to find the next trip from. + * \param check_transitions: Whether or not to skip transitions. * \return The next strip in the track, or NULL if none are present. */ struct NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_transitions); @@ -258,8 +258,8 @@ struct NlaStrip *BKE_nlastrip_next_in_track(struct NlaStrip *strip, bool skip_tr /** * Returns the previous strip in this strip's NLA track, or a null pointer. * - * \param strip The strip to find the previous trip from. - * \param check_transitions Whether or not to skip transitions. + * \param strip: The strip to find the previous trip from. + * \param check_transitions: Whether or not to skip transitions. * \return The previous strip in the track, or NULL if none are present. */ struct NlaStrip *BKE_nlastrip_prev_in_track(struct NlaStrip *strip, bool skip_transitions); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 60dfc0af25f..5cbd7937f3f 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -323,7 +323,7 @@ struct Base **BKE_object_pose_base_array_get(const struct Scene *scene, void BKE_object_get_parent_matrix(struct Object *ob, struct Object *par, float r_parentmat[4][4]); /** - * Compute object world transform and store it in `ob->obmat`. + * Compute object world transform and store it in `ob->object_to_world`. */ void BKE_object_where_is_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_object_where_is_calc_ex(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 437a22e4782..9fc4aa5307d 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -886,7 +886,7 @@ void BKE_sculpt_sync_face_visibility_to_grids(struct Mesh *mesh, struct SubdivCC * Test if PBVH can be used directly for drawing, which is faster than * drawing the mesh and all updates that come with it. */ -bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d); +bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct RegionView3D *rv3d); enum { SCULPT_MASK_LAYER_CALC_VERT = (1 << 0), diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index efb8c2a9bb1..4331a25c112 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -293,6 +293,7 @@ void BKE_ptcache_ids_from_object(struct ListBase *lb, bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis); /************ ID specific functions ************************/ + void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra); bool BKE_ptcache_id_exist(PTCacheID *id, int cfra); int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 9a7d2bde810..a86953f35cc 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -385,6 +385,7 @@ typedef struct MenuType { bool (*poll)(const struct bContext *C, struct MenuType *mt); /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct Menu *menu); + void (*listener)(const wmRegionListenerParams *params); /* RNA integration */ ExtensionRNA rna_ext; diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index f3a929dc5b9..5d1a27f8ba0 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -75,7 +75,7 @@ typedef struct UndoStep { /** Some situations require the global state to be stored, edge cases when exiting modes. */ bool use_memfile_step; /** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged - * IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */ + * IDs, and existing depsgraphs. This has to be forbidden in some cases (like renamed IDs). */ bool use_old_bmain_data; /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */ bool is_applied; diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h index 736f7548bb4..cfe246eb470 100644 --- a/source/blender/blenkernel/BKE_writeffmpeg.h +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -27,6 +27,7 @@ enum { FFMPEG_OGG = 10, FFMPEG_INVALID = 11, FFMPEG_WEBM = 12, + FFMPEG_AV1 = 13, }; enum { @@ -38,6 +39,7 @@ enum { FFMPEG_PRESET_H264 = 5, FFMPEG_PRESET_THEORA = 6, FFMPEG_PRESET_XVID = 7, + FFMPEG_PRESET_AV1 = 8, }; struct RenderData; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 10aa4ec7906..8f6bd812d8e 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1738,7 +1738,7 @@ void what_does_obaction(Object *ob, BKE_object_workob_clear(workob); /* init workob */ - copy_m4_m4(workob->obmat, ob->obmat); + copy_m4_m4(workob->object_to_world, ob->object_to_world); copy_m4_m4(workob->parentinv, ob->parentinv); copy_m4_m4(workob->constinv, ob->constinv); workob->parent = ob->parent; diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 965f48d1e51..b3990b2b7fc 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -237,7 +237,7 @@ bool BKE_appdir_font_folder_default(char *dir) } #elif defined(__APPLE__) STRNCPY(test_dir, BLI_expand_tilde("~/Library/Fonts/")); - BLI_path_slash_ensure(test_dir); + BLI_path_slash_ensure(test_dir, sizeof(test_dir)); #else STRNCPY(test_dir, "/usr/share/fonts"); #endif @@ -1093,13 +1093,13 @@ void BKE_appdir_app_templates(ListBase *templates) * \param userdir: Directory specified in user preferences (may be NULL). * note that by default this is an empty string, only use when non-empty. */ -static void where_is_temp(char *tempdir, const size_t tempdir_len, const char *userdir) +static void where_is_temp(char *tempdir, const size_t tempdir_maxlen, const char *userdir) { tempdir[0] = '\0'; if (userdir && BLI_is_dir(userdir)) { - BLI_strncpy(tempdir, userdir, tempdir_len); + BLI_strncpy(tempdir, userdir, tempdir_maxlen); } if (tempdir[0] == '\0') { @@ -1116,23 +1116,23 @@ static void where_is_temp(char *tempdir, const size_t tempdir_len, const char *u for (int i = 0; i < ARRAY_SIZE(env_vars); i++) { const char *tmp = BLI_getenv(env_vars[i]); if (tmp && (tmp[0] != '\0') && BLI_is_dir(tmp)) { - BLI_strncpy(tempdir, tmp, tempdir_len); + BLI_strncpy(tempdir, tmp, tempdir_maxlen); break; } } } if (tempdir[0] == '\0') { - BLI_strncpy(tempdir, "/tmp/", tempdir_len); + BLI_strncpy(tempdir, "/tmp/", tempdir_maxlen); } else { /* add a trailing slash if needed */ - BLI_path_slash_ensure(tempdir); + BLI_path_slash_ensure(tempdir, tempdir_maxlen); } } static void tempdir_session_create(char *tempdir_session, - const size_t tempdir_session_len, + const size_t tempdir_session_maxlen, const char *tempdir) { tempdir_session[0] = '\0'; @@ -1146,9 +1146,9 @@ static void tempdir_session_create(char *tempdir_session, * #_mktemp_s also requires the last null character is included. */ const int tempdir_session_len_required = tempdir_len + session_name_len + 1; - if (tempdir_session_len_required <= tempdir_session_len) { + if (tempdir_session_len_required <= tempdir_session_maxlen) { /* No need to use path joining utility as we know the last character of #tempdir is a slash. */ - BLI_string_join(tempdir_session, tempdir_session_len, tempdir, session_name); + BLI_string_join(tempdir_session, tempdir_session_maxlen, tempdir, session_name); #ifdef WIN32 const bool needs_create = (_mktemp_s(tempdir_session, tempdir_session_len_required) == 0); #else @@ -1158,7 +1158,7 @@ static void tempdir_session_create(char *tempdir_session, BLI_dir_create_recursive(tempdir_session); } if (BLI_is_dir(tempdir_session)) { - BLI_path_slash_ensure(tempdir_session); + BLI_path_slash_ensure(tempdir_session, tempdir_session_maxlen); /* Success. */ return; } @@ -1168,7 +1168,7 @@ static void tempdir_session_create(char *tempdir_session, "Could not generate a temp file name for '%s', falling back to '%s'", tempdir_session, tempdir); - BLI_strncpy(tempdir_session, tempdir, tempdir_session_len); + BLI_strncpy(tempdir_session, tempdir, tempdir_session_maxlen); } void BKE_tempdir_init(const char *userdir) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 2e73cac99b5..0f8bf0e9928 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1596,7 +1596,7 @@ void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float o } /* Get inverse of (armature) object's matrix. */ - invert_m4_m4(obmat, ob->obmat); + invert_m4_m4(obmat, ob->object_to_world); /* multiply given matrix by object's-inverse to find pose-space matrix */ mul_m4_m4m4(outmat, inmat, obmat); @@ -2569,7 +2569,7 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob) } } else { - invert_m4_m4(ob->imat, ob->obmat); /* imat is needed */ + invert_m4_m4(ob->imat, ob->object_to_world); /* imat is needed */ /* 1. clear flags */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -2696,14 +2696,14 @@ void BKE_pchan_minmax(const Object *ob, pchan->custom_translation[0], pchan->custom_translation[1], pchan->custom_translation[2]); - mul_m4_series(mat, ob->obmat, tmp, rmat, smat); + mul_m4_series(mat, ob->object_to_world, tmp, rmat, smat); BKE_boundbox_minmax(bb_custom, mat, r_min, r_max); } else { float vec[3]; - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head); + mul_v3_m4v3(vec, ob->object_to_world, pchan_tx->pose_head); minmax_v3v3_v3(r_min, r_max, vec); - mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail); + mul_v3_m4v3(vec, ob->object_to_world, pchan_tx->pose_tail); minmax_v3v3_v3(r_min, r_max, vec); } } diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c index 89afb886fc2..64a3937c191 100644 --- a/source/blender/blenkernel/intern/armature_deform.c +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -582,9 +582,9 @@ static void armature_deform_coords_impl(const Object *ob_arm, }; float obinv[4][4]; - invert_m4_m4(obinv, ob_target->obmat); + invert_m4_m4(obinv, ob_target->object_to_world); - mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat); + mul_m4_m4m4(data.postmat, obinv, ob_arm->object_to_world); invert_m4_m4(data.premat, data.postmat); if (em_target != NULL) { diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 6d7aed239e7..b9f46118c0d 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -249,7 +249,7 @@ static void apply_curve_transform( * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root). */ if ((ik_data->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) { - mul_m4_v3(ik_data->tar->obmat, r_vec); + mul_m4_v3(ik_data->tar->object_to_world, r_vec); } /* Convert the position to pose-space. */ @@ -819,7 +819,7 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec BLI_assert((object->pose->flag & POSE_RECALC) == 0); /* imat is needed for solvers. */ - invert_m4_m4(object->imat, object->obmat); + invert_m4_m4(object->imat, object->object_to_world); /* clear flags */ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index 38c712d7e75..62d03b2d79b 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -9,6 +9,7 @@ #include "BKE_asset_catalog.hh" #include "BKE_asset_library.h" +#include "BKE_asset_library.hh" #include "BLI_fileops.hh" #include "BLI_path_util.h" @@ -787,6 +788,41 @@ void AssetCatalogTree::foreach_root_item(const ItemIterFn callback) } } +bool AssetCatalogTree::is_empty() const +{ + return root_items_.empty(); +} + +AssetCatalogTreeItem *AssetCatalogTree::find_item(const AssetCatalogPath &path) +{ + AssetCatalogTreeItem *result = nullptr; + this->foreach_item([&](AssetCatalogTreeItem &item) { + if (result) { + /* There is no way to stop iteration. */ + return; + } + if (item.catalog_path() == path) { + result = &item; + } + }); + return result; +} + +AssetCatalogTreeItem *AssetCatalogTree::find_root_item(const AssetCatalogPath &path) +{ + AssetCatalogTreeItem *result = nullptr; + this->foreach_root_item([&](AssetCatalogTreeItem &item) { + if (result) { + /* There is no way to stop iteration. */ + return; + } + if (item.catalog_path() == path) { + result = &item; + } + }); + return result; +} + /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/asset_catalog_path.cc b/source/blender/blenkernel/intern/asset_catalog_path.cc index 669adb7adf4..9c653c1a137 100644 --- a/source/blender/blenkernel/intern/asset_catalog_path.cc +++ b/source/blender/blenkernel/intern/asset_catalog_path.cc @@ -12,7 +12,7 @@ namespace blender::bke { const char AssetCatalogPath::SEPARATOR = '/'; -AssetCatalogPath::AssetCatalogPath(const std::string &path) : path_(path) +AssetCatalogPath::AssetCatalogPath(std::string path) : path_(std::move(path)) { } diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc index 543b71e9da8..6a667d572a0 100644 --- a/source/blender/blenkernel/intern/asset_library.cc +++ b/source/blender/blenkernel/intern/asset_library.cc @@ -10,6 +10,7 @@ #include "BKE_asset_library_custom.h" #include "BKE_main.h" +#include "BLI_fileops.h" #include "BLI_path_util.h" #include "DNA_asset_types.h" @@ -19,6 +20,13 @@ bool blender::bke::AssetLibrary::save_catalogs_when_file_is_saved = true; +blender::bke::AssetLibrary *BKE_asset_library_load(const Main *bmain, + const AssetLibraryReference &library_reference) +{ + blender::bke::AssetLibraryService *service = blender::bke::AssetLibraryService::get(); + return service->get_asset_library(bmain, library_reference); +} + /** * Loading an asset library at this point only means loading the catalogs. Later on this should * invoke reading of asset representations too. @@ -172,4 +180,26 @@ void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data) } STRNCPY(asset_data->catalog_simple_name, catalog->simple_name.c_str()); } + +Vector<AssetLibraryReference> all_valid_asset_library_refs() +{ + Vector<AssetLibraryReference> result; + int i; + LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) { + if (!BLI_is_dir(asset_library->path)) { + continue; + } + AssetLibraryReference library_ref{}; + library_ref.custom_library_index = i; + library_ref.type = ASSET_LIBRARY_CUSTOM; + result.append(library_ref); + } + + AssetLibraryReference library_ref{}; + library_ref.custom_library_index = -1; + library_ref.type = ASSET_LIBRARY_LOCAL; + result.append(library_ref); + return result; +} + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc index a6b2b7548a2..cd8de7908bf 100644 --- a/source/blender/blenkernel/intern/asset_library_service.cc +++ b/source/blender/blenkernel/intern/asset_library_service.cc @@ -7,11 +7,15 @@ #include "asset_library_service.hh" #include "BKE_blender.h" +#include "BKE_preferences.h" #include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BLI_string_ref.hh" +#include "DNA_asset_types.h" +#include "DNA_userdef_types.h" + #include "CLG_log.h" static CLG_LogRef LOG = {"bke.asset_service"}; @@ -38,13 +42,45 @@ void AssetLibraryService::destroy() instance_.reset(); } +AssetLibrary *AssetLibraryService::get_asset_library( + const Main *bmain, const AssetLibraryReference &library_reference) +{ + if (library_reference.type == ASSET_LIBRARY_LOCAL) { + /* For the "Current File" library we get the asset library root path based on main. */ + char root_path[FILE_MAX]; + if (bmain) { + BKE_asset_library_find_suitable_root_path_from_main(bmain, root_path); + } + else { + root_path[0] = '\0'; + } + + if (root_path[0] == '\0') { + /* File wasn't saved yet. */ + return get_asset_library_current_file(); + } + + return get_asset_library_on_disk(root_path); + } + if (library_reference.type == ASSET_LIBRARY_CUSTOM) { + bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( + &U, library_reference.custom_library_index); + + if (user_library) { + return get_asset_library_on_disk(user_library->path); + } + } + + return nullptr; +} + namespace { std::string normalize_directory_path(StringRefNull directory) { char dir_normalized[PATH_MAX]; STRNCPY(dir_normalized, directory.c_str()); - BLI_path_normalize_dir(nullptr, dir_normalized); + BLI_path_normalize_dir(nullptr, dir_normalized, sizeof(dir_normalized)); return std::string(dir_normalized); } } // namespace diff --git a/source/blender/blenkernel/intern/asset_library_service.hh b/source/blender/blenkernel/intern/asset_library_service.hh index 277fb9db6cc..c22c6b182ce 100644 --- a/source/blender/blenkernel/intern/asset_library_service.hh +++ b/source/blender/blenkernel/intern/asset_library_service.hh @@ -44,6 +44,9 @@ class AssetLibraryService { /** Destroy the AssetLibraryService singleton. It will be reallocated by #get() if necessary. */ static void destroy(); + AssetLibrary *get_asset_library(const Main *bmain, + const AssetLibraryReference &library_reference); + /** * Get the given asset library. Opens it (i.e. creates a new AssetLibrary instance) if necessary. */ diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc index d105c5644de..7952e7ea3b0 100644 --- a/source/blender/blenkernel/intern/asset_library_service_test.cc +++ b/source/blender/blenkernel/intern/asset_library_service_test.cc @@ -118,7 +118,7 @@ TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes) asset_lib_no_slash[strlen(asset_lib_no_slash) - 1] = '\0'; } - BLI_path_slash_ensure(asset_lib_with_slash); + BLI_path_slash_ensure(asset_lib_with_slash, PATH_MAX); AssetLibrary *const lib_no_slash = service->get_asset_library_on_disk(asset_lib_no_slash); diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index b86353bdb74..544427cfdd3 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -642,15 +642,26 @@ CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other) size_ = other.size_; data = other.data; CustomData_reset(&other.data); + other.size_ = 0; } CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes &other) { - if (this != &other) { - CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_); - size_ = other.size_; + if (this == &other) { + return *this; } + this->~CustomDataAttributes(); + new (this) CustomDataAttributes(other); + return *this; +} +CustomDataAttributes &CustomDataAttributes::operator=(CustomDataAttributes &&other) +{ + if (this == &other) { + return *this; + } + this->~CustomDataAttributes(); + new (this) CustomDataAttributes(std::move(other)); return *this; } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 23cf368af01..3598201d906 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -59,7 +59,7 @@ void BKE_blender_free(void) { /* samples are in a global list..., also sets G_MAIN->sound->sample NULL */ - /* Needs to run before main free as wm is still referenced for icons preview jobs. */ + /* Needs to run before main free as window-manager is still referenced for icons preview jobs. */ BKE_studiolight_free(); BKE_blender_globals_clear(); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index e39c8756d96..f625f06d4d0 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -187,7 +187,7 @@ static void setup_app_data(bContext *C, clean_paths(bfd->main); } - /* XXX here the complex windowmanager matching */ + /* The following code blocks performs complex window-manager matching. */ /* no load screens? */ if (mode != LOAD_UI) { diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index 394469e19a4..4dd225c09ec 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -1494,6 +1494,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, * code is wrong, we need to redo it here after adding them back to main. */ BKE_main_id_refcount_recompute(bmain, false); + BKE_layer_collection_resync_forbid(); /* Note that in reload case, we also want to replace indirect usages. */ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); @@ -1523,6 +1524,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, id_us_plus_no_lib(&old_key->id); } } + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync_remap(bmain); BKE_main_unlock(bmain); @@ -1614,6 +1617,9 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, (id->tag & LIB_TAG_PRE_EXISTING) == 0) { continue; } + if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) { + id->tag &= ~LIB_TAG_MISSING; + } if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { BKE_lib_override_library_update(bmain, id); } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 2e07b52c7bf..a0458f0f8d8 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -959,7 +959,7 @@ void boids_precalc_rules(ParticleSettings *part, float cfra) if (flbr->ob && flbr->cfra != cfra) { /* save object locations for velocity calculations */ copy_v3_v3(flbr->oloc, flbr->loc); - copy_v3_v3(flbr->loc, flbr->ob->obmat[3]); + copy_v3_v3(flbr->loc, flbr->ob->object_to_world[3]); flbr->cfra = cfra; } } diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 20d86ea5a2d..6f1435e90b8 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -1974,19 +1974,37 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset) BKE_curvemapping_changed(cumap, false); } +const struct MTex *BKE_brush_mask_texture_get(const struct Brush *brush, + const eObjectMode object_mode) +{ + if (object_mode == OB_MODE_SCULPT) { + return &brush->mtex; + } + return &brush->mask_mtex; +} + +const struct MTex *BKE_brush_color_texture_get(const struct Brush *brush, + const eObjectMode object_mode) +{ + if (object_mode == OB_MODE_SCULPT) { + return &brush->mask_mtex; + } + return &brush->mtex; +} + float BKE_brush_sample_tex_3d(const Scene *scene, const Brush *br, + const MTex *mtex, const float point[3], float rgba[4], const int thread, struct ImagePool *pool) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - const MTex *mtex = &br->mtex; float intensity = 1.0; bool hasrgb = false; - if (!mtex->tex) { + if (mtex == nullptr || mtex->tex == nullptr) { intensity = 1; } else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 8608ce97397..7c1193d80ab 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -221,16 +221,16 @@ float BKE_camera_object_dof_distance(const Object *ob) } if (cam->dof.focus_object) { float view_dir[3], dof_dir[3]; - normalize_v3_v3(view_dir, ob->obmat[2]); + normalize_v3_v3(view_dir, ob->object_to_world[2]); bPoseChannel *pchan = BKE_pose_channel_find_name(cam->dof.focus_object->pose, cam->dof.focus_subtarget); if (pchan) { float posemat[4][4]; - mul_m4_m4m4(posemat, cam->dof.focus_object->obmat, pchan->pose_mat); - sub_v3_v3v3(dof_dir, ob->obmat[3], posemat[3]); + mul_m4_m4m4(posemat, cam->dof.focus_object->object_to_world, pchan->pose_mat); + sub_v3_v3v3(dof_dir, ob->object_to_world[3], posemat[3]); } else { - sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]); + sub_v3_v3v3(dof_dir, ob->object_to_world[3], cam->dof.focus_object->object_to_world[3]); } return fabsf(dot_v3v3(view_dir, dof_dir)); } @@ -628,7 +628,7 @@ static void camera_frame_fit_data_init(const Scene *scene, BKE_camera_params_compute_matrix(params); /* initialize callback data */ - copy_m3_m4(data->camera_rotmat, (float(*)[4])ob->obmat); + copy_m3_m4(data->camera_rotmat, (float(*)[4])ob->object_to_world); normalize_m3(data->camera_rotmat); /* To transform a plane which is in its homogeneous representation (4d vector), * we need the inverse of the transpose of the transform matrix... */ @@ -828,7 +828,7 @@ bool BKE_camera_view_frame_fit_to_coords(const Depsgraph *depsgraph, static void camera_model_matrix(const Object *camera, float r_modelmat[4][4]) { - copy_m4_m4(r_modelmat, camera->obmat); + copy_m4_m4(r_modelmat, camera->object_to_world); } static void camera_stereo3d_model_matrix(const Object *camera, @@ -854,7 +854,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, } float size[3]; - mat4_to_size(size, camera->obmat); + mat4_to_size(size, camera->object_to_world); size_to_mat4(sizemat, size); if (pivot == CAM_S3D_PIVOT_CENTER) { @@ -894,7 +894,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, toeinmat[3][0] = interocular_distance * fac_signed; /* transform */ - normalize_m4_m4(r_modelmat, camera->obmat); + normalize_m4_m4(r_modelmat, camera->object_to_world); mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat); /* scale back to the original size */ @@ -902,7 +902,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, } else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */ /* rotate perpendicular to the interocular line */ - normalize_m4_m4(r_modelmat, camera->obmat); + normalize_m4_m4(r_modelmat, camera->object_to_world); mul_m4_m4m4(r_modelmat, r_modelmat, rotmat); /* translate along the interocular line */ @@ -918,7 +918,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, } } else { - normalize_m4_m4(r_modelmat, camera->obmat); + normalize_m4_m4(r_modelmat, camera->object_to_world); /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */ translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 89983eb8f62..910869bbc72 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -269,7 +269,7 @@ static int do_step_cloth( /* Get the current position. */ copy_v3_v3(verts->xconst, mvert[i].co); - mul_m4_v3(ob->obmat, verts->xconst); + mul_m4_v3(ob->object_to_world, verts->xconst); if (vert_mass_changed) { verts->mass = clmd->sim_parms->mass; @@ -581,7 +581,7 @@ static void cloth_to_object(Object *ob, ClothModifierData *clmd, float (*vertexC if (clmd->clothObject) { /* Inverse matrix is not up to date. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); for (i = 0; i < cloth->mvert_num; i++) { copy_v3_v3(vertexCos[i], cloth->verts[i].x); @@ -763,11 +763,11 @@ static bool cloth_from_object( if (first) { copy_v3_v3(verts->x, mvert[i].co); - mul_m4_v3(ob->obmat, verts->x); + mul_m4_v3(ob->object_to_world, verts->x); if (shapekey_rest) { copy_v3_v3(verts->xrest, shapekey_rest[i]); - mul_m4_v3(ob->obmat, verts->xrest); + mul_m4_v3(ob->object_to_world, verts->xrest); } else { copy_v3_v3(verts->xrest, verts->x); @@ -1155,7 +1155,7 @@ static void cloth_update_verts(Object *ob, ClothModifierData *clmd, Mesh *mesh) /* vertex count is already ensured to match */ for (i = 0; i < mesh->totvert; i++, verts++) { copy_v3_v3(verts->xrest, mvert[i].co); - mul_m4_v3(ob->obmat, verts->xrest); + mul_m4_v3(ob->object_to_world, verts->xrest); } } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index a6a6a1ca28f..1f288aef5ad 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -149,7 +149,7 @@ bConstraintOb *BKE_constraints_make_evalob( /* Quats/Axis-Angle, so Eulers should just use default order */ cob->rotOrder = EULER_ORDER_DEFAULT; } - copy_m4_m4(cob->matrix, ob->obmat); + copy_m4_m4(cob->matrix, ob->object_to_world); } else { unit_m4(cob->matrix); @@ -175,7 +175,7 @@ bConstraintOb *BKE_constraints_make_evalob( } /* matrix in world-space */ - mul_m4_m4m4(cob->matrix, ob->obmat, cob->pchan->pose_mat); + mul_m4_m4m4(cob->matrix, ob->object_to_world, cob->pchan->pose_mat); } else { unit_m4(cob->matrix); @@ -216,7 +216,7 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob) /* cob->ob might not exist! */ if (cob->ob) { /* copy new ob-matrix back to owner */ - copy_m4_m4(cob->ob->obmat, cob->matrix); + copy_m4_m4(cob->ob->object_to_world, cob->matrix); /* copy inverse of delta back to owner */ invert_m4_m4(cob->ob->constinv, delta); @@ -276,7 +276,7 @@ void BKE_constraint_mat_convertspace(Object *ob, } else { /* World to pose. */ - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_m4_m4m4(mat, imat, mat); /* Use pose-space as stepping stone for other spaces. */ @@ -319,7 +319,7 @@ void BKE_constraint_mat_convertspace(Object *ob, } else { /* Pose to world. */ - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); /* Use world-space as stepping stone for other spaces. */ if (to != CONSTRAINT_SPACE_WORLD) { /* Call self with slightly different values. */ @@ -429,7 +429,7 @@ void BKE_constraint_mat_convertspace(Object *ob, /* Check if object has a parent. */ if (ob->parent) { /* 'subtract' parent's effects from owner. */ - mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); + mul_m4_m4m4(diff_mat, ob->parent->object_to_world, ob->parentinv); invert_m4_m4_safe(imat, diff_mat); mul_m4_m4m4(mat, imat, mat); } @@ -465,7 +465,7 @@ void BKE_constraint_mat_convertspace(Object *ob, /* check that object has a parent - otherwise this won't work */ if (ob->parent) { /* 'add' parent's effect back to owner */ - mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); + mul_m4_m4m4(diff_mat, ob->parent->object_to_world, ob->parentinv); mul_m4_m4m4(mat, diff_mat, mat); } else { @@ -518,7 +518,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ const int defgroup = BKE_object_defgroup_name_index(ob, substring); /* initialize target matrix using target matrix */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* get index of vertex group */ if (defgroup == -1) { @@ -584,7 +584,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ * calc_gizmo_stats, V3D_ORIENT_NORMAL case */ /* We need the transpose of the inverse for a normal. */ - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3_m3(tmat, imat); transpose_m3(tmat); @@ -605,7 +605,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[ normalize_m4(mat); /* apply the average coordinate as the new location */ - mul_v3_m4v3(mat[3], ob->obmat, vec); + mul_v3_m4v3(mat[3], ob->object_to_world, vec); } /* function that sets the given matrix based on given vertex group in lattice */ @@ -627,7 +627,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m const int defgroup = BKE_object_defgroup_name_index(ob, substring); /* initialize target matrix using target matrix */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* get index of vertex group */ if (defgroup == -1) { @@ -661,11 +661,11 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m } } - /* find average location, then multiply by ob->obmat to find world-space location */ + /* find average location, then multiply by ob->object_to_world to find world-space location */ if (grouped) { mul_v3_fl(vec, 1.0f / grouped); } - mul_v3_m4v3(tvec, ob->obmat, vec); + mul_v3_m4v3(tvec, ob->object_to_world, vec); /* copy new location to matrix */ copy_v3_v3(mat[3], tvec); @@ -684,7 +684,7 @@ static void constraint_target_to_mat4(Object *ob, { /* Case OBJECT */ if (substring[0] == '\0') { - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false); } /* Case VERTEXGROUP */ @@ -719,7 +719,7 @@ static void constraint_target_to_mat4(Object *ob, if (headtail < 0.000001f && !(is_bbone && full_bbone)) { /* skip length interpolation if set to head */ - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat); } else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) { /* use point along bbone */ @@ -745,7 +745,7 @@ static void constraint_target_to_mat4(Object *ob, mul_v3_m4v3(tempmat[3], pchan->pose_mat, loc); } - mul_m4_m4m4(mat, ob->obmat, tempmat); + mul_m4_m4m4(mat, ob->object_to_world, tempmat); } else { float tempmat[4][4], loc[3]; @@ -757,11 +757,11 @@ static void constraint_target_to_mat4(Object *ob, copy_m4_m4(tempmat, pchan->pose_mat); copy_v3_v3(tempmat[3], loc); - mul_m4_m4m4(mat, ob->obmat, tempmat); + mul_m4_m4m4(mat, ob->object_to_world, tempmat); } } else { - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); } /* convert matrix space as required */ @@ -1069,7 +1069,7 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar if (data->flag & CHILDOF_SET_INVERSE) { invert_m4_m4(data->invmat, parmat); if (cob->pchan != NULL) { - mul_m4_series(data->invmat, data->invmat, cob->ob->obmat); + mul_m4_series(data->invmat, data->invmat, cob->ob->object_to_world); } copy_m4_m4(inverse_matrix, data->invmat); @@ -1388,8 +1388,8 @@ static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), else { float vec[3]; /* move grabtarget into world space */ - mul_v3_m4v3(vec, ob->obmat, data->grabtarget); - copy_m4_m4(ct->matrix, ob->obmat); + mul_v3_m4v3(vec, ob->object_to_world, data->grabtarget); + copy_m4_m4(ct->matrix, ob->object_to_world); copy_v3_v3(ct->matrix[3], vec); } } @@ -1528,7 +1528,7 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph), copy_v3_v3(totmat[3], vec); - mul_m4_m4m4(ct->matrix, ct->tar->obmat, totmat); + mul_m4_m4m4(ct->matrix, ct->tar->object_to_world, totmat); } } } @@ -2557,7 +2557,7 @@ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); if (pchan != NULL) { - mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat); + mul_m4_m4m4(ct->matrix, ct->tar->object_to_world, pchan->pose_mat); return; } } @@ -2613,7 +2613,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, float weight = ct->weight; /* Our object's location in target pose space. */ - invert_m4_m4(iobmat, ct->tar->obmat); + invert_m4_m4(iobmat, ct->tar->object_to_world); mul_v3_m4v3(co, iobmat, wco); /* Multiply by the envelope weight when appropriate. */ @@ -2644,7 +2644,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, mul_m4_m4m4(basemat, bone->arm_mat, b_bone_rest_mats[index].mat); } - armdef_accumulate_matrix(ct->tar->obmat, + armdef_accumulate_matrix(ct->tar->object_to_world, iobmat, basemat, b_bone_mats[index + 1].mat, @@ -2657,7 +2657,7 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, mul_m4_m4m4(basemat, bone->arm_mat, b_bone_rest_mats[index + 1].mat); } - armdef_accumulate_matrix(ct->tar->obmat, + armdef_accumulate_matrix(ct->tar->object_to_world, iobmat, basemat, b_bone_mats[index + 2].mat, @@ -2667,8 +2667,13 @@ static void armdef_accumulate_bone(bConstraintTarget *ct, } else { /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */ - armdef_accumulate_matrix( - ct->tar->obmat, iobmat, bone->arm_mat, pchan->chan_mat, weight, r_sum_mat, r_sum_dq); + armdef_accumulate_matrix(ct->tar->object_to_world, + iobmat, + bone->arm_mat, + pchan->chan_mat, + weight, + r_sum_mat, + r_sum_dq); } /* Accumulate the weight. */ @@ -2694,7 +2699,7 @@ static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ /* For constraints on bones, use the rest position to bind b-bone segments * and envelopes, to allow safely changing the bone location as if parented. */ copy_v3_v3(input_co, cob->pchan->bone->arm_head); - mul_m4_v3(cob->ob->obmat, input_co); + mul_m4_v3(cob->ob->object_to_world, input_co); } else { copy_v3_v3(input_co, cob->matrix[3]); @@ -3927,7 +3932,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar unit_m4(totmat); copy_v3_v3(totmat[3], vec); - mul_m4_m4m4(targetMatrix, ct->tar->obmat, totmat); + mul_m4_m4m4(targetMatrix, ct->tar->object_to_world, totmat); } } @@ -4227,7 +4232,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), if (BKE_shrinkwrap_init_tree( &tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) { - BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat); + BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->object_to_world); switch (scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: @@ -4902,7 +4907,7 @@ static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *co /* Object matrix of the camera. */ float camera_obmat[4][4]; - copy_m4_m4(camera_obmat, camera_object->obmat); + copy_m4_m4(camera_obmat, camera_object->object_to_world); /* Calculate inverted matrix of the solved camera at the current time. */ float reconstructed_camera_mat[4][4]; @@ -5054,10 +5059,10 @@ static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *co } float depth_object_mat_inv[4][4]; - invert_m4_m4(depth_object_mat_inv, depth_object->obmat); + invert_m4_m4(depth_object_mat_inv, depth_object->object_to_world); float ray_start[3], ray_end[3]; - mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->obmat[3]); + mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->object_to_world[3]); mul_v3_m4v3(ray_end, depth_object_mat_inv, cob->matrix[3]); float ray_direction[3]; @@ -5080,7 +5085,7 @@ static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *co &tree_data); if (result != -1) { - mul_v3_m4v3(cob->matrix[3], depth_object->obmat, hit.co); + mul_v3_m4v3(cob->matrix[3], depth_object->object_to_world, hit.co); } free_bvhtree_from_mesh(&tree_data); @@ -5128,9 +5133,9 @@ static void followtrack_evaluate_using_2d_position(FollowTrackContext *context, } float disp[3]; - mul_v3_m4v3(disp, camera_object->obmat, vec); + mul_v3_m4v3(disp, camera_object->object_to_world, vec); - copy_m4_m4(rmat, camera_object->obmat); + copy_m4_m4(rmat, camera_object->object_to_world); zero_v3(rmat[3]); mul_m4_m4m4(cob->matrix, cob->matrix, rmat); @@ -5152,10 +5157,10 @@ static void followtrack_evaluate_using_2d_position(FollowTrackContext *context, } float disp[3]; - mul_v3_m4v3(disp, camera_object->obmat, vec); + mul_v3_m4v3(disp, camera_object->object_to_world, vec); /* apply camera rotation so Z-axis would be co-linear */ - copy_m4_m4(rmat, camera_object->obmat); + copy_m4_m4(rmat, camera_object->object_to_world); zero_v3(rmat[3]); mul_m4_m4m4(cob->matrix, cob->matrix, rmat); @@ -5303,7 +5308,7 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); invert_m4_m4(imat, mat); - mul_m4_m4m4(parmat, camob->obmat, imat); + mul_m4_m4m4(parmat, camob->object_to_world, imat); copy_m4_m4(obmat, cob->matrix); @@ -5650,7 +5655,7 @@ bool BKE_constraint_apply_for_object(Depsgraph *depsgraph, BLI_freelinkN(&single_con, new_con); /* Apply transform from matrix. */ - BKE_object_apply_mat4(ob, ob_eval->obmat, true, true); + BKE_object_apply_mat4(ob, ob_eval->object_to_world, true, true); return true; } @@ -6237,7 +6242,7 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, cob->ob = (Object *)ownerdata; cob->pchan = NULL; if (cob->ob) { - copy_m4_m4(cob->matrix, cob->ob->obmat); + copy_m4_m4(cob->matrix, cob->ob->object_to_world); copy_m4_m4(cob->startmat, cob->matrix); } else { diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index e44058032fc..ed6f55cc8f9 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -394,37 +394,37 @@ static void *ctx_data_pointer_get(const bContext *C, const char *member) return NULL; } -static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer) +static bool ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer) { /* if context is NULL, pointer must be NULL too and that is a valid return */ if (C == NULL) { *pointer = NULL; - return 1; + return true; } bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == CTX_RESULT_OK) { BLI_assert(result.type == CTX_DATA_TYPE_POINTER); *pointer = result.ptr.data; - return 1; + return true; } *pointer = NULL; - return 0; + return false; } -static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list) +static bool ctx_data_collection_get(const bContext *C, const char *member, ListBase *list) { bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == CTX_RESULT_OK) { BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION); *list = result.list; - return 1; + return true; } BLI_listbase_clear(list); - return 0; + return false; } static int ctx_data_base_collection_get(const bContext *C, const char *member, ListBase *list) @@ -682,7 +682,7 @@ void CTX_data_list_add_ptr(bContextDataResult *result, const PointerRNA *ptr) BLI_addtail(&result->list, link); } -int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBase *)) +int ctx_data_list_count(const bContext *C, bool (*func)(const bContext *, ListBase *)) { ListBase list; @@ -1306,62 +1306,62 @@ ToolSettings *CTX_data_tool_settings(const bContext *C) return NULL; } -int CTX_data_selected_ids(const bContext *C, ListBase *list) +bool CTX_data_selected_ids(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_ids", list); } -int CTX_data_selected_nodes(const bContext *C, ListBase *list) +bool CTX_data_selected_nodes(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_nodes", list); } -int CTX_data_selected_editable_objects(const bContext *C, ListBase *list) +bool CTX_data_selected_editable_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_editable_objects", list); } -int CTX_data_selected_editable_bases(const bContext *C, ListBase *list) +bool CTX_data_selected_editable_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "selected_editable_objects", list); } -int CTX_data_editable_objects(const bContext *C, ListBase *list) +bool CTX_data_editable_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_objects", list); } -int CTX_data_editable_bases(const bContext *C, ListBase *list) +bool CTX_data_editable_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "editable_objects", list); } -int CTX_data_selected_objects(const bContext *C, ListBase *list) +bool CTX_data_selected_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_objects", list); } -int CTX_data_selected_bases(const bContext *C, ListBase *list) +bool CTX_data_selected_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "selected_objects", list); } -int CTX_data_visible_objects(const bContext *C, ListBase *list) +bool CTX_data_visible_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_objects", list); } -int CTX_data_visible_bases(const bContext *C, ListBase *list) +bool CTX_data_visible_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "visible_objects", list); } -int CTX_data_selectable_objects(const bContext *C, ListBase *list) +bool CTX_data_selectable_objects(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selectable_objects", list); } -int CTX_data_selectable_bases(const bContext *C, ListBase *list) +bool CTX_data_selectable_bases(const bContext *C, ListBase *list) { return ctx_data_base_collection_get(C, "selectable_objects", list); } @@ -1419,22 +1419,22 @@ struct CacheFile *CTX_data_edit_cachefile(const bContext *C) return ctx_data_pointer_get(C, "edit_cachefile"); } -int CTX_data_selected_bones(const bContext *C, ListBase *list) +bool CTX_data_selected_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_bones", list); } -int CTX_data_selected_editable_bones(const bContext *C, ListBase *list) +bool CTX_data_selected_editable_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_editable_bones", list); } -int CTX_data_visible_bones(const bContext *C, ListBase *list) +bool CTX_data_visible_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_bones", list); } -int CTX_data_editable_bones(const bContext *C, ListBase *list) +bool CTX_data_editable_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_bones", list); } @@ -1444,17 +1444,17 @@ struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C) return ctx_data_pointer_get(C, "active_pose_bone"); } -int CTX_data_selected_pose_bones(const bContext *C, ListBase *list) +bool CTX_data_selected_pose_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_pose_bones", list); } -int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list) +bool CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list); } -int CTX_data_visible_pose_bones(const bContext *C, ListBase *list) +bool CTX_data_visible_pose_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_pose_bones", list); } @@ -1474,17 +1474,17 @@ bGPDframe *CTX_data_active_gpencil_frame(const bContext *C) return ctx_data_pointer_get(C, "active_gpencil_frame"); } -int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list) +bool CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_gpencil_layers", list); } -int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list) +bool CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_gpencil_layers", list); } -int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list) +bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_gpencil_strokes", list); } diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 190e2d3bb7e..f83c321c4ae 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -70,47 +70,48 @@ static void set_crazy_vertex_quat(float r_quat[4], sub_qt_qtqt(r_quat, q2, q1); } -static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob) +static bool modifiers_disable_subsurf_temporary(Object *ob, const int cageIndex) { - bool disabled = false; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); + bool changed = false; ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first); for (int i = 0; md && i <= cageIndex; i++, md = md->next) { if (md->type == eModifierType_Subsurf) { md->mode ^= eModifierMode_DisableTemporary; - disabled = true; + changed = true; } } - return disabled; + return changed; } float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object *obedit))[3] { - Scene *scene = DEG_get_input_scene(depsgraph); Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - Mesh *mesh_eval = static_cast<Mesh *>(obedit_eval->data); - BMEditMesh *editmesh_eval = mesh_eval->edit_mesh; + const int cageIndex = BKE_modifiers_get_cage_index(scene_eval, obedit_eval, nullptr, true); - /* disable subsurf temporal, get mapped cos, and enable it */ - if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) { - /* Need to make new derived-mesh. */ + /* Disable subsurf temporal, get mapped cos, and enable it. */ + if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) { + /* Need to make new cage. + * TODO: Avoid losing original evaluated geometry. */ makeDerivedMesh(depsgraph, scene_eval, obedit_eval, &CD_MASK_BAREMESH); } - /* now get the cage */ - Mesh *mesh_eval_cage = editbmesh_get_eval_cage_from_orig( - depsgraph, scene, obedit, &CD_MASK_BAREMESH); + /* Now get the cage. */ + BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval); + Mesh *mesh_eval_cage = editbmesh_get_eval_cage( + depsgraph, scene_eval, obedit_eval, em_eval, &CD_MASK_BAREMESH); - const int nverts = editmesh_eval->bm->totvert; + const int nverts = em_eval->bm->totvert; float(*vertexcos)[3] = static_cast<float(*)[3]>( MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map")); mesh_get_mapped_verts_coords(mesh_eval_cage, vertexcos, nverts); - /* set back the flag, no new cage needs to be built, transform does it */ - modifiers_disable_subsurf_temporary(scene_eval, obedit_eval); + /* Set back the flag, and ensure new cage needs to be built. */ + if (modifiers_disable_subsurf_temporary(obedit_eval, cageIndex)) { + DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + } return vertexcos; } diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c index 9a27ba91c2f..066d8494451 100644 --- a/source/blender/blenkernel/intern/curve_deform.c +++ b/source/blender/blenkernel/intern/curve_deform.c @@ -44,8 +44,8 @@ typedef struct { static void init_curve_deform(const Object *ob_curve, const Object *ob_target, CurveDeform *cd) { float imat[4][4]; - invert_m4_m4(imat, ob_target->obmat); - mul_m4_m4m4(cd->objectspace, imat, ob_curve->obmat); + invert_m4_m4(imat, ob_target->object_to_world); + mul_m4_m4m4(cd->objectspace, imat, ob_curve->object_to_world); invert_m4_m4(cd->curvespace, cd->objectspace); copy_m3_m4(cd->objectspace3, cd->objectspace); cd->no_rot_axis = 0; diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index b9fea2a27b8..ecf3be9bd81 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -332,7 +332,8 @@ static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_a static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes, const AttributeAccessor &mesh_attributes, - const AttributeIDRef &id) + const AttributeIDRef &id, + const AttributeMetaData &meta_data) { /* The position attribute has special non-generic evaluation. */ @@ -346,6 +347,9 @@ static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attribut if (!id.should_be_kept()) { return false; } + if (meta_data.data_type == CD_PROP_STRING) { + return false; + } return true; } @@ -714,7 +718,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write(); main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { - if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) { + if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id, meta_data)) { return true; } main_attributes_set.add_new(id); @@ -751,7 +755,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, if (main_attributes.contains(id)) { return true; } - if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) { + if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id, meta_data)) { return true; } const eAttrDomain src_domain = meta_data.domain; diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 01be22a57b0..61755a5be9b 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -287,7 +287,10 @@ static void curves_evaluate_modifiers(struct Depsgraph *depsgraph, { /* Modifier evaluation modes. */ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + if (BKE_object_is_in_editmode(object)) { + required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode); + } ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; @@ -409,11 +412,11 @@ void curves_copy_parameters(const Curves &src, Curves &dst) CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const Object *surface_ob) { - this->curves_to_world = curves_ob.obmat; + this->curves_to_world = curves_ob.object_to_world; this->world_to_curves = this->curves_to_world.inverted(); if (surface_ob != nullptr) { - this->surface_to_world = surface_ob->obmat; + this->surface_to_world = surface_ob->object_to_world; this->world_to_surface = this->surface_to_world.inverted(); this->surface_to_curves = this->world_to_curves * this->surface_to_world; this->curves_to_surface = this->world_to_surface * this->curves_to_world; diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index f5c845443f1..7c338480c71 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -9,6 +9,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.hh" #include "BLI_bounds.hh" #include "BLI_index_mask_ops.hh" #include "BLI_length_parameterize.hh" @@ -1111,21 +1112,11 @@ static void copy_between_buffers(const CPPType &type, src_range.size()); } -template<typename T> -static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst) -{ - threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) { - for (const int i : range) { - dst[i] = src[map[i]]; - } - }); -} - static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst) { attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); - copy_with_map(src.typed<T>(), map, dst.typed<T>()); + array_utils::gather(src.typed<T>(), map, dst.typed<T>()); }); } @@ -1233,6 +1224,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, attribute.dst.finish(); } + if (new_curves.curves_num() != curves.curves_num()) { + new_curves.remove_attributes_based_on_types(); + } + return new_curves; } @@ -1338,6 +1333,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, attribute.dst.finish(); } + new_curves.remove_attributes_based_on_types(); + return new_curves; } @@ -1402,6 +1399,9 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) if (meta_data.domain != ATTR_DOMAIN_POINT) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } if (id.is_named() && bezier_handle_names.contains(id.name())) { return true; } diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 6f2390fc28f..03a0f17a4bb 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -19,6 +19,7 @@ #include "BLI_bitmap.h" #include "BLI_color.hh" +#include "BLI_cpp_type_make.hh" #include "BLI_endian_switch.h" #include "BLI_index_range.hh" #include "BLI_math.h" @@ -5387,6 +5388,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type) return &CPPType::get<int8_t>(); case CD_PROP_BYTE_COLOR: return &CPPType::get<ColorGeometry4b>(); + case CD_PROP_STRING: + return &CPPType::get<MStringProperty>(); default: return nullptr; } @@ -5419,6 +5422,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) if (type.is<ColorGeometry4b>()) { return CD_PROP_BYTE_COLOR; } + if (type.is<MStringProperty>()) { + return CD_PROP_STRING; + } return static_cast<eCustomDataType>(-1); } @@ -5430,3 +5436,5 @@ size_t CustomData_get_elem_size(CustomDataLayer *layer) { return LAYERTYPEINFO[layer->type].size; } + +BLI_CPP_TYPE_MAKE(MStringProperty, MStringProperty, CPPTypeFlags::None); diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index e177250ae5a..b9cec17b6e0 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -3783,7 +3783,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, numOfVerts_p = mesh_p->totvert; mvert_p = BKE_mesh_verts_for_write(mesh_p); - copy_m4_m4(prev_obmat, ob->obmat); + copy_m4_m4(prev_obmat, ob->object_to_world); /* current frame mesh */ scene->r.cfra = cur_fra; @@ -3816,7 +3816,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, .brush_vel = *brushVel, .mvert_p = mvert_p, .mvert_c = mvert_c, - .obmat = ob->obmat, + .obmat = ob->object_to_world, .prev_obmat = prev_obmat, .timescale = timescale, }; @@ -3856,7 +3856,7 @@ static void dynamicPaint_brushObjectCalculateVelocity( SUBFRAME_RECURSION, BKE_scene_ctime_get(scene), eModifierType_DynamicPaint); - copy_m4_m4(prev_obmat, ob->obmat); + copy_m4_m4(prev_obmat, ob->object_to_world); /* current frame mesh */ scene->r.cfra = cur_fra; @@ -3871,7 +3871,7 @@ static void dynamicPaint_brushObjectCalculateVelocity( /* calculate speed */ mul_m4_v3(prev_obmat, prev_loc); - mul_m4_v3(ob->obmat, cur_loc); + mul_m4_v3(ob->object_to_world, cur_loc); sub_v3_v3v3(brushVel->v, cur_loc, prev_loc); mul_v3_fl(brushVel->v, 1.0f / timescale); @@ -4279,14 +4279,14 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph, * (Faster than transforming per surface point * coordinates and normals to object space) */ for (ii = 0; ii < numOfVerts; ii++) { - mul_m4_v3(brushOb->obmat, mvert[ii].co); + mul_m4_v3(brushOb->object_to_world, mvert[ii].co); boundInsert(&mesh_bb, mvert[ii].co); /* for proximity project calculate average normal */ if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) { float nor[3]; copy_v3_v3(nor, vert_normals[ii]); - mul_mat3_m4_v3(brushOb->obmat, nor); + mul_mat3_m4_v3(brushOb->object_to_world, nor); normalize_v3(nor); add_v3_v3(avg_brushNor, nor); @@ -5870,7 +5870,7 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o } /* matrix comparison */ - if (!equals_m4m4(bData->prev_obmat, ob->obmat)) { + if (!equals_m4m4(bData->prev_obmat, ob->object_to_world)) { return true; } @@ -5957,7 +5957,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata, mul_v3_v3v3(scaled_nor, temp_nor, ob->scale); bData->bNormal[index].normal_scale = len_v3(scaled_nor); } - mul_mat3_m4_v3(ob->obmat, temp_nor); + mul_mat3_m4_v3(ob->object_to_world, temp_nor); normalize_v3(temp_nor); negate_v3_v3(bData->bNormal[index].invNorm, temp_nor); } @@ -5995,7 +5995,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata, mul_v3_v3v3(scaled_nor, temp_nor, ob->scale); bData->bNormal[index].normal_scale = len_v3(scaled_nor); } - mul_mat3_m4_v3(ob->obmat, temp_nor); + mul_mat3_m4_v3(ob->object_to_world, temp_nor); normalize_v3(temp_nor); negate_v3_v3(bData->bNormal[index].invNorm, temp_nor); } @@ -6113,7 +6113,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface, bData->mesh_bounds.valid = false; for (index = 0; index < canvasNumOfVerts; index++) { copy_v3_v3(canvas_verts[index].v, mvert[index].co); - mul_m4_v3(ob->obmat, canvas_verts[index].v); + mul_m4_v3(ob->object_to_world, canvas_verts[index].v); boundInsert(&bData->mesh_bounds, canvas_verts[index].v); } @@ -6143,7 +6143,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface, dynamicPaint_prepareAdjacencyData(surface, false); /* Copy current frame vertices to check against in next frame */ - copy_m4_m4(bData->prev_obmat, ob->obmat); + copy_m4_m4(bData->prev_obmat, ob->object_to_world); memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert)); bData->clear = 0; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 42b38854248..983e4b3c6e6 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -154,8 +154,8 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef if (eff->ob->runtime.curve_cache->anim_path_accum_length) { BKE_where_on_path( eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL); - mul_m4_v3(eff->ob->obmat, eff->guide_loc); - mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir); + mul_m4_v3(eff->ob->object_to_world, eff->guide_loc); + mul_mat3_m4_v3(eff->ob->object_to_world, eff->guide_dir); } } } @@ -707,8 +707,8 @@ bool get_effector_data(EffectorCache *eff, copy_v3_v3(efd->loc, verts[*efd->index].co); copy_v3_v3(efd->nor, vert_normals[*efd->index]); - mul_m4_v3(eff->ob->obmat, efd->loc); - mul_mat3_m4_v3(eff->ob->obmat, efd->nor); + mul_m4_v3(eff->ob->object_to_world, efd->loc); + mul_mat3_m4_v3(eff->ob->object_to_world, efd->nor); normalize_v3(efd->nor); @@ -760,23 +760,23 @@ bool get_effector_data(EffectorCache *eff, const Object *ob = eff->ob; /* Use z-axis as normal. */ - normalize_v3_v3(efd->nor, ob->obmat[2]); + normalize_v3_v3(efd->nor, ob->object_to_world[2]); if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) { float temp[3], translate[3]; - sub_v3_v3v3(temp, point->loc, ob->obmat[3]); + sub_v3_v3v3(temp, point->loc, ob->object_to_world[3]); project_v3_v3v3(translate, temp, efd->nor); /* for vortex the shape chooses between old / new force */ if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) { - add_v3_v3v3(efd->loc, ob->obmat[3], translate); + add_v3_v3v3(efd->loc, ob->object_to_world[3], translate); } else { /* normally efd->loc is closest point on effector xy-plane */ sub_v3_v3v3(efd->loc, point->loc, translate); } } else { - copy_v3_v3(efd->loc, ob->obmat[3]); + copy_v3_v3(efd->loc, ob->object_to_world[3]); } zero_v3(efd->vel); @@ -801,8 +801,8 @@ bool get_effector_data(EffectorCache *eff, } else { /* for some effectors we need the object center every time */ - sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]); - normalize_v3_v3(efd->nor2, eff->ob->obmat[2]); + sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->object_to_world[3]); + normalize_v3_v3(efd->nor2, eff->ob->object_to_world[2]); } } diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index 9f63e2d3743..3d1439b5530 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -321,7 +321,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) } else { /* Object. */ - mat[i] = ob->obmat; + mat[i] = ob->object_to_world; } } @@ -399,7 +399,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) else { /* Convert to world-space. */ copy_v3_v3(tmp_loc, pchan->pose_head); - mul_m4_v3(ob->obmat, tmp_loc); + mul_m4_v3(ob->object_to_world, tmp_loc); } } else { @@ -410,7 +410,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) float mat[4][4]; /* Extract transform just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); BKE_constraint_mat_convertspace( ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); @@ -424,7 +424,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) } else { /* World-space. */ - copy_v3_v3(tmp_loc, ob->obmat[3]); + copy_v3_v3(tmp_loc, ob->object_to_world[3]); } } @@ -500,7 +500,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) } else { /* World-space matrix. */ - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat); } } else { @@ -514,7 +514,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCALSPACE) { if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* Just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); BKE_constraint_mat_convertspace( ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); } @@ -525,7 +525,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) } else { /* World-space matrix - just the good-old one. */ - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); } } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 5470231cd07..b0e99e10acc 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -433,7 +433,7 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *fds, copy_v3_v3(fds->global_size, size); copy_v3_v3(fds->dp0, min); - invert_m4_m4(fds->imat, ob->obmat); + invert_m4_m4(fds->imat, ob->object_to_world); /* Prevent crash when initializing a plane as domain. */ if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || @@ -498,8 +498,8 @@ static bool fluid_modifier_init( zero_v3(fds->shift_f); add_v3_fl(fds->shift_f, 0.5f); zero_v3(fds->prev_loc); - mul_m4_v3(ob->obmat, fds->prev_loc); - copy_m4_m4(fds->obmat, ob->obmat); + mul_m4_v3(ob->object_to_world, fds->prev_loc); + copy_m4_m4(fds->obmat, ob->object_to_world); /* Set resolutions. */ if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS && @@ -566,11 +566,11 @@ static int get_light(Scene *scene, ViewLayer *view_layer, float *light) Light *la = base_tmp->object->data; if (la->type == LA_LOCAL) { - copy_v3_v3(light, base_tmp->object->obmat[3]); + copy_v3_v3(light, base_tmp->object->object_to_world[3]); return 1; } if (!found_light) { - copy_v3_v3(light, base_tmp->object->obmat[3]); + copy_v3_v3(light, base_tmp->object->object_to_world[3]); found_light = 1; } } @@ -1036,7 +1036,7 @@ static void obstacles_from_mesh(Object *coll_ob, float co[3]; /* Vertex position. */ - mul_m4_v3(coll_ob->obmat, verts[i].co); + mul_m4_v3(coll_ob->object_to_world, verts[i].co); manta_pos_to_cell(fds, verts[i].co); /* Vertex velocity. */ @@ -2099,11 +2099,11 @@ static void emit_from_mesh( float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me); for (i = 0; i < numverts; i++) { /* Vertex position. */ - mul_m4_v3(flow_ob->obmat, verts[i].co); + mul_m4_v3(flow_ob->object_to_world, verts[i].co); manta_pos_to_cell(fds, verts[i].co); /* Vertex normal. */ - mul_mat3_m4_v3(flow_ob->obmat, vert_normals[i]); + mul_mat3_m4_v3(flow_ob->object_to_world, vert_normals[i]); mul_mat3_m4_v3(fds->imat, vert_normals[i]); normalize_v3(vert_normals[i]); @@ -2121,7 +2121,7 @@ static void emit_from_mesh( /* Calculate emission map bounds. */ bb_boundInsert(bb, verts[i].co); } - mul_m4_v3(flow_ob->obmat, flow_center); + mul_m4_v3(flow_ob->object_to_world, flow_center); manta_pos_to_cell(fds, flow_center); /* Set emission map. @@ -2191,7 +2191,7 @@ static void adaptive_domain_adjust( float frame_shift_f[3]; float ob_loc[3] = {0}; - mul_m4_v3(ob->obmat, ob_loc); + mul_m4_v3(ob->object_to_world, ob_loc); sub_v3_v3v3(frame_shift_f, ob_loc, fds->prev_loc); copy_v3_v3(fds->prev_loc, ob_loc); @@ -3495,8 +3495,8 @@ static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obje /* Calculate required shift to match domain's global position * it was originally simulated at (if object moves without manta step). */ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->obmat, ob_loc); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_m4_v3(ob->object_to_world, ob_loc); mul_m4_v3(fds->obmat, ob_cache_loc); sub_v3_v3v3(fds->obj_shift_f, ob_cache_loc, ob_loc); /* Convert shift to local space and apply to vertices. */ @@ -3525,8 +3525,8 @@ static int manta_step( bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY); /* Update object state. */ - invert_m4_m4(fds->imat, ob->obmat); - copy_m4_m4(fds->obmat, ob->obmat); + invert_m4_m4(fds->imat, ob->object_to_world); + copy_m4_m4(fds->obmat, ob->object_to_world); /* Gas domain might use adaptive domain. */ if (fds->type == FLUID_DOMAIN_TYPE_GAS) { diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 90568a8a080..ee4c398c3d6 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -607,7 +607,10 @@ void GeometrySet::gather_attributes_for_propagation( return; } } - + if (meta_data.data_type == CD_PROP_STRING) { + /* Propagating string attributes is not supported yet. */ + return; + } if (!attribute_id.should_be_kept()) { return; } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index e078991187d..2b36020b4e7 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -98,7 +98,7 @@ static void geometry_set_collect_recursive_collection(const Collection &collecti LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) { BLI_assert(collection_object->ob != nullptr); const Object &object = *collection_object->ob; - const float4x4 object_transform = transform * object.obmat; + const float4x4 object_transform = transform * object.object_to_world; geometry_set_collect_recursive_object(object, object_transform, r_sets); } LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) { @@ -220,7 +220,7 @@ void Instances::ensure_geometry_instances() Collection &collection = reference.collection(); FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) { const int handle = instances->add_reference(*object); - instances->add_instance(handle, object->obmat); + instances->add_instance(handle, object->object_to_world); float4x4 &transform = instances->transforms().last(); sub_v3_v3(transform.values[3], collection.instance_offset); } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 45e56717d6a..666142e3a54 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -2691,7 +2691,7 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, /* if not layer parented, try with object parented */ if (obparent_eval == NULL) { if ((ob_eval != NULL) && (ob_eval->type == OB_GPENCIL)) { - copy_m4_m4(diff_mat, ob_eval->obmat); + copy_m4_m4(diff_mat, ob_eval->object_to_world); mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; } @@ -2701,8 +2701,8 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, } if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { - mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + mul_m4_m4m4(diff_mat, obparent_eval->object_to_world, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]); mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; } @@ -2710,14 +2710,14 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr); if (pchan) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat); + mul_m4_m4m4(tmp_mat, obparent_eval->object_to_world, pchan->pose_mat); mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]); } else { /* if bone not found use object (armature) */ - mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + mul_m4_m4m4(diff_mat, obparent_eval->object_to_world, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->object_to_world[3]); } mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; @@ -2771,12 +2771,12 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob) Object *ob_parent = DEG_get_evaluated_object(depsgraph, gpl->parent); /* calculate new matrix */ if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { - mul_m4_m4m4(cur_mat, ob->imat, ob_parent->obmat); + mul_m4_m4m4(cur_mat, ob->imat, ob_parent->object_to_world); } else if (gpl->partype == PARBONE) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob_parent->pose, gpl->parsubstr); if (pchan != NULL) { - mul_m4_series(cur_mat, ob->imat, ob_parent->obmat, pchan->pose_mat); + mul_m4_series(cur_mat, ob->imat, ob_parent->object_to_world, pchan->pose_mat); } else { unit_m4(cur_mat); diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index 52fcdef8a43..9297663b157 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -789,7 +789,10 @@ bool BKE_gpencil_stroke_stretch(bGPDstroke *gps, /** \name Stroke Trim * \{ */ -bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to) +bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, + const int index_from, + const int index_to, + const bool keep_point) { bGPDspoint *pt = gps->points, *new_pt; MDeformVert *dv, *new_dv; @@ -800,7 +803,7 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const return false; } - if (new_count == 1) { + if ((!keep_point) && (new_count == 1)) { if (gps->dvert) { BKE_gpencil_free_stroke_weights(gps); MEM_freeN(gps->dvert); @@ -894,7 +897,7 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd, /* Trim the original stroke into a shorter one. * Keep the end point. */ - BKE_gpencil_stroke_trim_points(gps, 0, old_count); + BKE_gpencil_stroke_trim_points(gps, 0, old_count, false); BKE_gpencil_stroke_geometry_update(gpd, gps); return true; } @@ -917,7 +920,7 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo if (gps->totpoints == 1) { second_last = &pt[1]; if (len_v3v3(&second_last->x, &pt->x) < dist) { - BKE_gpencil_stroke_trim_points(gps, 0, 0); + BKE_gpencil_stroke_trim_points(gps, 0, 0, false); return true; } } @@ -969,7 +972,7 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo index_start = index_end = 0; /* no length left to cut */ } - BKE_gpencil_stroke_trim_points(gps, index_start, index_end); + BKE_gpencil_stroke_trim_points(gps, index_start, index_end, false); if (gps->totpoints == 0) { return false; @@ -3562,8 +3565,8 @@ void BKE_gpencil_stroke_start_set(bGPDstroke *gps, int start_idx) } bGPDstroke *gps_b = BKE_gpencil_stroke_duplicate(gps, true, false); - BKE_gpencil_stroke_trim_points(gps_b, 0, start_idx - 1); - BKE_gpencil_stroke_trim_points(gps, start_idx, gps->totpoints - 1); + BKE_gpencil_stroke_trim_points(gps_b, 0, start_idx - 1, true); + BKE_gpencil_stroke_trim_points(gps, start_idx, gps->totpoints - 1, true); /* Join both strokes. */ BKE_gpencil_stroke_join(gps, gps_b, false, false, false, false); diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index c84ee2e4a56..1ad7aeed41c 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -942,7 +942,7 @@ void BKE_gpencil_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb) BLO_read_data_address(reader, &gpmd->curve_intensity); if (gpmd->curve_intensity) { BKE_curvemapping_blend_read(reader, gpmd->curve_intensity); - /* initialize the curve. Maybe this could be moved to modififer logic */ + /* Initialize the curve. Maybe this could be moved to modifier logic. */ BKE_curvemapping_init(gpmd->curve_intensity); } } diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index dc1d23de7e0..7fd0515b52c 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -530,7 +530,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) thumb = IMB_thumb_manage(filepath, THB_LARGE, (ThumbSource)source); if (thumb) { - /* PreviewImage assumes premultiplied alhpa... */ + /* #PreviewImage assumes pre-multiplied alpha. */ IMB_premultiply_alpha(thumb); if (do_preview) { diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 51d8f02616f..eae8b454189 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -3082,16 +3082,10 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) /* Free all but the first tile. */ image_remove_all_tiles(ima); - /* If the remaining tile is generated, we need to again ensure that we - * wouldn't continue to use the old filepath. - * - * Otherwise, if this used to be a UDIM image, get the concrete filepath associated + /* If this used to be a UDIM image, get the concrete filepath associated * with the remaining tile and use that as the new filepath. */ ImageTile *base_tile = BKE_image_get_tile(ima, 0); - if ((base_tile->gen_flag & IMA_GEN_TILE) != 0) { - ima->filepath[0] = '\0'; - } - else if (BKE_image_is_filename_tokenized(ima->filepath)) { + if (BKE_image_is_filename_tokenized(ima->filepath)) { const bool was_relative = BLI_path_is_rel(ima->filepath); eUDIM_TILE_FORMAT tile_format; @@ -3183,10 +3177,14 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) * left. */ image_remove_all_tiles(ima); - int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + int remaining_tile_number = base_tile->tile_number; bool needs_final_cleanup = true; - /* Add in all the new tiles. */ + /* Add in all the new tiles. As the image is proven to be on disk at this point, remove + * the generation flag from the remaining tile in case this was previously a generated + * image. */ + base_tile->gen_flag &= ~IMA_GEN_TILE; LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) { int new_tile_number = POINTER_AS_INT(new_tile->data); BKE_image_add_tile(ima, new_tile_number, nullptr); @@ -3202,6 +3200,11 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) } BLI_freelistN(&new_tiles); } + else if (ima->filepath[0] != '\0') { + /* If the filepath is set at this point remove the generation flag. */ + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + base_tile->gen_flag &= ~IMA_GEN_TILE; + } if (iuser) { image_tag_reload(ima, nullptr, iuser, ima); diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc index 8d1aeac76fb..5b861eff166 100644 --- a/source/blender/blenkernel/intern/image_format.cc +++ b/source/blender/blenkernel/intern/image_format.cc @@ -201,6 +201,7 @@ bool BKE_imtype_is_movie(const char imtype) case R_IMF_IMTYPE_H264: case R_IMF_IMTYPE_THEORA: case R_IMF_IMTYPE_XVID: + case R_IMF_IMTYPE_AV1: return true; } return false; @@ -433,7 +434,8 @@ static bool do_add_image_extension(char *string, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, - R_IMF_IMTYPE_XVID)) { + R_IMF_IMTYPE_XVID, + R_IMF_IMTYPE_AV1)) { if (!BLI_path_extension_check(string, extension_test = ".png")) { extension = extension_test; } @@ -627,7 +629,8 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf) R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, - R_IMF_IMTYPE_XVID)) { + R_IMF_IMTYPE_XVID, + R_IMF_IMTYPE_AV1)) { ibuf->ftype = IMB_FTYPE_PNG; if (imtype == R_IMF_IMTYPE_PNG) { diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 4e47e71fb2b..003211e6288 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -968,6 +968,7 @@ bool BKE_image_render_write(ReportList *reports, /* optional preview images for exr */ if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { image_format.imtype = R_IMF_IMTYPE_JPEG90; + image_format.depth = R_IMF_CHAN_DEPTH_8; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; @@ -1025,6 +1026,7 @@ bool BKE_image_render_write(ReportList *reports, /* optional preview images for exr */ if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { image_format.imtype = R_IMF_IMTYPE_JPEG90; + image_format.depth = R_IMF_CHAN_DEPTH_8; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc index dd759453630..4675562e927 100644 --- a/source/blender/blenkernel/intern/instances.cc +++ b/source/blender/blenkernel/intern/instances.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_cpp_type_make.hh" #include "BLI_rand.hh" #include "BLI_task.hh" @@ -107,18 +108,6 @@ blender::Span<InstanceReference> Instances::references() const return references_; } -template<typename T> -static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask) -{ - BLI_assert(src.data() != dst.data()); - using namespace blender; - threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { - for (const int i : range) { - dst[i] = src[mask[i]]; - } - }); -} - void Instances::remove(const IndexMask mask) { using namespace blender; @@ -129,11 +118,14 @@ void Instances::remove(const IndexMask mask) return; } + const Span<int> old_handles = this->reference_handles(); Vector<int> new_handles(mask.size()); - copy_data_based_on_mask<int>(this->reference_handles(), new_handles, mask); + array_utils::gather(old_handles, mask.indices(), new_handles.as_mutable_span()); reference_handles_ = std::move(new_handles); + + const Span<float4x4> old_tansforms = this->transforms(); Vector<float4x4> new_transforms(mask.size()); - copy_data_based_on_mask<float4x4>(this->transforms(), new_transforms, mask); + array_utils::gather(old_tansforms, mask.indices(), new_transforms.as_mutable_span()); transforms_ = std::move(new_transforms); const bke::CustomDataAttributes &src_attributes = attributes_; @@ -150,11 +142,8 @@ void Instances::remove(const IndexMask mask) GSpan src = *src_attributes.get_for_read(id); dst_attributes.create(id, meta_data.data_type); GMutableSpan dst = *dst_attributes.get_for_write(id); + array_utils::gather(src, mask.indices(), dst); - attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { - using T = decltype(dummy); - copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask); - }); return true; }, ATTR_DOMAIN_INSTANCE); @@ -266,7 +255,7 @@ bool Instances::owns_direct_data() const void Instances::ensure_owns_direct_data() { for (const InstanceReference &const_reference : references_) { - /* Const cast is fine because we are not changing anything that would change the hash of the + /* `const` cast is fine because we are not changing anything that would change the hash of the * reference. */ InstanceReference &reference = const_cast<InstanceReference &>(const_reference); reference.ensure_owns_direct_data(); diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index bd655caae2b..a21033a8b91 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1147,7 +1147,7 @@ static char *get_rna_access(ID *id, /* 'buf' _must_ be initialized in this block */ /* append preceding bits to path */ - /* NOTE: strings are not escapted and they should be! */ + /* NOTE: strings are not escaped and they should be! */ if ((actname && actname[0]) && (constname && constname[0])) { /* Constraint in Pose-Channel */ char actname_esc[sizeof(((bActionChannel *)NULL)->name) * 2]; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index f6a409ee3f0..0adf162b4eb 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -355,10 +355,10 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) BKE_displist_free(<Ob->runtime.curve_cache->disp); } - copy_m4_m4(mat, ltOb->obmat); - unit_m4(ltOb->obmat); + copy_m4_m4(mat, ltOb->object_to_world); + unit_m4(ltOb->object_to_world); BKE_lattice_deform_coords(ltOb, NULL, vert_coords, uNew * vNew * wNew, 0, NULL, 1.0f); - copy_m4_m4(ltOb->obmat, mat); + copy_m4_m4(ltOb->object_to_world, mat); lt->typeu = typeu; lt->typev = typev; diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c index 3a1c42b9178..892889aa426 100644 --- a/source/blender/blenkernel/intern/lattice_deform.c +++ b/source/blender/blenkernel/intern/lattice_deform.c @@ -79,15 +79,15 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob /* for example with a particle system: (ob == NULL) */ if (ob == NULL) { /* In deform-space, calc matrix. */ - invert_m4_m4(latmat, oblatt->obmat); + invert_m4_m4(latmat, oblatt->object_to_world); /* back: put in deform array */ invert_m4_m4(imat, latmat); } else { /* In deform-space, calc matrix. */ - invert_m4_m4(imat, oblatt->obmat); - mul_m4_m4m4(latmat, imat, ob->obmat); + invert_m4_m4(imat, oblatt->object_to_world); + mul_m4_m4m4(latmat, imat, ob->object_to_world); /* back: put in deform array. */ invert_m4_m4(imat, latmat); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 06d69b6ff61..5b54f16661c 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -614,7 +614,7 @@ static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc) return true; } - /* Check visiblilty restriction flags */ + /* Check visibility restriction flags */ if (lc->flag & LAYER_COLLECTION_HIDE || lc->collection->flag & COLLECTION_HIDE_VIEWPORT) { return true; } diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 158aaa961ce..f60234a684d 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -1612,7 +1612,7 @@ static void library_make_local_copying_check(ID *id, if (!BLI_gset_haskey(done_ids, from_id)) { if (BLI_gset_haskey(loop_tags, from_id)) { /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it. - * Note that this is the situation that can lead to archipelagoes of linked data-blocks + * Note that this is the situation that can lead to archipelagos of linked data-blocks * (since all of them have non-local users, they would all be duplicated, * leading to a loop of unused linked data-blocks that cannot be freed since they all use * each other...). */ diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index f4f5ca7a1d7..c7643c56212 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -16,6 +16,7 @@ #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BLI_listbase.h" #include "BKE_anim_data.h" @@ -23,10 +24,10 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_remap.h" -#include "BKE_library.h" #include "BKE_main.h" #include "BKE_main_namemap.h" @@ -202,7 +203,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) { const int tag = LIB_TAG_DOIT; ListBase *lbarray[INDEX_ID_MAX]; - Link dummy_link = {0}; int base_count, i; /* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database, @@ -217,6 +217,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) BKE_main_lock(bmain); if (do_tagged_deletion) { + struct IDRemapper *id_remapper = BKE_id_remapper_create(); + BKE_layer_collection_resync_forbid(); + /* Main idea of batch deletion is to remove all IDs to be deleted from Main database. * This means that we won't have to loop over all deleted IDs to remove usages * of other deleted IDs. @@ -227,7 +230,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) bool keep_looping = true; while (keep_looping) { ID *id, *id_next; - ID *last_remapped_id = tagged_deleted_ids.last; keep_looping = false; /* First tag and remove from Main all datablocks directly from target lib. @@ -243,6 +245,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) BLI_remlink(lb, id); BKE_main_namemap_remove_name(bmain, id, id->name + 2); BLI_addtail(&tagged_deleted_ids, id); + BKE_id_remapper_add(id_remapper, id, NULL); /* Do not tag as no_main now, we want to unlink it first (lower-level ID management * code has some specific handling of 'no main' IDs that would be a problem in that * case). */ @@ -251,33 +254,38 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) } } } - if (last_remapped_id == NULL) { - dummy_link.next = tagged_deleted_ids.first; - last_remapped_id = (ID *)(&dummy_link); - } - for (id = last_remapped_id->next; id; id = id->next) { - /* Will tag 'never NULL' users of this ID too. - * - * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect - * links, this can lead to nasty crashing here in second, actual deleting loop. - * Also, this will also flag users of deleted data that cannot be unlinked - * (object using deleted obdata, etc.), so that they also get deleted. */ - BKE_libblock_remap_locked(bmain, - id, - NULL, - (ID_REMAP_FLAG_NEVER_NULL_USAGE | - ID_REMAP_FORCE_NEVER_NULL_USAGE | - ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS)); - /* Since we removed ID from Main, - * we also need to unlink its own other IDs usages ourself. */ - BKE_libblock_relink_ex( - bmain, - id, - NULL, - NULL, - (ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | ID_REMAP_SKIP_USER_CLEAR)); - } + + /* Will tag 'never NULL' users of this ID too. + * + * NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect + * links, this can lead to nasty crashing here in second, actual deleting loop. + * Also, this will also flag users of deleted data that cannot be unlinked + * (object using deleted obdata, etc.), so that they also get deleted. */ + BKE_libblock_remap_multiple_locked(bmain, + id_remapper, + ID_REMAP_FLAG_NEVER_NULL_USAGE | + ID_REMAP_FORCE_NEVER_NULL_USAGE | + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS); + BKE_id_remapper_clear(id_remapper); + } + + /* Since we removed IDs from Main, their own other IDs usages need to be removed 'manually'. */ + LinkNode *cleanup_ids = NULL; + for (ID *id = tagged_deleted_ids.first; id; id = id->next) { + BLI_linklist_prepend(&cleanup_ids, id); } + BKE_libblock_relink_multiple(bmain, + cleanup_ids, + ID_REMAP_TYPE_CLEANUP, + id_remapper, + ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS | + ID_REMAP_SKIP_USER_CLEAR); + + BKE_id_remapper_free(id_remapper); + BLI_linklist_free(cleanup_ids, NULL); + + BKE_layer_collection_resync_allow(); + BKE_main_collection_sync_remap(bmain); /* Now we can safely mark that ID as not being in Main database anymore. */ /* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of @@ -285,10 +293,14 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) * is never affected). */ for (ID *id = tagged_deleted_ids.first; id; id = id->next) { id->tag |= LIB_TAG_NO_MAIN; + /* User-count needs to be reset artificially, since some usages may not be cleared in batch + * deletion (typically, if one deleted ID uses another deleted ID, this may not be cleared by + * remapping code, depending on order in which these are handled). */ + id->us = ID_FAKE_USERS(id); } } else { - /* First tag all datablocks directly from target lib. + /* First tag all data-blocks directly from target lib. * Note that we go forward here, since we want to check dependencies before users * (e.g. meshes before objects). * Avoids to have to loop twice. */ diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 55834d5cf4e..adc0eb5f78c 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -521,7 +521,7 @@ static void layer_bucket_init(MaskRasterLayer *layer, const float pixel_size) } if (1) { - /* now convert linknodes into arrays for faster per pixel access */ + /* Now convert link-nodes into arrays for faster per pixel access. */ uint **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__); uint bucket_index; @@ -1186,7 +1186,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, // printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); } - /* add trianges */ + /* Add triangles. */ BLI_scanfill_end_arena(&sf_ctx, sf_arena); } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 6c6d2298dbd..59530a6d6a6 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -1450,7 +1450,7 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata) NodeTexImage *storage = (NodeTexImage *)node->storage; slot->interp = storage->interpolation; slot->image_user = &storage->iuser; - /* for new renderer, we need to traverse the treeback in search of a UV node */ + /* For new renderer, we need to traverse the tree back in search of a UV node. */ bNode *uvnode = nodetree_uv_node_recursive(node); if (uvnode) { @@ -1512,58 +1512,65 @@ static ePaintSlotFilter material_paint_slot_filter(const struct Object *ob) void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma, const struct Object *ob) { - int count = 0; - if (!ma) { return; } const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob); - /* COW needed when adding texture slot on an object with no materials. */ - DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE); + const TexPaintSlot *prev_texpaintslot = ma->texpaintslot; + const int prev_paint_active_slot = ma->paint_active_slot; + const int prev_paint_clone_slot = ma->paint_clone_slot; + const int prev_tot_slots = ma->tot_slots; - if (ma->texpaintslot) { - MEM_freeN(ma->texpaintslot); - ma->tot_slots = 0; - ma->texpaintslot = NULL; - } + ma->texpaintslot = NULL; + ma->tot_slots = 0; if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) { ma->paint_active_slot = 0; ma->paint_clone_slot = 0; - return; } - - if (!(ma->nodetree)) { + else if (!(ma->nodetree)) { ma->paint_active_slot = 0; ma->paint_clone_slot = 0; - return; } + else { + int count = count_texture_nodes_recursive(ma->nodetree, slot_filter); - count = count_texture_nodes_recursive(ma->nodetree, slot_filter); - - if (count == 0) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } + if (count == 0) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + } + else { + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); - ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree); - bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree); + fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter); - fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter); + ma->tot_slots = count; - ma->tot_slots = count; + if (ma->paint_active_slot >= count) { + ma->paint_active_slot = count - 1; + } - if (ma->paint_active_slot >= count) { - ma->paint_active_slot = count - 1; + if (ma->paint_clone_slot >= count) { + ma->paint_clone_slot = count - 1; + } + } } - if (ma->paint_clone_slot >= count) { - ma->paint_clone_slot = count - 1; + /* COW needed when adding texture slot on an object with no materials. + * But do it only when slots actually change to avoid continuous depsgraph updates. */ + if (ma->tot_slots != prev_tot_slots || ma->paint_active_slot != prev_paint_active_slot || + ma->paint_clone_slot != prev_paint_clone_slot || + (ma->texpaintslot && prev_texpaintslot && + memcmp(ma->texpaintslot, prev_texpaintslot, sizeof(*ma->texpaintslot) * ma->tot_slots) != + 0)) { + DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE); } + + MEM_SAFE_FREE(prev_texpaintslot); } void BKE_texpaint_slots_refresh_object(Scene *scene, struct Object *ob) diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc index bb3713e770a..f8a64a7cd8b 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.cc +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -1188,8 +1188,9 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph); const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS); - copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */ - invert_m4_m4(obinv, ob->obmat); + copy_m4_m4(obmat, + ob->object_to_world); /* to cope with duplicators from BKE_scene_base_iter_next */ + invert_m4_m4(obinv, ob->object_to_world); BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); @@ -1237,13 +1238,13 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje /* when metaball object has zero scale, then MetaElem to this MetaBall * will not be put to mainb array */ - if (has_zero_axis_m4(bob->obmat)) { + if (has_zero_axis_m4(bob->object_to_world)) { zero_size = 1; } else if (bob->parent) { struct Object *pob = bob->parent; while (pob) { - if (has_zero_axis_m4(pob->obmat)) { + if (has_zero_axis_m4(pob->object_to_world)) { zero_size = 1; break; } @@ -1307,7 +1308,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje * rotation -> * ml local space */ - mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot); + mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->object_to_world, pos, rot); /* ml local space -> basis object space */ invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 027423f5774..784d35a8d65 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1313,6 +1313,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly); CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop); + const bool verts_num_changed = mesh_dst->totvert != mesh_src->totvert; mesh_dst->totvert = mesh_src->totvert; mesh_dst->totedge = mesh_src->totedge; mesh_dst->totpoly = mesh_src->totpoly; @@ -1339,11 +1340,10 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob) const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1; move_shapekey_layers_to_keyblocks(*mesh_dst, mesh_src->vdata, *key_dst, uid_active); } - else if (mesh_src->totvert != mesh_dst->totvert) { - CLOG_ERROR(&LOG, "Mesh in Main '%s' lost shape keys", mesh_src->id.name); - if (mesh_src->key) { - id_us_min(&mesh_src->key->id); - } + else if (verts_num_changed) { + CLOG_WARN(&LOG, "Shape key data lost when replacing mesh '%s' in Main", mesh_src->id.name); + id_us_min(&mesh_dst->key->id); + mesh_dst->key = nullptr; } } diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c index 261bc3d150b..ce3fc5d99c8 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.c +++ b/source/blender/blenkernel/intern/mesh_mirror.c @@ -152,8 +152,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, /* tmp is a transform from coords relative to the object's own origin, * to coords relative to the mirror object origin */ - invert_m4_m4(tmp, mirror_ob->obmat); - mul_m4_m4m4(tmp, tmp, ob->obmat); + invert_m4_m4(tmp, mirror_ob->object_to_world); + mul_m4_m4m4(tmp, tmp, ob->object_to_world); /* itmp is the reverse transform back to origin-relative coordinates */ invert_m4_m4(itmp, tmp); @@ -169,9 +169,9 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, /* Account for non-uniform scale in `ob`, see: T87592. */ float ob_scale[3] = { - len_squared_v3(ob->obmat[0]), - len_squared_v3(ob->obmat[1]), - len_squared_v3(ob->obmat[2]), + len_squared_v3(ob->object_to_world[0]), + len_squared_v3(ob->object_to_world[1]), + len_squared_v3(ob->object_to_world[2]), }; /* Scale to avoid precision loss with extreme values. */ const float ob_scale_max = max_fff(UNPACK3(ob_scale)); diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index ba63cdff917..c0aff204069 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -464,6 +464,7 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_libo */ nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); BKE_nlatrack_add_strip(nlt, strip, is_liboverride); + BLI_strncpy(nlt->name, act->id.name + 2, sizeof(nlt->name)); } /* automatically name it too */ @@ -1918,7 +1919,7 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride) * NOTE: this must be done *after* adding the strip to the track, or else * the strip locking will prevent the strip from getting added */ - nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED); + nlt->flag |= (NLATRACK_MUTED | NLATRACK_PROTECTED); strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE); /* also mark the strip for auto syncing the length, so that the strips accurately @@ -2054,7 +2055,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) } /* If block is already in tweak-mode, just leave, but we should report - * that this block is in tweak-mode (as our returncode). */ + * that this block is in tweak-mode (as our return-code). */ if (adt->flag & ADT_NLA_EDIT_ON) { return true; } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 8028f990c42..8f8cd02e119 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -516,10 +516,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) write_node_socket(writer, sock); } - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { - BLO_write_struct(writer, bNodeLink, link); - } - if (node->storage) { if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) { @@ -703,13 +699,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) BLO_read_data_address(reader, &node->prop); IDP_BlendDataRead(reader, &node->prop); - BLO_read_list(reader, &node->internal_links); - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { - BLO_read_data_address(reader, &link->fromnode); - BLO_read_data_address(reader, &link->fromsock); - BLO_read_data_address(reader, &link->tonode); - BLO_read_data_address(reader, &link->tosock); - } + BLI_listbase_clear(&node->internal_links); if (node->type == CMP_NODE_MOVIEDISTORTION) { /* Do nothing, this is runtime cache and hence handled by generic code using @@ -2032,21 +2022,29 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) { *r_node = nullptr; + if (!ntree->runtime->topology_cache_is_dirty) { + bNode *node = &sock->owner_node(); + *r_node = node; + if (r_sockindex) { + ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; + *r_sockindex = BLI_findindex(sockets, sock); + } + return true; + } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; - int index = 0; - LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) { + int i; + LISTBASE_FOREACH_INDEX (bNodeSocket *, tsock, sockets, i) { if (sock == tsock) { if (r_node != nullptr) { *r_node = node; } if (r_sockindex != nullptr) { - *r_sockindex = index; + *r_sockindex = i; } return true; } - index++; } } return false; diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 2d949fb5c65..53e6d47860f 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1330,14 +1330,14 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) /* Calculate the world-space matrix for the pose-channel target first, * then carry on as usual. */ - mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, hmd->object->object_to_world, pchan->pose_mat); invert_m4_m4(imat, mat); - mul_m4_m4m4(hmd->parentinv, imat, ob->obmat); + mul_m4_m4m4(hmd->parentinv, imat, ob->object_to_world); } else { - invert_m4_m4(hmd->object->imat, hmd->object->obmat); - mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat); + invert_m4_m4(hmd->object->imat, hmd->object->object_to_world); + mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->object_to_world); } } } @@ -1355,14 +1355,14 @@ void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData /* Calculate the world-space matrix for the pose-channel target first, * then carry on as usual. */ - mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, hmd->object->object_to_world, pchan->pose_mat); invert_m4_m4(imat, mat); - mul_m4_m4m4(hmd->parentinv, imat, ob->obmat); + mul_m4_m4m4(hmd->parentinv, imat, ob->object_to_world); } else { - invert_m4_m4(hmd->object->imat, hmd->object->obmat); - mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat); + invert_m4_m4(hmd->object->imat, hmd->object->object_to_world); + mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->object_to_world); } } @@ -1902,6 +1902,7 @@ bool BKE_object_is_in_editmode(const Object *ob) /* Grease Pencil object has no edit mode data. */ return GPENCIL_EDIT_MODE((bGPdata *)ob->data); case OB_CURVES: + /* Curves object has no edit mode data. */ return ob->mode == OB_MODE_EDIT; default: return false; @@ -3101,10 +3102,10 @@ void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4]) BKE_object_get_parent_matrix(ob, ob->parent, par_imat); invert_m4(par_imat); - mul_m4_m4m4(r_mat, par_imat, ob->obmat); + mul_m4_m4m4(r_mat, par_imat, ob->object_to_world); } else { - copy_m4_m4(r_mat, ob->obmat); + copy_m4_m4(r_mat, ob->object_to_world); } } @@ -3358,32 +3359,32 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float r_parentmat[4][ } if (ok) { - mul_m4_m4m4(r_parentmat, par->obmat, tmat); + mul_m4_m4m4(r_parentmat, par->object_to_world, tmat); } else { - copy_m4_m4(r_parentmat, par->obmat); + copy_m4_m4(r_parentmat, par->object_to_world); } break; } case PARBONE: ob_parbone(ob, par, tmat); - mul_m4_m4m4(r_parentmat, par->obmat, tmat); + mul_m4_m4m4(r_parentmat, par->object_to_world, tmat); break; case PARVERT1: unit_m4(r_parentmat); give_parvert(par, ob->par1, vec); - mul_v3_m4v3(r_parentmat[3], par->obmat, vec); + mul_v3_m4v3(r_parentmat[3], par->object_to_world, vec); break; case PARVERT3: ob_parvert3(ob, par, tmat); - mul_m4_m4m4(r_parentmat, par->obmat, tmat); + mul_m4_m4m4(r_parentmat, par->object_to_world, tmat); break; case PARSKEL: - copy_m4_m4(r_parentmat, par->obmat); + copy_m4_m4(r_parentmat, par->object_to_world); break; } } @@ -3421,7 +3422,7 @@ static void solve_parenting( /* origin, for help line */ if (set_origin) { if ((ob->partype & PARTYPE) == PARSKEL) { - copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]); + copy_v3_v3(ob->runtime.parent_display_origin, par->object_to_world[3]); } else { copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]); @@ -3440,10 +3441,10 @@ static void object_where_is_calc_ex(Depsgraph *depsgraph, Object *par = ob->parent; /* calculate parent matrix */ - solve_parenting(ob, par, true, ob->obmat, r_originmat); + solve_parenting(ob, par, true, ob->object_to_world, r_originmat); } else { - BKE_object_to_mat4(ob, ob->obmat); + BKE_object_to_mat4(ob, ob->object_to_world); } /* try to fall back to the scene rigid body world if none given */ @@ -3460,7 +3461,7 @@ static void object_where_is_calc_ex(Depsgraph *depsgraph, } /* set negative scale flag in object */ - if (is_negative_m4(ob->obmat)) { + if (is_negative_m4(ob->object_to_world)) { ob->transflag |= OB_NEG_SCALE; } else { @@ -3506,7 +3507,7 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o { BKE_object_workob_clear(workob); - unit_m4(workob->obmat); + unit_m4(workob->object_to_world); unit_m4(workob->parentinv); unit_m4(workob->constinv); @@ -3598,7 +3599,7 @@ void BKE_object_apply_parent_inverse(struct Object *ob) * `inv(parent) @ world = parentinv` * `parentinv = inv(parent) @ world` * - * NOTE: If `ob->obmat` has shear, then this `parentinv` is insufficient because + * NOTE: If `ob->object_to_world` has shear, then this `parentinv` is insufficient because * `parent @ parentinv => shearless result` * * Thus, local will have shear which cannot be decomposed into TRS: @@ -3627,7 +3628,7 @@ void BKE_object_apply_parent_inverse(struct Object *ob) copy_m4_m4(ob_local, ob->parentinv); invert_m4(ob_local); mul_m4_m4_post(ob_local, par_imat); - mul_m4_m4_post(ob_local, ob->obmat); + mul_m4_m4_post(ob_local, ob->object_to_world); /* Send use_compat=False so the rotation is predictable. */ BKE_object_apply_mat4(ob, ob_local, false, false); @@ -3792,7 +3793,7 @@ void BKE_object_dimensions_get(Object *ob, float r_vec[3]) const BoundBox *bb = BKE_object_boundbox_get(ob); if (bb) { float3 scale; - mat4_to_size(scale, ob->obmat); + mat4_to_size(scale, ob->object_to_world); r_vec[0] = fabsf(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]); r_vec[1] = fabsf(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]); @@ -3849,19 +3850,19 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us case OB_FONT: case OB_SURF: { const BoundBox bb = *BKE_curve_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_MESH: { const BoundBox bb = *BKE_mesh_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_GPENCIL: { const BoundBox bb = *BKE_gpencil_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } @@ -3874,7 +3875,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us for (v = 0; v < lt->pntsv; v++) { for (u = 0; u < lt->pntsu; u++, bp++) { float3 vec; - mul_v3_m4v3(vec, ob->obmat, bp->vec); + mul_v3_m4v3(vec, ob->object_to_world, bp->vec); minmax_v3v3_v3(r_min, r_max, vec); } } @@ -3889,7 +3890,8 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us case OB_MBALL: { float ob_min[3], ob_max[3]; - changed = BKE_mball_minmax_ex((const MetaBall *)ob->data, ob_min, ob_max, ob->obmat, 0); + changed = BKE_mball_minmax_ex( + (const MetaBall *)ob->data, ob_min, ob_max, ob->object_to_world, 0); if (changed) { minmax_v3v3_v3(r_min, r_max, ob_min); minmax_v3v3_v3(r_min, r_max, ob_max); @@ -3898,20 +3900,20 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us } case OB_CURVES: { const BoundBox bb = *BKE_curves_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_POINTCLOUD: { const BoundBox bb = *BKE_pointcloud_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } case OB_VOLUME: { const BoundBox bb = *BKE_volume_boundbox_get(ob); - BKE_boundbox_minmax(&bb, ob->obmat, r_min, r_max); + BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; break; } @@ -3925,14 +3927,14 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us size *= ob->empty_drawsize; } - minmax_v3v3_v3(r_min, r_max, ob->obmat[3]); + minmax_v3v3_v3(r_min, r_max, ob->object_to_world[3]); float3 vec; - copy_v3_v3(vec, ob->obmat[3]); + copy_v3_v3(vec, ob->object_to_world[3]); add_v3_v3(vec, size); minmax_v3v3_v3(r_min, r_max, vec); - copy_v3_v3(vec, ob->obmat[3]); + copy_v3_v3(vec, ob->object_to_world[3]); sub_v3_v3(vec, size); minmax_v3v3_v3(r_min, r_max, vec); } @@ -3979,12 +3981,12 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re * however the issue with empty objects being visible when viewed from the side * is only noticeable in orthographic views. */ float3 view_dir; - sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->obmat[3]); - dot = dot_v3v3(ob->obmat[2], view_dir); + sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->object_to_world[3]); + dot = dot_v3v3(ob->object_to_world[2], view_dir); eps = 0.0f; } else { - dot = dot_v3v3(ob->obmat[2], rv3d->viewinv[2]); + dot = dot_v3v3(ob->object_to_world[2], rv3d->viewinv[2]); eps = 1e-5f; } if (visibility_flag & OB_EMPTY_IMAGE_HIDE_BACK) { @@ -4001,7 +4003,7 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re if (visibility_flag & OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED) { float3 proj, ob_z_axis; - normalize_v3_v3(ob_z_axis, ob->obmat[2]); + normalize_v3_v3(ob_z_axis, ob->object_to_world[2]); project_plane_v3_v3v3(proj, ob_z_axis, rv3d->viewinv[2]); const float proj_length_sq = len_squared_v3(proj); if (proj_length_sq > 1e-5f) { @@ -4193,7 +4195,7 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph, DEG_ITER_OBJECT_FLAG_DUPLI; DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) { if ((ob->base_flag & BASE_SELECTED) != 0) { - BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data); + BKE_object_foreach_display_point(ob, ob->object_to_world, func_cb, user_data); } } DEG_OBJECT_ITER_END; @@ -4236,7 +4238,7 @@ void *BKE_object_tfm_backup(Object *ob) copy_v3_v3(obtfm->drotAxis, ob->drotAxis); obtfm->rotAngle = ob->rotAngle; obtfm->drotAngle = ob->drotAngle; - copy_m4_m4(obtfm->obmat, ob->obmat); + copy_m4_m4(obtfm->obmat, ob->object_to_world); copy_m4_m4(obtfm->parentinv, ob->parentinv); copy_m4_m4(obtfm->constinv, ob->constinv); copy_m4_m4(obtfm->imat, ob->imat); @@ -4259,7 +4261,7 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt) copy_v3_v3(ob->drotAxis, obtfm->drotAxis); ob->rotAngle = obtfm->rotAngle; ob->drotAngle = obtfm->drotAngle; - copy_m4_m4(ob->obmat, obtfm->obmat); + copy_m4_m4(ob->object_to_world, obtfm->obmat); copy_m4_m4(ob->parentinv, obtfm->parentinv); copy_m4_m4(ob->constinv, obtfm->constinv); copy_m4_m4(ob->imat, obtfm->imat); @@ -5290,7 +5292,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) for (i = 0; i < verts.size(); i++) { if (index[i] != ORIGINDEX_NONE) { float co[3]; - mul_v3_m4v3(co, ob->obmat, verts[i].co); + mul_v3_m4v3(co, ob->object_to_world, verts[i].co); BLI_kdtree_3d_insert(tree, index[i], co); tot++; } @@ -5304,7 +5306,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) for (i = 0; i < tot; i++) { float co[3]; - mul_v3_m4v3(co, ob->obmat, verts[i].co); + mul_v3_m4v3(co, ob->object_to_world, verts[i].co); BLI_kdtree_3d_insert(tree, i, co); } } @@ -5333,7 +5335,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) a = nu->pntsu; while (a--) { float co[3]; - mul_v3_m4v3(co, ob->obmat, bezt->vec[1]); + mul_v3_m4v3(co, ob->object_to_world, bezt->vec[1]); BLI_kdtree_3d_insert(tree, i++, co); bezt++; } @@ -5345,7 +5347,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) a = nu->pntsu * nu->pntsv; while (a--) { float co[3]; - mul_v3_m4v3(co, ob->obmat, bp->vec); + mul_v3_m4v3(co, ob->object_to_world, bp->vec); BLI_kdtree_3d_insert(tree, i++, co); bp++; } @@ -5368,7 +5370,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) for (bp = lt->def; i < tot; bp++) { float co[3]; - mul_v3_m4v3(co, ob->obmat, bp->vec); + mul_v3_m4v3(co, ob->object_to_world, bp->vec); BLI_kdtree_3d_insert(tree, i++, co); } diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index d43eff6f9b4..d029d307d6e 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -197,7 +197,8 @@ static bool copy_dupli_context(DupliContext *r_ctx, /** * Generate a dupli instance. * - * \param mat: is transform of the object relative to current context (including #Object.obmat). + * \param mat: is transform of the object relative to current context (including + * #Object.object_to_world). */ static DupliObject *make_dupli(const DupliContext *ctx, Object *ob, @@ -296,7 +297,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, /** * Recursive dupli-objects. * - * \param space_mat: is the local dupli-space (excluding dupli #Object.obmat). + * \param space_mat: is the local dupli-space (excluding dupli #Object.object_to_world). */ static void make_recursive_duplis(const DupliContext *ctx, Object *ob, @@ -468,8 +469,8 @@ static void make_duplis_collection(const DupliContext *ctx) /* Combine collection offset and `obmat`. */ unit_m4(collection_mat); sub_v3_v3(collection_mat[3], collection->instance_offset); - mul_m4_m4m4(collection_mat, ob->obmat, collection_mat); - /* Don't access 'ob->obmat' from now on. */ + mul_m4_m4m4(collection_mat, ob->object_to_world, collection_mat); + /* Don't access 'ob->object_to_world' from now on. */ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, cob, mode) { @@ -477,7 +478,7 @@ static void make_duplis_collection(const DupliContext *ctx) float mat[4][4]; /* Collection dupli-offset, should apply after everything else. */ - mul_m4_m4m4(mat, collection_mat, cob->obmat); + mul_m4_m4m4(mat, collection_mat, cob->object_to_world); make_dupli(ctx, cob, mat, _base_id); @@ -584,7 +585,7 @@ static DupliObject *vertex_dupli(const DupliContext *ctx, /* Make offset relative to inst_ob using relative child transform. */ mul_mat3_m4_v3(child_imat, obmat[3]); /* Apply `obmat` _after_ the local vertex transform. */ - mul_m4_m4m4(obmat, inst_ob->obmat, obmat); + mul_m4_m4m4(obmat, inst_ob->object_to_world, obmat); /* Space matrix is constructed by removing `obmat` transform, * this yields the world-space transform for recursive duplis. */ @@ -608,10 +609,10 @@ static void make_child_duplis_verts_from_mesh(const DupliContext *ctx, const MVert *mvert = vdd->mvert; const int totvert = vdd->totvert; - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ float child_imat[4][4]; - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); for (int i = 0; i < totvert; i++) { DupliObject *dob = vertex_dupli( @@ -630,10 +631,10 @@ static void make_child_duplis_verts_from_editmesh(const DupliContext *ctx, BMEditMesh *em = vdd->em; const bool use_rotation = vdd->params.use_rotation; - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ float child_imat[4][4]; - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); BMVert *v; BMIter iter; @@ -758,7 +759,7 @@ static void make_duplis_font(const DupliContext *ctx) return; } - copy_m4_m4(pmat, par->obmat); + copy_m4_m4(pmat, par->object_to_world); /* In `par` the family name is stored, use this to find the other objects. */ @@ -803,7 +804,7 @@ static void make_duplis_font(const DupliContext *ctx) mul_m4_v3(pmat, vec); - copy_m4_m4(obmat, par->obmat); + copy_m4_m4(obmat, par->object_to_world); if (UNLIKELY(ct->rot != 0.0f)) { float rmat[4][4]; @@ -951,7 +952,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, } float instance_matrix[4][4]; - mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); + mul_m4_m4m4(instance_matrix, collection_matrix, object->object_to_world); make_dupli(&sub_ctx, object, instance_matrix, object_id++); make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); @@ -986,7 +987,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, static void make_duplis_geometry_set(const DupliContext *ctx) { const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval; - make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false, false); + make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->object_to_world, false, false); } static const DupliGenerator gen_dupli_geometry_set = { @@ -1092,7 +1093,7 @@ static DupliObject *face_dupli(const DupliContext *ctx, } /* Apply `obmat` _after_ the local face transform. */ - mul_m4_m4m4(obmat, inst_ob->obmat, obmat); + mul_m4_m4m4(obmat, inst_ob->object_to_world, obmat); /* Space matrix is constructed by removing `obmat` transform, * this yields the world-space transform for recursive duplis. */ @@ -1176,9 +1177,9 @@ static void make_child_duplis_faces_from_mesh(const DupliContext *ctx, float child_imat[4][4]; - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); const float scale_fac = ctx->object->instance_faces_scale; for (a = 0, mp = mpoly; a < totface; a++, mp++) { @@ -1216,9 +1217,9 @@ static void make_child_duplis_faces_from_editmesh(const DupliContext *ctx, BLI_assert((vert_coords == nullptr) || (em->bm->elem_index_dirty & BM_VERT) == 0); - invert_m4_m4(inst_ob->imat, inst_ob->obmat); + invert_m4_m4(inst_ob->imat, inst_ob->object_to_world); /* Relative transform from parent to child space. */ - mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); + mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->object_to_world); const float scale_fac = ctx->object->instance_faces_scale; BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, a) { @@ -1348,7 +1349,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* Make sure emitter `imat` is in global coordinates instead of render view coordinates. */ - invert_m4_m4(par->imat, par->obmat); + invert_m4_m4(par->imat, par->object_to_world); /* First check for loops (particle system object used as dupli-object). */ if (part->ren_as == PART_DRAW_OB) { @@ -1535,7 +1536,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem b = 0; FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN ( part->instance_collection, object, mode) { - copy_m4_m4(tmat, oblist[b]->obmat); + copy_m4_m4(tmat, oblist[b]->object_to_world); /* Apply collection instance offset. */ sub_v3_v3(tmat[3], part->instance_collection->instance_offset); @@ -1558,7 +1559,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } else { float obmat[4][4]; - copy_m4_m4(obmat, ob->obmat); + copy_m4_m4(obmat, ob->object_to_world); float vec[3]; copy_v3_v3(vec, obmat[3]); @@ -1752,7 +1753,7 @@ ListBase *object_duplilist_preview(Depsgraph *depsgraph, *viewer_path)) { ctx.preview_base_geometry = &viewer_log->geometry; make_duplis_geometry_set_impl( - &ctx, viewer_log->geometry, ob_eval->obmat, true, ob_eval->type == OB_CURVES); + &ctx, viewer_log->geometry, ob_eval->object_to_world, true, ob_eval->type == OB_CURVES); } } return duplilist; diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc index ceef6404bf0..7ea13bfcc84 100644 --- a/source/blender/blenkernel/intern/object_update.cc +++ b/source/blender/blenkernel/intern/object_update.cc @@ -61,7 +61,7 @@ void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob) DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* calculate local matrix */ - BKE_object_to_mat4(ob, ob->obmat); + BKE_object_to_mat4(ob, ob->object_to_world); } void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob) @@ -78,18 +78,18 @@ void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob) /* get local matrix (but don't calculate it, as that was done already!) */ /* XXX: redundant? */ - copy_m4_m4(locmat, ob->obmat); + copy_m4_m4(locmat, ob->object_to_world); /* get parent effect matrix */ BKE_object_get_parent_matrix(ob, par, totmat); /* total */ mul_m4_m4m4(tmat, totmat, ob->parentinv); - mul_m4_m4m4(ob->obmat, tmat, locmat); + mul_m4_m4m4(ob->object_to_world, tmat, locmat); /* origin, for help line */ if ((ob->partype & PARTYPE) == PARSKEL) { - copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]); + copy_v3_v3(ob->runtime.parent_display_origin, par->object_to_world[3]); } else { copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]); @@ -121,9 +121,9 @@ void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob) DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* Make sure inverse matrix is always up to date. This way users of it * do not need to worry about recalculating it. */ - invert_m4_m4_safe(ob->imat, ob->obmat); + invert_m4_m4_safe(ob->imat, ob->object_to_world); /* Set negative scale flag in object. */ - if (is_negative_m4(ob->obmat)) { + if (is_negative_m4(ob->object_to_world)) { ob->transflag |= OB_NEG_SCALE; } else { @@ -257,7 +257,7 @@ void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object) /* Base flags. */ object_orig->base_flag = object->base_flag; /* Transformation flags. */ - copy_m4_m4(object_orig->obmat, object->obmat); + copy_m4_m4(object_orig->object_to_world, object->object_to_world); copy_m4_m4(object_orig->imat, object->imat); copy_m4_m4(object_orig->constinv, object->constinv); object_orig->transflag = object->transflag; @@ -292,6 +292,8 @@ void BKE_object_batch_cache_dirty_tag(Object *ob) BKE_lattice_batch_cache_dirty_tag((struct Lattice *)ob->data, BKE_LATTICE_BATCH_DIRTY_ALL); break; case OB_CURVES_LEGACY: + case OB_SURF: + case OB_FONT: BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL); break; case OB_MBALL: { diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 13243925b28..a39e53662aa 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1043,6 +1043,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode) return OB_MODE_TEXTURE_PAINT; case PAINT_MODE_SCULPT_UV: return OB_MODE_EDIT; + case PAINT_MODE_SCULPT_CURVES: + return OB_MODE_SCULPT_CURVES; case PAINT_MODE_INVALID: default: return OB_MODE_OBJECT; @@ -1199,7 +1201,7 @@ void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3]) mul_v3_v3fl(stroke, ups->average_stroke_accum, fac); } else { - copy_v3_v3(stroke, ob->obmat[3]); + copy_v3_v3(stroke, ob->object_to_world[3]); } } @@ -2314,7 +2316,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg) &key); } -bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D * /*v3d*/) +bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d) { SculptSession *ss = ob->sculpt; if (ss == nullptr || ss->pbvh == nullptr || ss->mode_type != OB_MODE_SCULPT) { @@ -2322,9 +2324,10 @@ 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. */ - - return !(ss->shapekey_active || ss->deform_modifiers_active); + /* Regular mesh only draws from PBVH without modifiers and shape keys, or for + * external engines that do not have access to the PBVH like Eevee does. */ + const bool external_engine = rv3d && rv3d->render_engine != nullptr; + return !(ss->shapekey_active || ss->deform_modifiers_active || external_engine); } /* Multires and dyntopo always draw directly from the PBVH. */ diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index d6dd3cf0dbb..f111e2dde17 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2370,8 +2370,8 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors) 0, 0); - mul_m4_v3(sim->ob->obmat, state.co); - mul_mat3_m4_v3(sim->ob->obmat, state.vel); + mul_m4_v3(sim->ob->object_to_world, state.co); + mul_mat3_m4_v3(sim->ob->object_to_world, state.vel); pd_point_from_particle(sim, pa, &state, &point); @@ -2454,8 +2454,8 @@ bool do_guides(Depsgraph *depsgraph, } } - mul_m4_v3(eff->ob->obmat, guidevec); - mul_mat3_m4_v3(eff->ob->obmat, guidedir); + mul_m4_v3(eff->ob->object_to_world, guidevec); + mul_mat3_m4_v3(eff->ob->object_to_world, guidedir); normalize_v3(guidedir); @@ -2956,7 +2956,7 @@ static void psys_thread_create_path(ParticleTask *task, psys_particle_on_emitter( ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco); - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); for (w = 0; w < 4; w++) { sub_v3_v3v3(off1[w], co, key[w]->co); @@ -3419,7 +3419,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re /* dynamic hair is in object space */ /* keyed and baked are already in global space */ if (hair_mesh) { - mul_m4_v3(sim->ob->obmat, ca->co); + mul_m4_v3(sim->ob->object_to_world, ca->co); } else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR)) { mul_m4_v3(hairmat, ca->co); @@ -3929,7 +3929,7 @@ void psys_mat_hair_to_global( psys_mat_hair_to_object(ob, mesh, from, pa, facemat); - mul_m4_m4m4(hairmat, ob->obmat, facemat); + mul_m4_m4m4(hairmat, ob->object_to_world, facemat); } /************************************************/ @@ -4661,8 +4661,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, do_particle_interpolation(psys, p, pa, t, &pind, state); if (pind.mesh) { - mul_m4_v3(sim->ob->obmat, state->co); - mul_mat3_m4_v3(sim->ob->obmat, state->vel); + mul_m4_v3(sim->ob->object_to_world, state->co); + mul_mat3_m4_v3(sim->ob->object_to_world, state->vel); } else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) { if ((pa->flag & PARS_REKEY) == 0) { @@ -4685,7 +4685,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, } } else if (totchild) { - // invert_m4_m4(imat, ob->obmat); + // invert_m4_m4(imat, ob->object_to_world); /* interpolate childcache directly if it exists */ if (psys->childcache) { @@ -4733,7 +4733,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, * positioning it accurately to the surface of the emitter. */ // copy_v3_v3(cpa_1st, co); - // mul_m4_v3(ob->obmat, cpa_1st); + // mul_m4_v3(ob->object_to_world, cpa_1st); pa = psys->particles + cpa->parent; diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index a890812cfc4..6cc7dbc70d0 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -187,7 +187,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx, zero_v3(kink_base); kink_base[part->kink_axis] = 1.0f; - mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base); + mul_mat3_m4_v3(ctx->sim.ob->object_to_world, kink_base); /* Fill in invariant part of modifier context. */ ParticleChildModifierContext modifier_ctx = {NULL}; @@ -873,7 +873,7 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx, part->kink_flat, part->kink, part->kink_axis, - sim->ob->obmat, + sim->ob->object_to_world, smooth_start); } } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index c72bbe2fd08..7317318e828 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -750,10 +750,10 @@ void psys_get_birth_coords( /* particles live in global space so */ /* let's convert: */ /* -location */ - mul_m4_v3(ob->obmat, loc); + mul_m4_v3(ob->object_to_world, loc); /* -normal */ - mul_mat3_m4_v3(ob->obmat, nor); + mul_mat3_m4_v3(ob->object_to_world, nor); normalize_v3(nor); /* -tangent */ @@ -771,7 +771,7 @@ void psys_get_birth_coords( fac = -sinf((float)M_PI * (part->tanphase + phase)); madd_v3_v3fl(vtan, utan, fac); - mul_mat3_m4_v3(ob->obmat, vtan); + mul_mat3_m4_v3(ob->object_to_world, vtan); copy_v3_v3(utan, nor); mul_v3_fl(utan, dot_v3v3(vtan, nor)); @@ -786,7 +786,7 @@ void psys_get_birth_coords( r_vel[1] = 2.0f * (psys_frand(psys, p + 11) - 0.5f); r_vel[2] = 2.0f * (psys_frand(psys, p + 12) - 0.5f); - mul_mat3_m4_v3(ob->obmat, r_vel); + mul_mat3_m4_v3(ob->object_to_world, r_vel); normalize_v3(r_vel); } @@ -796,7 +796,7 @@ void psys_get_birth_coords( r_ave[1] = 2.0f * (psys_frand(psys, p + 14) - 0.5f); r_ave[2] = 2.0f * (psys_frand(psys, p + 15) - 0.5f); - mul_mat3_m4_v3(ob->obmat, r_ave); + mul_mat3_m4_v3(ob->object_to_world, r_ave); normalize_v3(r_ave); } @@ -808,7 +808,7 @@ void psys_get_birth_coords( r_rot[3] = 2.0f * (psys_frand(psys, p + 19) - 0.5f); normalize_qt(r_rot); - mat4_to_quat(rot, ob->obmat); + mat4_to_quat(rot, ob->object_to_world); mul_qt_qtqt(r_rot, r_rot, rot); } @@ -822,7 +822,7 @@ void psys_get_birth_coords( /* boids store direction in ave */ if (fabsf(nor[2]) == 1.0f) { - sub_v3_v3v3(state->ave, loc, ob->obmat[3]); + sub_v3_v3v3(state->ave, loc, ob->object_to_world[3]); normalize_v3(state->ave); } else { @@ -868,15 +868,15 @@ void psys_get_birth_coords( /* *emitter object orientation */ if (part->ob_vel[0] != 0.0f) { - normalize_v3_v3(vec, ob->obmat[0]); + normalize_v3_v3(vec, ob->object_to_world[0]); madd_v3_v3fl(vel, vec, part->ob_vel[0]); } if (part->ob_vel[1] != 0.0f) { - normalize_v3_v3(vec, ob->obmat[1]); + normalize_v3_v3(vec, ob->object_to_world[1]); madd_v3_v3fl(vel, vec, part->ob_vel[1]); } if (part->ob_vel[2] != 0.0f) { - normalize_v3_v3(vec, ob->obmat[2]); + normalize_v3_v3(vec, ob->object_to_world[2]); madd_v3_v3fl(vel, vec, part->ob_vel[2]); } @@ -924,7 +924,7 @@ void psys_get_birth_coords( case PART_ROT_OB_X: case PART_ROT_OB_Y: case PART_ROT_OB_Z: - copy_v3_v3(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]); + copy_v3_v3(rot_vec, ob->object_to_world[part->rotmode - PART_ROT_OB_X]); use_global_space = false; break; default: @@ -951,7 +951,7 @@ void psys_get_birth_coords( float q_obmat[4]; float q_imat[4]; - mat4_to_quat(q_obmat, ob->obmat); + mat4_to_quat(q_obmat, ob->object_to_world); invert_qt_qt_normalized(q_imat, q_obmat); if (part->rotmode != PART_ROT_NOR_TAN) { @@ -1639,7 +1639,7 @@ static void sph_springs_modify(ParticleSystem *psys, float dtime) } } - /* Loop through springs backwaqrds - for efficient delete function */ + /* Loop through springs backwards - for efficient delete function. */ for (i = psys->tot_fluidsprings - 1; i >= 0; i--) { if (psys->fluid_springs[i].delete_flag) { sph_spring_delete(psys, i); @@ -3364,7 +3364,7 @@ static void hair_create_input_mesh(ParticleSimulationData *sim, use_hair = psys_hair_use_simulation(pa, max_length); psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat); - mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); + mul_m4_m4m4(root_mat, sim->ob->object_to_world, hairmat); normalize_m4(root_mat); bending_stiffness = CLAMPIS( @@ -3555,7 +3555,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) HairKey *key, *root; PARTICLE_P; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); psys->lattice_deform_data = psys_create_lattice_deform_data(sim); @@ -4380,7 +4380,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, mul_v3_v3(pa->state.co, scaleAbs); /* Match domain scale. */ - mul_m4_v3(ob->obmat, pa->state.co); + mul_m4_v3(ob->object_to_world, pa->state.co); /* Add origin offset to particle position. */ zero_v3(tmp); @@ -4764,7 +4764,7 @@ void particle_system_update(struct Depsgraph *depsgraph, float cfra; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - /* drawdata is outdated after ANY change */ + /* Draw data is outdated after ANY change. */ if (psys->pdd) { psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; } @@ -4963,7 +4963,7 @@ void particle_system_update(struct Depsgraph *depsgraph, /* Save matrix for duplicators, * at render-time the actual dupli-object's matrix is used so don't update! */ - invert_m4_m4(psys->imat, ob->obmat); + invert_m4_m4(psys->imat, ob->object_to_world); BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index ac98bed2cf0..868cdde6d01 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1317,7 +1317,7 @@ static int ptcache_path(PTCacheID *pid, char *dirname) BLI_path_abs(dirname, blendfilename); } - return BLI_path_slash_ensure(dirname); /* new strlen() */ + return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */ } if ((blendfile_path[0] != '\0') || lib) { char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */ @@ -1334,14 +1334,14 @@ static int ptcache_path(PTCacheID *pid, char *dirname) BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file); BLI_path_abs(dirname, blendfilename); - return BLI_path_slash_ensure(dirname); /* new strlen() */ + return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */ } /* use the temp path. this is weak but better than not using point cache at all */ /* temporary directory is assumed to exist and ALWAYS has a trailing slash */ BLI_snprintf(dirname, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session()); - return BLI_path_slash_ensure(dirname); /* new strlen() */ + return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */ } static size_t ptcache_filepath_ext_append(PTCacheID *pid, @@ -2611,7 +2611,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra) } #endif - /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */ + /* Clear all files in the temp dir with the prefix of the ID and the `.bphys` suffix. */ switch (mode) { case PTCACHE_CLEAR_ALL: case PTCACHE_CLEAR_BEFORE: @@ -2775,7 +2775,7 @@ void BKE_ptcache_id_time( /* time handling for point cache: * - simulation time is scaled by result of bsystem_time * - for offsetting time only time offset is taken into account, since - * that's always the same and can't be animated. a timeoffset which + * that's always the same and can't be animated. a time-offset which * varies over time is not simple to support. * - field and motion blur offsets are currently ignored, proper solution * is probably to interpolate results from two frames for that .. diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index ffc6bc8d7a3..5e91b23bce3 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -264,13 +264,13 @@ static RigidBodyCon *rigidbody_copy_constraint(const Object *ob, const int UNUSE RigidBodyCon *rbcN = NULL; if (ob->rigidbody_constraint) { - /* just duplicate the whole struct first (to catch all the settings) */ + /* Just duplicate the whole struct first (to catch all the settings). */ rbcN = MEM_dupallocN(ob->rigidbody_constraint); - /* tag object as needing to be verified */ + /* Tag object as needing to be verified. */ rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE; - /* clear out all the fields which need to be revalidated later */ + /* Clear out all the fields which need to be re-validated later. */ rbcN->physics_constraint = NULL; } @@ -684,7 +684,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) if (totvert > 0 && tottri > 0) { BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL); - const float volume_scale = mat4_to_volume_scale(ob->obmat); + const float volume_scale = mat4_to_volume_scale(ob->object_to_world); volume *= fabsf(volume_scale); } } @@ -809,7 +809,7 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool return; } - mat4_to_loc_quat(loc, rot, ob->obmat); + mat4_to_loc_quat(loc, rot, ob->object_to_world); rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot); @@ -974,7 +974,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b rbc->physics_constraint = NULL; } - mat4_to_loc_quat(loc, rot, ob->obmat); + mat4_to_loc_quat(loc, rot, ob->object_to_world); if (rb1 && rb2) { switch (rbc->type) { @@ -1266,7 +1266,7 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) rbo->mesh_source = RBO_MESH_DEFORM; /* set initial transform */ - mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->object_to_world); /* flag cache as outdated */ BKE_rigidbody_cache_reset(rbw); @@ -1689,7 +1689,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyO if (!(rbo->flag & RBO_FLAG_KINEMATIC)) { /* update scale for all non kinematic objects */ float new_scale[3], old_scale[3]; - mat4_to_size(new_scale, ob->obmat); + mat4_to_size(new_scale, ob->object_to_world); RB_body_get_scale(rbo->shared->physics_object, old_scale); /* Avoid updating collision shape AABBs if scale didn't change. */ @@ -1886,7 +1886,7 @@ static ListBase rigidbody_create_substep_data(RigidBodyWorld *rbw) copy_v4_v4(data->old_rot, rot); copy_v3_v3(data->old_scale, scale); - mat4_decompose(loc, rot, scale, ob->obmat); + mat4_decompose(loc, rot, scale, ob->object_to_world); copy_v3_v3(data->new_pos, loc); copy_v4_v4(data->new_rot, rot); @@ -2055,15 +2055,15 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) quat_to_mat4(mat, rbo->orn); copy_v3_v3(mat[3], rbo->pos); - mat4_to_size(size, ob->obmat); + mat4_to_size(size, ob->object_to_world); size_to_mat4(size_mat, size); mul_m4_m4m4(mat, mat, size_mat); - copy_m4_m4(ob->obmat, mat); + copy_m4_m4(ob->object_to_world, mat); } /* otherwise set rigid body transform to current obmat */ else { - mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->object_to_world); } } diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index bd26075f81f..c921cf603de 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -2278,13 +2278,13 @@ int BKE_scene_base_iter_next( if (iter->dupli_refob != *ob) { if (iter->dupli_refob) { /* Restore previous object's real matrix. */ - copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + copy_m4_m4(iter->dupli_refob->object_to_world, iter->omat); } /* Backup new object's real matrix. */ iter->dupli_refob = *ob; - copy_m4_m4(iter->omat, iter->dupli_refob->obmat); + copy_m4_m4(iter->omat, iter->dupli_refob->object_to_world); } - copy_m4_m4((*ob)->obmat, iter->dupob->mat); + copy_m4_m4((*ob)->object_to_world, iter->dupob->mat); iter->dupob = iter->dupob->next; } @@ -2294,7 +2294,7 @@ int BKE_scene_base_iter_next( if (iter->dupli_refob) { /* Restore last object's real matrix. */ - copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + copy_m4_m4(iter->dupli_refob->object_to_world, iter->omat); iter->dupli_refob = nullptr; } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 3e5dbc47c40..2c896788b20 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -304,7 +304,7 @@ IDTypeInfo IDType_ID_SCR = { /* ************ Space-type/region-type handling ************** */ -/* keep global; this has to be accessible outside of windowmanager */ +/** Keep global; this has to be accessible outside of window-manager. */ static ListBase spacetypes = {NULL, NULL}; /* not SpaceType itself */ diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 14a7d26a354..4147999bef8 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -133,9 +133,9 @@ typedef struct SB_thread_context { #define BSF_INTERSECT 1 /* edge intersects collider face */ -/* private definitions for bodypoint states */ -#define SBF_DOFUZZY 1 /* Bodypoint do fuzzy. */ -#define SBF_OUTOFCOLLISION 2 /* Bodypoint does not collide. */ +/* private definitions for body-point states */ +#define SBF_DOFUZZY 1 /* Body-point do fuzzy. */ +#define SBF_OUTOFCOLLISION 2 /* Body-point does not collide. */ #define BFF_INTERSECT 1 /* collider edge intrudes face. */ #define BFF_CLOSEVERT 2 /* collider vertex repulses face. */ @@ -318,7 +318,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob) /* OBBs for idea1 */ pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax) * pccd_M->tri_num, "ccd_Mesh_Faces_mima"); - /* anyhoo we need to walk the list of faces and find OBB they live in */ + /* Anyhow we need to walk the list of faces and find OBB they live in. */ for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) { const float *v; @@ -413,7 +413,7 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M) pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull); } - /* anyhoo we need to walk the list of faces and find OBB they live in */ + /* Anyhow we need to walk the list of faces and find OBB they live in. */ for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) { const float *v; @@ -2644,7 +2644,7 @@ static void springs_from_mesh(Object *ob) bp = ob->soft->bpoint; for (a = 0; a < me->totvert; a++, bp++) { copy_v3_v3(bp->origS, verts[a].co); - mul_m4_v3(ob->obmat, bp->origS); + mul_m4_v3(ob->object_to_world, bp->origS); } } /* recalculate spring length for meshes here */ @@ -2809,9 +2809,9 @@ static float globallen(float *v1, float *v2, Object *ob) { float p1[3], p2[3]; copy_v3_v3(p1, v1); - mul_m4_v3(ob->obmat, p1); + mul_m4_v3(ob->object_to_world, p1); copy_v3_v3(p2, v2); - mul_m4_v3(ob->obmat, p2); + mul_m4_v3(ob->object_to_world, p2); return len_v3v3(p1, p2); } @@ -3073,7 +3073,7 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, SB_estimate_transform(ob, sb->lcom, sb->lrot, sb->lscale); } /* Inverse matrix is not up to date. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); for (a = 0; a < numVerts; a++, bp++) { copy_v3_v3(vertexCos[a], bp->pos); @@ -3223,7 +3223,7 @@ static void softbody_update_positions(Object *ob, /* copy the position of the goals at desired end time */ copy_v3_v3(bp->origE, vertexCos[a]); /* vertexCos came from local world, go global */ - mul_m4_v3(ob->obmat, bp->origE); + mul_m4_v3(ob->object_to_world, bp->origE); /* just to be save give bp->origT a defined value * will be calculated in interpolate_exciter() */ copy_v3_v3(bp->origT, bp->origE); @@ -3279,7 +3279,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int for (a = 0, bp = sb->bpoint; a < numVerts; a++, bp++) { copy_v3_v3(bp->pos, vertexCos[a]); - mul_m4_v3(ob->obmat, bp->pos); /* Yep, soft-body is global coords. */ + mul_m4_v3(ob->object_to_world, bp->pos); /* Yep, soft-body is global coords. */ copy_v3_v3(bp->origS, bp->pos); copy_v3_v3(bp->origE, bp->pos); copy_v3_v3(bp->origT, bp->pos); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index d08fba0e657..1aef42ef037 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -1129,9 +1129,9 @@ static void sound_update_base(Scene *scene, Object *object, void *new_set) AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner); AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer); - mat4_to_quat(quat, object->obmat); + mat4_to_quat(quat, object->object_to_world); AUD_SequenceEntry_setAnimationData( - strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, object->obmat[3], 1); + strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, object->object_to_world[3], 1); AUD_SequenceEntry_setAnimationData( strip->speaker_handle, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1); AUD_SequenceEntry_setAnimationData( @@ -1171,9 +1171,9 @@ void BKE_sound_update_scene(Depsgraph *depsgraph, Scene *scene) } if (scene->camera) { - mat4_to_quat(quat, scene->camera->obmat); + mat4_to_quat(quat, scene->camera->object_to_world); AUD_Sequence_setAnimationData( - scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, scene->camera->obmat[3], 1); + scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, scene->camera->object_to_world[3], 1); AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1); } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index f7ea4c81fbf..f5badfc9e94 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -715,7 +715,7 @@ static const char *unit_find_str(const char *str, const char *substr, bool case_ /* Weak unicode support!, so "µm" won't match up be replaced by "m" * since non ascii utf8 values will NEVER return true */ isalpha_or_utf8(*BLI_str_find_prev_char_utf8(str_found, str)) == 0) { - /* Next char cannot be alphanum. */ + /* Next char cannot be alpha-numeric. */ int len_name = strlen(substr); if (!isalpha_or_utf8(*(str_found + len_name))) { diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c index 7ace1a3aa3b..9f48b9b9c4a 100644 --- a/source/blender/blenkernel/intern/vfont.c +++ b/source/blender/blenkernel/intern/vfont.c @@ -1310,14 +1310,14 @@ static bool vfont_to_curve(Object *ob, float timeofs, sizefac; if (ob != NULL) { - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); } else { unit_m4(imat); } copy_m3_m4(imat3, imat); - copy_m3_m4(cmat, cu->textoncurve->obmat); + copy_m3_m4(cmat, cu->textoncurve->object_to_world); mul_m3_m3m3(cmat, cmat, imat3); sizefac = normalize_v3(cmat[0]) / font_size; diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 7c54b4d3f2f..e81657f9ef0 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -445,7 +445,7 @@ struct VolumeGrid { * may actually be loaded by another user while this is false. But only after * calling load() and is_loaded changes to true is it safe to access. * - * Const write access to this must be protected by `entry->mutex`. + * `const` write access to this must be protected by `entry->mutex`. */ mutable bool is_loaded; }; @@ -480,7 +480,7 @@ struct VolumeGridVector : public std::list<VolumeGrid> { metadata.reset(); } - /* Mutex for file loading of grids list. Const write access to the fields after this must be + /* Mutex for file loading of grids list. `const` write access to the fields after this must be * protected by locking with this mutex. */ mutable std::mutex mutex; /* Absolute file path that grids have been loaded from. */ diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index dbdf8cc395d..de2e196c163 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -122,7 +122,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, - R_IMF_IMTYPE_THEORA)) { + R_IMF_IMTYPE_THEORA, + R_IMF_IMTYPE_AV1)) { mh.start_movie = BKE_ffmpeg_start; mh.append_movie = BKE_ffmpeg_append; mh.end_movie = BKE_ffmpeg_end; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 99df07b6105..ee827cd8cd4 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -299,6 +299,10 @@ static const char **get_file_extensions(int format) static const char *rv[] = {".webm", NULL}; return rv; } + case FFMPEG_AV1: { + static const char *rv[] = {".mp4", ".mkv", NULL}; + return rv; + } default: return NULL; } @@ -455,6 +459,204 @@ static AVRational calc_time_base(uint den, double num, int codec_id) return time_base; } +static const AVCodec *get_av1_encoder( + FFMpegContext *context, RenderData *rd, AVDictionary **opts, int rectx, int recty) +{ + /* There are three possible encoders for AV1: libaom-av1, librav1e, and libsvtav1. librav1e tends + * to give the best compression quality while libsvtav1 tends to be the fastest encoder. One of + * each will be picked based on the preset setting, and if a particular encoder is not available, + * then use the default returned by FFMpeg. */ + const AVCodec *codec = NULL; + switch (context->ffmpeg_preset) { + case FFM_PRESET_BEST: + /* Default to libaom-av1 for BEST preset due to it performing better than rav1e in terms of + * video quality (VMAF scores). Fallback to rav1e if libaom-av1 isn't available. */ + codec = avcodec_find_encoder_by_name("libaom-av1"); + if (!codec) { + codec = avcodec_find_encoder_by_name("librav1e"); + } + break; + case FFM_PRESET_REALTIME: + codec = avcodec_find_encoder_by_name("libsvtav1"); + break; + case FFM_PRESET_GOOD: + default: + codec = avcodec_find_encoder_by_name("libaom-av1"); + break; + } + + /* Use the default AV1 encoder if the specified encoder wasn't found. */ + if (!codec) { + codec = avcodec_find_encoder(AV_CODEC_ID_AV1); + } + + /* Apply AV1 encoder specific settings. */ + if (codec) { + if (STREQ(codec->name, "librav1e")) { + /* Set "tiles" to 8 to enable multi-threaded encoding. */ + if (rd->threads > 8) { + ffmpeg_dict_set_int(opts, "tiles", rd->threads); + } + else { + ffmpeg_dict_set_int(opts, "tiles", 8); + } + + /* Use a reasonable speed setting based on preset. Speed ranges from 0-10. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "speed", 4); + break; + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "speed", 10); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "speed", 6); + break; + } + if (context->ffmpeg_crf >= 0) { + /* librav1e does not use -crf, but uses -qp in the range of 0-255. Calculates the roughly + * equivalent float, and truncates it to an integer. */ + unsigned int qp_value = ((float)context->ffmpeg_crf) * 255.0F / 51.0F; + if (qp_value > 255) { + qp_value = 255; + } + ffmpeg_dict_set_int(opts, "qp", qp_value); + } + /* Set gop_size as rav1e's "--keyint". */ + char buffer[64]; + BLI_snprintf(buffer, sizeof(buffer), "keyint=%d", context->ffmpeg_gop_size); + av_dict_set(opts, "rav1e-params", buffer, 0); + } + else if (STREQ(codec->name, "libsvtav1")) { + /* Set preset value based on ffmpeg_preset. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "preset", 8); + break; + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "preset", 3); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "preset", 5); + break; + } + if (context->ffmpeg_crf >= 0) { + /* libsvtav1 does not support crf until FFmpeg builds since 2022-02-24, use qp as fallback. + */ + ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf); + } + } + else if (STREQ(codec->name, "libaom-av1")) { + /* Speed up libaom-av1 encoding by enabling multithreading and setting tiles. */ + ffmpeg_dict_set_int(opts, "row-mt", 1); + const char *tiles_string = NULL; + bool tiles_string_is_dynamic = false; + if (rd->threads > 0) { + /* See if threads is a square. */ + int threads_sqrt = sqrtf(rd->threads); + if (threads_sqrt < 4) { + /* Ensure a default minimum. */ + threads_sqrt = 4; + } + if (is_power_of_2_i(threads_sqrt) && threads_sqrt * threads_sqrt == rd->threads) { + /* Is a square num, therefore just do "sqrt x sqrt" for tiles parameter. */ + int digits = 0; + for (int t_sqrt_copy = threads_sqrt; t_sqrt_copy > 0; t_sqrt_copy /= 10) { + ++digits; + } + /* A char array need only an alignment of 1. */ + char *tiles_string_mut = (char *)calloc(digits * 2 + 2, 1); + BLI_snprintf(tiles_string_mut, digits * 2 + 2, "%dx%d", threads_sqrt, threads_sqrt); + tiles_string_is_dynamic = true; + tiles_string = tiles_string_mut; + } + else { + /* Is not a square num, set greater side based on longer side, or use a square if both + sides are equal. */ + int sqrt_p2 = power_of_2_min_i(threads_sqrt); + if (sqrt_p2 < 2) { + /* Ensure a default minimum. */ + sqrt_p2 = 2; + } + int sqrt_p2_next = power_of_2_min_i((int)rd->threads / sqrt_p2); + if (sqrt_p2_next < 1) { + sqrt_p2_next = 1; + } + if (sqrt_p2 > sqrt_p2_next) { + /* Ensure sqrt_p2_next is greater or equal to sqrt_p2. */ + int temp = sqrt_p2; + sqrt_p2 = sqrt_p2_next; + sqrt_p2_next = temp; + } + int combined_digits = 0; + for (int sqrt_p2_copy = sqrt_p2; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) { + ++combined_digits; + } + for (int sqrt_p2_copy = sqrt_p2_next; sqrt_p2_copy > 0; sqrt_p2_copy /= 10) { + ++combined_digits; + } + /* A char array need only an alignment of 1. */ + char *tiles_string_mut = (char *)calloc(combined_digits + 2, 1); + if (rectx > recty) { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2_next, sqrt_p2); + } + else if (rectx < recty) { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2_next); + } + else { + BLI_snprintf(tiles_string_mut, combined_digits + 2, "%dx%d", sqrt_p2, sqrt_p2); + } + tiles_string_is_dynamic = true; + tiles_string = tiles_string_mut; + } + } + else { + /* Thread count unknown, default to 8. */ + if (rectx > recty) { + tiles_string = "4x2"; + } + else if (rectx < recty) { + tiles_string = "2x4"; + } + else { + tiles_string = "2x2"; + } + } + av_dict_set(opts, "tiles", tiles_string, 0); + if (tiles_string_is_dynamic) { + free((void *)tiles_string); + } + /* libaom-av1 uses "cpu-used" instead of "preset" for defining compression quality. + * This value is in a range from 0-8. 0 and 8 are extremes, but we will allow 8. + * Must check context->ffmpeg_preset again in case this encoder was selected due to the + * absence of another. */ + switch (context->ffmpeg_preset) { + case FFM_PRESET_REALTIME: + ffmpeg_dict_set_int(opts, "cpu-used", 8); + break; + case FFM_PRESET_BEST: + ffmpeg_dict_set_int(opts, "cpu-used", 4); + break; + case FFM_PRESET_GOOD: + default: + ffmpeg_dict_set_int(opts, "cpu-used", 6); + break; + } + + /* CRF related settings is similar to H264 for libaom-av1, so we will rely on those settings + * applied later. */ + } + } + + return codec; +} + /* prepare a video stream for the output file */ static AVStream *alloc_video_stream(FFMpegContext *context, @@ -480,7 +682,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context, /* Set up the codec context */ - codec = avcodec_find_encoder(codec_id); + if (codec_id == AV_CODEC_ID_AV1) { + /* Use get_av1_encoder() to get the ideal (hopefully) encoder for AV1 based + * on given parameters, and also set up opts. */ + codec = get_av1_encoder(context, rd, &opts, rectx, recty); + } + else { + codec = avcodec_find_encoder(codec_id); + } if (!codec) { fprintf(stderr, "Couldn't find valid video codec\n"); context->video_codec = NULL; @@ -568,7 +777,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context, default: printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset); } - if (preset_name != NULL) { + /* "codec_id != AV_CODEC_ID_AV1" is required due to "preset" already being set by an AV1 codec. + */ + if (preset_name != NULL && codec_id != AV_CODEC_ID_AV1) { av_dict_set(&opts, "preset", preset_name, 0); } if (deadline_name != NULL) { @@ -806,7 +1017,7 @@ static AVStream *alloc_audio_stream(FFMpegContext *context, return NULL; } - /* need to prevent floating point exception when using vorbis audio codec, + /* Need to prevent floating point exception when using VORBIS audio codec, * initialize this value in the same way as it's done in FFmpeg itself (sergey) */ c->time_base.num = 1; c->time_base.den = c->sample_rate; @@ -951,6 +1162,9 @@ static int start_ffmpeg_impl(FFMpegContext *context, case FFMPEG_FLV: video_codec = AV_CODEC_ID_FLV1; break; + case FFMPEG_AV1: + video_codec = AV_CODEC_ID_AV1; + break; default: /* These containers are not restricted to any specific codec types. * Currently we expect these to be .avi, .mov, .mkv, and .mp4. @@ -1482,6 +1696,18 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset) rd->ffcodecdata.mux_packet_size = 2048; rd->ffcodecdata.mux_rate = 10080000; break; + case FFMPEG_PRESET_AV1: + rd->ffcodecdata.type = FFMPEG_AV1; + rd->ffcodecdata.codec = AV_CODEC_ID_AV1; + rd->ffcodecdata.video_bitrate = 6000; + rd->ffcodecdata.gop_size = is_ntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 9000; + rd->ffcodecdata.rc_min_rate = 0; + rd->ffcodecdata.rc_buffer_size = 224 * 8; + rd->ffcodecdata.mux_packet_size = 2048; + rd->ffcodecdata.mux_rate = 10080000; + + break; } } @@ -1521,6 +1747,12 @@ void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf) audio = 1; } } + else if (imf->imtype == R_IMF_IMTYPE_AV1) { + if (rd->ffcodecdata.codec != AV_CODEC_ID_AV1) { + BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_AV1); + audio = 1; + } + } if (audio && rd->ffcodecdata.audio_codec < 0) { rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE; diff --git a/source/blender/blenlib/BLI_array_utils.hh b/source/blender/blenlib/BLI_array_utils.hh index 95b3bde10f4..264ac00e034 100644 --- a/source/blender/blenlib/BLI_array_utils.hh +++ b/source/blender/blenlib/BLI_array_utils.hh @@ -42,6 +42,11 @@ void gather(const GVArray &src, IndexMask indices, GMutableSpan dst, int64_t gra /** * Fill the destination span by gathering indexed values from the `src` array. */ +void gather(GSpan src, IndexMask indices, GMutableSpan dst, int64_t grain_size = 4096); + +/** + * Fill the destination span by gathering indexed values from the `src` array. + */ template<typename T> inline void gather(const VArray<T> &src, const IndexMask indices, diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 7e1b7c2ba56..538474f58b6 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -624,7 +624,7 @@ void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float n void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float no[3]); #define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \ - BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat) + BLI_space_transform_from_matrices((data), (local)->object_to_world, (target)->object_to_world) /** \} */ diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index d4d2ddead71..1b723ab038d 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -68,8 +68,15 @@ const char *BLI_path_extension(const char *filepath) ATTR_NONNULL(); /** * Append a filename to a dir, ensuring slash separates. + * \return The new length of `dst`. */ -void BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file) +size_t BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file) + ATTR_NONNULL(); +/** + * A version of #BLI_path_append that ensures a trailing slash if there is space in `dst`. + * \return The new length of `dst`. + */ +size_t BLI_path_append_dir(char *__restrict dst, size_t maxlen, const char *__restrict dir) ATTR_NONNULL(); /** @@ -218,7 +225,7 @@ const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UN * Appends a slash to string if there isn't one there already. * Returns the new length of the string. */ -int BLI_path_slash_ensure(char *string) ATTR_NONNULL(); +int BLI_path_slash_ensure(char *string, size_t string_maxlen) ATTR_NONNULL(1); /** * Removes the last slash and everything after it to the end of string, if there is one. */ @@ -314,7 +321,7 @@ void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2); * * \note Same as #BLI_path_normalize but adds a trailing slash. */ -void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2); +void BLI_path_normalize_dir(const char *relabase, char *dir, size_t dir_maxlen) ATTR_NONNULL(2); /** * Make given name safe to be used in paths. @@ -357,6 +364,8 @@ bool BLI_path_make_safe(char *path) ATTR_NONNULL(1); * * Replaces path with the path of its parent directory, returning true if * it was able to find a parent directory within the path. + * + * On success, the resulting path will always have a trailing slash. */ bool BLI_path_parent_dir(char *path) ATTR_NONNULL(); /** diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 15926e8f2d2..17abcf52ecc 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -309,6 +309,28 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, bool base_10) A */ void BLI_str_format_decimal_unit(char dst[7], int number_to_format) ATTR_NONNULL(); /** + * Format a count to up to 3 places (plus minus sign, plus '\0' terminator) string using long + * number names abbreviations. Used to produce a compact representation of large numbers as + * integers. + * + * It shows a lower bound instead of rounding the number. + * + * 1 -> 1 + * 15 -> 15 + * 155 -> 155 + * 1555 -> 1K + * 15555 -> 15K + * 155555 -> .1M + * 1555555 -> 1M + * 15555555 -> 15M + * 155555555 -> .1B + * 1000000000 -> 1B + * ... + * + * Length of 5 is the maximum of the resulting string, for example, `-15K\0`. + */ +void BLI_str_format_integer_unit(char dst[5], int number_to_format) ATTR_NONNULL(); +/** * Compare two strings without regard to case. * * \retval True if the strings are equal, false otherwise. diff --git a/source/blender/blenlib/BLI_uvproject.h b/source/blender/blenlib/BLI_uvproject.h index 75f39de6b7f..a94fd796121 100644 --- a/source/blender/blenlib/BLI_uvproject.h +++ b/source/blender/blenlib/BLI_uvproject.h @@ -15,7 +15,7 @@ struct ProjCameraInfo; /** * Create UV info from the camera, needs to be freed. * - * \param rotmat: can be `obedit->obmat` when uv project is used. + * \param rotmat: can be `obedit->object_to_world` when uv project is used. * \param winx, winy: can be from `scene->r.xsch / ysch`. */ struct ProjCameraInfo *BLI_uvproject_camera_info(struct Object *ob, diff --git a/source/blender/blenlib/intern/array_utils.cc b/source/blender/blenlib/intern/array_utils.cc index a837d6aceec..2a231228dcb 100644 --- a/source/blender/blenlib/intern/array_utils.cc +++ b/source/blender/blenlib/intern/array_utils.cc @@ -28,4 +28,9 @@ void gather(const GVArray &src, }); } +void gather(const GSpan src, const IndexMask indices, GMutableSpan dst, const int64_t grain_size) +{ + gather(GVArray::ForSpan(src), indices, dst, grain_size); +} + } // namespace blender::array_utils diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index a157302e51e..005de1f85b4 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -401,7 +401,7 @@ static bool delete_recursive(const char *dir) /* dir listing produces dir path without trailing slash... */ BLI_strncpy(path, fl->path, sizeof(path)); - BLI_path_slash_ensure(path); + BLI_path_slash_ensure(path, sizeof(path)); if (delete_recursive(path)) { err = true; diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h index 6614f1bf964..f7993eb5adc 100644 --- a/source/blender/blenlib/intern/kdtree_impl.h +++ b/source/blender/blenlib/intern/kdtree_impl.h @@ -11,9 +11,9 @@ #include "BLI_strict_flags.h" #include "BLI_utildefines.h" -#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 -#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) -#define BLI_kdtree_nd_(id) _CONCAT(KDTREE_PREFIX_ID, _##id) +#define _BLI_KDTREE_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 +#define _BLI_KDTREE_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_KDTREE_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) +#define BLI_kdtree_nd_(id) _BLI_KDTREE_CONCAT(KDTREE_PREFIX_ID, _##id) typedef struct KDTreeNode_head { uint left, right; diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h index e1b93986f4a..7c38fc60b29 100644 --- a/source/blender/blenlib/intern/list_sort_impl.h +++ b/source/blender/blenlib/intern/list_sort_impl.h @@ -47,24 +47,25 @@ #endif #ifdef SORT_IMPL_USE_THUNK -# define THUNK_APPEND1(a, thunk) a, thunk -# define THUNK_PREPEND2(thunk, a, b) thunk, a, b +# define BLI_LIST_THUNK_APPEND1(a, thunk) a, thunk +# define BLI_LIST_THUNK_PREPEND2(thunk, a, b) thunk, a, b #else -# define THUNK_APPEND1(a, thunk) a -# define THUNK_PREPEND2(thunk, a, b) a, b +# define BLI_LIST_THUNK_APPEND1(a, thunk) a +# define BLI_LIST_THUNK_PREPEND2(thunk, a, b) a, b #endif -#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 -#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) -#define _SORT_PREFIX(id) _CONCAT(SORT_IMPL_FUNC, _##id) +#define _BLI_LIST_SORT_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 +#define _BLI_LIST_SORT_CONCAT(MACRO_ARG1, MACRO_ARG2) \ + _BLI_LIST_SORT_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) +#define _BLI_LIST_SORT_PREFIX(id) _BLI_LIST_SORT_CONCAT(SORT_IMPL_FUNC, _##id) /* local identifiers */ -#define SortInfo _SORT_PREFIX(SortInfo) -#define CompareFn _SORT_PREFIX(CompareFn) -#define init_sort_info _SORT_PREFIX(init_sort_info) -#define merge_lists _SORT_PREFIX(merge_lists) -#define sweep_up _SORT_PREFIX(sweep_up) -#define insert_list _SORT_PREFIX(insert_list) +#define SortInfo _BLI_LIST_SORT_PREFIX(SortInfo) +#define CompareFn _BLI_LIST_SORT_PREFIX(CompareFn) +#define init_sort_info _BLI_LIST_SORT_PREFIX(init_sort_info) +#define merge_lists _BLI_LIST_SORT_PREFIX(merge_lists) +#define sweep_up _BLI_LIST_SORT_PREFIX(sweep_up) +#define insert_list _BLI_LIST_SORT_PREFIX(insert_list) typedef int (*CompareFn)( #ifdef SORT_IMPL_USE_THUNK @@ -159,7 +160,7 @@ BLI_INLINE list_node *merge_lists(list_node *first, list_node *list = NULL; list_node **pos = &list; while (first && second) { - if (func(THUNK_PREPEND2(thunk, SORT_ARG(first), SORT_ARG(second))) > 0) { + if (func(BLI_LIST_THUNK_PREPEND2(thunk, SORT_ARG(first), SORT_ARG(second))) > 0) { *pos = second; second = second->next; } @@ -181,7 +182,7 @@ BLI_INLINE list_node *sweep_up(struct SortInfo *si, list_node *list, unsigned in { unsigned int i; for (i = si->min_rank; i < upto; i++) { - list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists(si->ranks[i], list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); si->ranks[i] = NULL; } return list; @@ -225,17 +226,19 @@ BLI_INLINE void insert_list(struct SortInfo *si, list_node *list, unsigned int r // printf("Rank '%d' should not exceed " STRINGIFY(MAX_RANKS), rank); rank = MAX_RANKS; } - list = merge_lists(sweep_up(si, NULL, si->n_ranks), list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists( + sweep_up(si, NULL, si->n_ranks), list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); for (i = si->n_ranks; i < rank; i++) { si->ranks[i] = NULL; } } else { if (rank) { - list = merge_lists(sweep_up(si, NULL, rank), list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists( + sweep_up(si, NULL, rank), list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); } for (i = rank; i < si->n_ranks && si->ranks[i]; i++) { - list = merge_lists(si->ranks[i], list, THUNK_APPEND1(si->func, si->thunk)); + list = merge_lists(si->ranks[i], list, BLI_LIST_THUNK_APPEND1(si->func, si->thunk)); si->ranks[i] = NULL; } } @@ -281,7 +284,7 @@ BLI_INLINE list_node *list_sort_do(list_node *list, list_node *next = list->next; list_node *tail = next->next; - if (func(THUNK_PREPEND2(thunk, SORT_ARG(list), SORT_ARG(next))) > 0) { + if (func(BLI_LIST_THUNK_PREPEND2(thunk, SORT_ARG(list), SORT_ARG(next))) > 0) { next->next = list; next = list; list = list->next; @@ -296,8 +299,8 @@ BLI_INLINE list_node *list_sort_do(list_node *list, return sweep_up(&si, list, si.n_ranks); } -#undef _CONCAT_AUX -#undef _CONCAT +#undef _BLI_LIST_SORT_CONCAT_AUX +#undef _BLI_LIST_SORT_CONCAT #undef _SORT_PREFIX #undef SortInfo @@ -310,6 +313,6 @@ BLI_INLINE list_node *list_sort_do(list_node *list, #undef list_node #undef list_sort_do -#undef THUNK_APPEND1 -#undef THUNK_PREPEND2 +#undef BLI_LIST_THUNK_APPEND1 +#undef BLI_LIST_THUNK_PREPEND2 #undef SORT_ARG diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index afe8c3cc033..3a87b39a446 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -153,6 +153,19 @@ void BLI_path_normalize(const char *relabase, char *path) */ #ifdef WIN32 + + while ((start = strstr(path, "\\.\\"))) { + eind = start + strlen("\\.\\") - 1; + memmove(start, eind, strlen(eind) + 1); + } + + /* remove two consecutive backslashes, but skip the UNC prefix, + * which needs to be preserved */ + while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) { + eind = start + strlen("\\\\") - 1; + memmove(start, eind, strlen(eind) + 1); + } + while ((start = strstr(path, "\\..\\"))) { eind = start + strlen("\\..\\") - 1; a = start - path - 1; @@ -170,18 +183,18 @@ void BLI_path_normalize(const char *relabase, char *path) } } - while ((start = strstr(path, "\\.\\"))) { - eind = start + strlen("\\.\\") - 1; +#else + + while ((start = strstr(path, "/./"))) { + eind = start + (3 - 1) /* strlen("/./") - 1 */; memmove(start, eind, strlen(eind) + 1); } - /* remove two consecutive backslashes, but skip the UNC prefix, - * which needs to be preserved */ - while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) { - eind = start + strlen("\\\\") - 1; + while ((start = strstr(path, "//"))) { + eind = start + (2 - 1) /* strlen("//") - 1 */; memmove(start, eind, strlen(eind) + 1); } -#else + while ((start = strstr(path, "/../"))) { a = start - path - 1; if (a > 0) { @@ -206,19 +219,10 @@ void BLI_path_normalize(const char *relabase, char *path) } } - while ((start = strstr(path, "/./"))) { - eind = start + (3 - 1) /* strlen("/./") - 1 */; - memmove(start, eind, strlen(eind) + 1); - } - - while ((start = strstr(path, "//"))) { - eind = start + (2 - 1) /* strlen("//") - 1 */; - memmove(start, eind, strlen(eind) + 1); - } #endif } -void BLI_path_normalize_dir(const char *relabase, char *dir) +void BLI_path_normalize_dir(const char *relabase, char *dir, size_t dir_maxlen) { /* Would just create an unexpected "/" path, just early exit entirely. */ if (dir[0] == '\0') { @@ -226,7 +230,7 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) } BLI_path_normalize(relabase, dir); - BLI_path_slash_ensure(dir); + BLI_path_slash_ensure(dir, dir_maxlen); } bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) @@ -622,18 +626,38 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char bool BLI_path_parent_dir(char *path) { - const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */ - char tmp[FILE_MAX + 4]; - - BLI_path_join(tmp, sizeof(tmp), path, parent_dir); - BLI_path_normalize(NULL, tmp); /* does all the work of normalizing the path for us */ + char tmp[FILE_MAX]; - if (!BLI_path_extension_check(tmp, parent_dir)) { - strcpy(path, tmp); /* We assume the parent directory is always shorter. */ - return true; + STRNCPY(tmp, path); + /* Does all the work of normalizing the path for us. + * + * NOTE(@campbellbarton): While it's possible strip text after the second last slash, + * this would have to be clever and skip cases like "/./" & multiple slashes. + * Since this ends up solving some of the same problems as #BLI_path_normalize, + * call this function instead of attempting to handle them separately. */ + BLI_path_normalize(NULL, tmp); + + /* Use #BLI_path_name_at_index instead of checking if the strings ends with `parent_dir` + * to ensure the logic isn't confused by: + * - Directory names that happen to end with `..`. + * - When `path` is empty, the contents will be `../` + * which would cause checking for a tailing `/../` fail. + * Extracting the span of the final directory avoids both these issues. */ + int tail_ofs = 0, tail_len = 0; + if (!BLI_path_name_at_index(tmp, -1, &tail_ofs, &tail_len)) { + return false; + } + if (tail_len == 1) { + /* Last path is ".", as normalize should remove this, it's safe to assume failure. + * This happens when the input a single period (possibly with slashes before or after). */ + if (tmp[tail_ofs] == '.') { + return false; + } } - return false; + memcpy(path, tmp, tail_ofs); + path[tail_ofs] = '\0'; + return true; } bool BLI_path_parent_dir_until_exists(char *dir) @@ -1431,21 +1455,34 @@ const char *BLI_path_extension(const char *filepath) return extension; } -void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) +size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) { size_t dirlen = BLI_strnlen(dst, maxlen); - /* inline BLI_path_slash_ensure */ + /* Inline #BLI_path_slash_ensure. */ if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) { dst[dirlen++] = SEP; dst[dirlen] = '\0'; } if (dirlen >= maxlen) { - return; /* fills the path */ + return dirlen; /* fills the path */ } - BLI_strncpy(dst + dirlen, file, maxlen - dirlen); + return dirlen + BLI_strncpy_rlen(dst + dirlen, file, maxlen - dirlen); +} + +size_t BLI_path_append_dir(char *__restrict dst, const size_t maxlen, const char *__restrict dir) +{ + size_t dirlen = BLI_path_append(dst, maxlen, dir); + if (dirlen + 1 < maxlen) { + /* Inline #BLI_path_slash_ensure. */ + if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) { + dst[dirlen++] = SEP; + dst[dirlen] = '\0'; + } + } + return dirlen; } size_t BLI_path_join_array(char *__restrict dst, @@ -1469,14 +1506,36 @@ size_t BLI_path_join_array(char *__restrict dst, return ofs; } +#ifdef WIN32 + /* Special case "//" for relative paths, don't use separator #SEP + * as this has a special meaning on both WIN32 & UNIX. + * Without this check joining `"//", "path"`. results in `"//\path"`. */ + if (ofs != 0) { + size_t i; + for (i = 0; i < ofs; i++) { + if (dst[i] != '/') { + break; + } + } + if (i == ofs) { + /* All slashes, keep them as-is, and join the remaining path array. */ + return path_array_num > 1 ? + BLI_path_join_array( + dst + ofs, dst_len - ofs, &path_array[1], path_array_num - 1) : + ofs; + } + } +#endif + /* Remove trailing slashes, unless there are *only* trailing slashes * (allow `//` or `//some_path` as the first argument). */ bool has_trailing_slash = false; if (ofs != 0) { size_t len = ofs; - while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) { + while ((len != 0) && (path[len - 1] == SEP)) { len -= 1; } + if (len != 0) { ofs = len; } @@ -1487,18 +1546,18 @@ size_t BLI_path_join_array(char *__restrict dst, path = path_array[path_index]; has_trailing_slash = false; const char *path_init = path; - while (ELEM(path[0], SEP, ALTSEP)) { + while (path[0] == SEP) { path++; } size_t len = strlen(path); if (len != 0) { - while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) { + while ((len != 0) && (path[len - 1] == SEP)) { len -= 1; } if (len != 0) { /* the very first path may have a slash at the end */ - if (ofs && !ELEM(dst[ofs - 1], SEP, ALTSEP)) { + if (ofs && (dst[ofs - 1] != SEP)) { dst[ofs++] = SEP; if (ofs == dst_last) { break; @@ -1521,7 +1580,7 @@ size_t BLI_path_join_array(char *__restrict dst, } if (has_trailing_slash) { - if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) { + if ((ofs != dst_last) && (ofs != 0) && (dst[ofs - 1] != SEP)) { dst[ofs++] = SEP; } } @@ -1549,7 +1608,7 @@ bool BLI_path_name_at_index(const char *__restrict path, int i = 0; while (true) { const char c = path[i]; - if (ELEM(c, SEP, ALTSEP, '\0')) { + if (ELEM(c, SEP, '\0')) { if (prev + 1 != i) { prev += 1; if (index_step == index) { @@ -1576,7 +1635,7 @@ bool BLI_path_name_at_index(const char *__restrict path, int i = prev - 1; while (true) { const char c = i >= 0 ? path[i] : '\0'; - if (ELEM(c, SEP, ALTSEP, '\0')) { + if (ELEM(c, SEP, '\0')) { if (prev - 1 != i) { i += 1; if (index_step == index) { @@ -1624,7 +1683,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path) /* Add a trailing slash to prevent same-prefix directories from matching. * e.g. "/some/path" doesn't contain "/some/path_lib". */ - BLI_path_slash_ensure(container_native); + BLI_path_slash_ensure(container_native, sizeof(container_native)); return BLI_str_startswith(containee_native, container_native); } @@ -1659,13 +1718,17 @@ const char *BLI_path_slash_rfind(const char *string) return (lfslash > lbslash) ? lfslash : lbslash; } -int BLI_path_slash_ensure(char *string) +int BLI_path_slash_ensure(char *string, size_t string_maxlen) { int len = strlen(string); + BLI_assert(len < string_maxlen); if (len == 0 || string[len - 1] != SEP) { - string[len] = SEP; - string[len + 1] = '\0'; - return len + 1; + /* Avoid unlikely buffer overflow. */ + if (len + 1 < string_maxlen) { + string[len] = SEP; + string[len + 1] = '\0'; + return len + 1; + } } return len; } diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 89d31c5e93f..755d2dbd55d 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -1176,4 +1176,34 @@ void BLI_str_format_decimal_unit(char dst[7], int number_to_format) BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]); } +void BLI_str_format_integer_unit(char dst[5], const int number_to_format) +{ + float number_to_format_converted = number_to_format; + int order = 0; + const float base = 1000; + const char *units[] = {"", "K", "M", "B"}; + const int units_num = ARRAY_SIZE(units); + + while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) { + number_to_format_converted /= base; + order++; + } + + const bool add_dot = (abs(number_to_format) > 99999) && fabsf(number_to_format_converted) > 99; + + if (add_dot) { + number_to_format_converted /= 100; + order++; + } + + const size_t dst_len = 5; + BLI_snprintf(dst, + dst_len, + "%s%s%d%s", + number_to_format < 0 ? "-" : "", + add_dot ? "." : "", + (int)floorf(fabsf(number_to_format_converted)), + units[order]); +} + /** \} */ diff --git a/source/blender/blenlib/intern/uvproject.c b/source/blender/blenlib/intern/uvproject.c index 347166bd57d..0398bf0b3fe 100644 --- a/source/blender/blenlib/intern/uvproject.c +++ b/source/blender/blenlib/intern/uvproject.c @@ -129,7 +129,7 @@ ProjCameraInfo *BLI_uvproject_camera_info(Object *ob, float rotmat[4][4], float uci.camsize = uci.do_persp ? tanf(uci.camangle) : camera->ortho_scale; /* account for scaled cameras */ - copy_m4_m4(uci.caminv, ob->obmat); + copy_m4_m4(uci.caminv, ob->object_to_world); normalize_m4(uci.caminv); if (invert_m4(uci.caminv)) { diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 89e537235db..293d353efcc 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -9,69 +9,166 @@ #include "BLI_string.h" /* -------------------------------------------------------------------- */ -/* tests */ +/** \name Local Utilities + * \{ */ -/* BLI_path_normalize */ -#ifndef _WIN32 -TEST(path_util, Clean) +static void str_replace_char_with_relative_exception(char *str, char src, char dst) { - /* "/./" -> "/" */ - { - char path[FILE_MAX] = "/a/./b/./c/./"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/a/b/c/", path); + /* Always keep "//" or more leading slashes (special meaning). */ + if (src == '/') { + if (str[0] == '/' && str[1] == '/') { + str += 2; + while (*str == '/') { + str++; + } + } } + BLI_str_replace_char(str, src, dst); +} - { - char path[FILE_MAX] = "/./././"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/", path); +static char *str_replace_char_strdup(const char *str, char src, char dst) +{ + if (str == nullptr) { + return nullptr; } + char *str_dupe = strdup(str); + BLI_str_replace_char(str_dupe, src, dst); + return str_dupe; +} - { - char path[FILE_MAX] = "/a/./././b/"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/a/b/", path); - } +/** \} */ - /* "//" -> "/" */ - { - char path[FILE_MAX] = "a////"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("a/", path); - } +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_normalize + * \{ */ - if (false) /* FIXME */ - { - char path[FILE_MAX] = "./a////"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("./a/", path); - } +#define NORMALIZE_WITH_BASEDIR(input, input_base, output) \ + { \ + char path[FILE_MAX] = input; \ + const char *input_base_test = input_base; \ + if (SEP == '\\') { \ + str_replace_char_with_relative_exception(path, '/', '\\'); \ + input_base_test = str_replace_char_strdup(input_base_test, '/', '\\'); \ + } \ + BLI_path_normalize(input_base_test, path); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '\\', '/'); \ + if (input_base_test) { \ + free((void *)input_base_test); \ + } \ + } \ + EXPECT_STREQ(output, path); \ + } \ + ((void)0) - /* "foo/bar/../" -> "foo/" */ - { - char path[FILE_MAX] = "/a/b/c/../../../"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/", path); - } +#define NORMALIZE(input, output) NORMALIZE_WITH_BASEDIR(input, nullptr, output) - { - char path[FILE_MAX] = "/a/../a/b/../b/c/../c/"; - BLI_path_normalize(nullptr, path); - EXPECT_STREQ("/a/b/c/", path); - } +/* #BLI_path_normalize: "/./" -> "/" */ +TEST(path_util, Clean_Dot) +{ + NORMALIZE("/./", "/"); + NORMALIZE("/a/./b/./c/./", "/a/b/c/"); + NORMALIZE("/./././", "/"); + NORMALIZE("/a/./././b/", "/a/b/"); +} +/* #BLI_path_normalize: complex "/./" -> "/", "//" -> "/", "./path/../" -> "./". */ +TEST(path_util, Clean_Complex) +{ + NORMALIZE("/a/./b/./c/./.././.././", "/a/"); + NORMALIZE("/a//.//b//.//c//.//..//.//..//.//", "/a/"); +} +/* #BLI_path_normalize: "//" -> "/" */ +TEST(path_util, Clean_DoubleSlash) +{ + NORMALIZE("//", "//"); /* Exception, double forward slash. */ + NORMALIZE(".//", "./"); + NORMALIZE("a////", "a/"); + NORMALIZE("./a////", "./a/"); +} +/* #BLI_path_normalize: "foo/bar/../" -> "foo/" */ +TEST(path_util, Clean_Parent) +{ + NORMALIZE("/a/b/c/../../../", "/"); + NORMALIZE("/a/../a/b/../b/c/../c/", "/a/b/c/"); + NORMALIZE_WITH_BASEDIR("//../", "/a/b/c/", "/a/b/"); +} - { - char path[FILE_MAX] = "//../"; - BLI_path_normalize("/a/b/c/", path); - EXPECT_STREQ("/a/b/", path); - } +#undef NORMALIZE_WITH_BASEDIR +#undef NORMALIZE + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_parent_dir + * \{ */ + +#define PARENT_DIR(input, output) \ + { \ + char path[FILE_MAX] = input; \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '/', '\\'); \ + } \ + BLI_path_parent_dir(path); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '\\', '/'); \ + } \ + EXPECT_STREQ(output, path); \ + } \ + ((void)0) + +TEST(path_util, ParentDir_Simple) +{ + PARENT_DIR("/a/b/", "/a/"); + PARENT_DIR("/a/b", "/a/"); + PARENT_DIR("/a", "/"); } -#endif + +TEST(path_util, ParentDir_NOP) +{ + PARENT_DIR("/", "/"); + PARENT_DIR("", ""); + PARENT_DIR(".", "."); + PARENT_DIR("./", "./"); + PARENT_DIR(".//", ".//"); + PARENT_DIR("./.", "./."); +} + +TEST(path_util, ParentDir_TrailingPeriod) +{ + /* Ensure trailing dots aren't confused with parent path. */ + PARENT_DIR("/.../.../.../", "/.../.../"); + PARENT_DIR("/.../.../...", "/.../.../"); + + PARENT_DIR("/a../b../c../", "/a../b../"); + PARENT_DIR("/a../b../c..", "/a../b../"); + + PARENT_DIR("/a./b./c./", "/a./b./"); + PARENT_DIR("/a./b./c.", "/a./b./"); +} + +TEST(path_util, ParentDir_Complex) +{ + PARENT_DIR("./a/", "./"); + PARENT_DIR("./a", "./"); + PARENT_DIR("../a/", "../"); + PARENT_DIR("../a", "../"); +} + +#undef PARENT_DIR + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_name_at_index + * \{ */ #define AT_INDEX(str_input, index_input, str_expect) \ { \ char path[] = str_input; \ + /* Test input assumes forward slash, support back-slash on WIN32. */ \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '/', '\\'); \ + } \ const char *expect = str_expect; \ int index_output, len_output; \ const bool ret = BLI_path_name_at_index(path, index_input, &index_output, &len_output); \ @@ -87,7 +184,6 @@ TEST(path_util, Clean) } \ ((void)0) -/* BLI_path_name_at_index */ TEST(path_util, NameAtIndex_Single) { AT_INDEX("/a", 0, "a"); @@ -166,21 +262,21 @@ TEST(path_util, NameAtIndex_MiscNeg) TEST(path_util, NameAtIndex_MiscComplex) { AT_INDEX("how//now/brown/cow", 0, "how"); - AT_INDEX("//how///now\\/brown/cow", 1, "now"); - AT_INDEX("/how/now\\//brown\\/cow", 2, "brown"); - AT_INDEX("/how/now/brown/cow//\\", 3, "cow"); - AT_INDEX("/how/now/brown/\\cow", 4, nullptr); - AT_INDEX("how/now/brown/\\cow\\", 4, nullptr); + AT_INDEX("//how///now//brown/cow", 1, "now"); + AT_INDEX("/how/now///brown//cow", 2, "brown"); + AT_INDEX("/how/now/brown/cow///", 3, "cow"); + AT_INDEX("/how/now/brown//cow", 4, nullptr); + AT_INDEX("how/now/brown//cow/", 4, nullptr); } TEST(path_util, NameAtIndex_MiscComplexNeg) { AT_INDEX("how//now/brown/cow", -4, "how"); - AT_INDEX("//how///now\\/brown/cow", -3, "now"); - AT_INDEX("/how/now\\//brown\\/cow", -2, "brown"); - AT_INDEX("/how/now/brown/cow//\\", -1, "cow"); - AT_INDEX("/how/now/brown/\\cow", -5, nullptr); - AT_INDEX("how/now/brown/\\cow\\", -5, nullptr); + AT_INDEX("//how///now//brown/cow", -3, "now"); + AT_INDEX("/how/now///brown//cow", -2, "brown"); + AT_INDEX("/how/now/brown/cow///", -1, "cow"); + AT_INDEX("/how/now/brown//cow", -5, nullptr); + AT_INDEX("how/now/brown//cow/", -5, nullptr); } TEST(path_util, NameAtIndex_NoneComplex) @@ -201,21 +297,59 @@ TEST(path_util, NameAtIndex_NoneComplexNeg) #undef AT_INDEX -#define JOIN(str_expect, out_size, ...) \ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_join + * \{ */ + +/* For systems with `/` path separator (non WIN32). */ +#define JOIN_FORWARD_SLASH(str_expect, out_size, ...) \ { \ const char *expect = str_expect; \ char result[(out_size) + 1024]; \ - /* check we don't write past the last byte */ \ + /* Check we don't write past the last byte. */ \ result[out_size] = '\0'; \ BLI_path_join(result, out_size, __VA_ARGS__); \ - /* simplify expected string */ \ + EXPECT_STREQ(result, expect); \ + EXPECT_EQ(result[out_size], '\0'); \ + } \ + ((void)0) + +/* For systems with `\` path separator (WIN32). + * Perform additional manipulation to behave as if input arguments used `\` separators. + * Needed since #BLI_path_join uses native slashes. */ +#define JOIN_BACK_SLASH(str_expect, out_size, ...) \ + { \ + const char *expect = str_expect; \ + char result[(out_size) + 1024]; \ + const char *input_forward_slash[] = {__VA_ARGS__}; \ + char *input_back_slash[ARRAY_SIZE(input_forward_slash)] = {nullptr}; \ + for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \ + input_back_slash[i] = strdup(input_forward_slash[i]); \ + BLI_str_replace_char(input_back_slash[i], '/', '\\'); \ + } \ + /* Check we don't write past the last byte. */ \ + result[out_size] = '\0'; \ + BLI_path_join_array(result, \ + out_size, \ + const_cast<const char **>(input_back_slash), \ + ARRAY_SIZE(input_back_slash)); \ BLI_str_replace_char(result, '\\', '/'); \ EXPECT_STREQ(result, expect); \ EXPECT_EQ(result[out_size], '\0'); \ + for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \ + free(input_back_slash[i]); \ + } \ } \ ((void)0) -/* BLI_path_join */ +#ifdef WIN32 +# define JOIN JOIN_BACK_SLASH +#else +# define JOIN JOIN_FORWARD_SLASH +#endif + TEST(path_util, JoinNop) { JOIN("", 100, ""); @@ -293,9 +427,9 @@ TEST(path_util, JoinTruncateLong) TEST(path_util, JoinComplex) { - JOIN("/a/b/c/d/e/f/g/", 100, "/", "\\a/b", "//////c/d", "", "e\\\\", "f", "g//"); - JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "\\aa/bb", "//////cc/dd", "", "ee\\\\", "ff", "gg//"); - JOIN("1/2/3/", 100, "1", "////////", "", "2", "3\\"); + JOIN("/a/b/c/d/e/f/g/", 100, "/", "a/b", "//////c/d", "", "e", "f", "g//"); + JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "aa/bb", "//////cc/dd", "", "ee", "ff", "gg//"); + JOIN("1/2/3/", 100, "1", "////////", "", "2", "3///"); } TEST(path_util, JoinRelativePrefix) @@ -306,8 +440,15 @@ TEST(path_util, JoinRelativePrefix) } #undef JOIN +#undef JOIN_BACK_SLASH +#undef JOIN_FORWARD_SLASH + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame + * \{ */ -/* BLI_path_frame */ TEST(path_util, Frame) { bool ret; @@ -384,7 +525,12 @@ TEST(path_util, Frame) } } -/* BLI_split_dirfile */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_split_dirfile + * \{ */ + TEST(path_util, SplitDirfile) { { @@ -440,6 +586,12 @@ TEST(path_util, SplitDirfile) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_strip + * \{ */ + #define PATH_FRAME_STRIP(input_path, expect_path, expect_ext) \ { \ char path[FILE_MAX]; \ @@ -451,7 +603,6 @@ TEST(path_util, SplitDirfile) } \ ((void)0) -/* BLI_path_frame_strip */ TEST(path_util, PathFrameStrip) { PATH_FRAME_STRIP("", "", ""); @@ -463,6 +614,12 @@ TEST(path_util, PathFrameStrip) } #undef PATH_FRAME_STRIP +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_extension_check + * \{ */ + #define PATH_EXTENSION_CHECK(input_path, input_ext, expect_ext) \ { \ const bool ret = BLI_path_extension_check(input_path, input_ext); \ @@ -475,7 +632,6 @@ TEST(path_util, PathFrameStrip) } \ ((void)0) -/* BLI_path_extension_check */ TEST(path_util, PathExtensionCheck) { PATH_EXTENSION_CHECK("a/b/c.exe", ".exe", ".exe"); @@ -501,6 +657,12 @@ TEST(path_util, PathExtensionCheck) } #undef PATH_EXTENSION_CHECK +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_check_chars + * \{ */ + #define PATH_FRAME_CHECK_CHARS(input_path, expect_hasChars) \ { \ const bool ret = BLI_path_frame_check_chars(input_path); \ @@ -513,7 +675,6 @@ TEST(path_util, PathExtensionCheck) } \ ((void)0) -/* BLI_path_frame_check_chars */ TEST(path_util, PathFrameCheckChars) { PATH_FRAME_CHECK_CHARS("a#", true); @@ -533,6 +694,12 @@ TEST(path_util, PathFrameCheckChars) } #undef PATH_FRAME_CHECK_CHARS +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_range + * \{ */ + #define PATH_FRAME_RANGE(input_path, sta, end, digits, expect_outpath) \ { \ char path[FILE_MAX]; \ @@ -549,7 +716,6 @@ TEST(path_util, PathFrameCheckChars) } \ ((void)0) -/* BLI_path_frame_range */ TEST(path_util, PathFrameRange) { int dummy = -1; @@ -565,6 +731,12 @@ TEST(path_util, PathFrameRange) } #undef PATH_FRAME_RANGE +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_frame_get + * \{ */ + #define PATH_FRAME_GET(input_path, expect_frame, expect_numdigits, expect_pathisvalid) \ { \ char path[FILE_MAX]; \ @@ -582,7 +754,6 @@ TEST(path_util, PathFrameRange) } \ ((void)0) -/* BLI_path_frame_get */ TEST(path_util, PathFrameGet) { PATH_FRAME_GET("001.avi", 1, 3, true); @@ -594,7 +765,12 @@ TEST(path_util, PathFrameGet) } #undef PATH_FRAME_GET -/* BLI_path_extension */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_extension + * \{ */ + TEST(path_util, PathExtension) { EXPECT_EQ(nullptr, BLI_path_extension("some.def/file")); @@ -608,62 +784,88 @@ TEST(path_util, PathExtension) EXPECT_STREQ(".001", BLI_path_extension("Text.001")); } -/* BLI_path_rel. */ -#ifndef _WIN32 +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_rel + * \{ */ -# define PATH_REL(abs_path, ref_path, rel_path) \ - { \ - char path[FILE_MAX]; \ - BLI_strncpy(path, abs_path, sizeof(path)); \ - BLI_path_rel(path, ref_path); \ - EXPECT_STREQ(rel_path, path); \ +#define PATH_REL(abs_path, ref_path, rel_path) \ + { \ + char path[FILE_MAX]; \ + const char *ref_path_test = ref_path; \ + BLI_strncpy(path, abs_path, sizeof(path)); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '/', '\\'); \ + ref_path_test = str_replace_char_strdup(ref_path_test, '/', '\\'); \ } \ - void(0) + BLI_path_rel(path, ref_path_test); \ + if (SEP == '\\') { \ + BLI_str_replace_char(path, '\\', '/'); \ + free((void *)ref_path_test); \ + } \ + EXPECT_STREQ(rel_path, path); \ + } \ + void(0) -TEST(path_util, PathRelPath) +#ifdef WIN32 +# define ABS_PREFIX "C:" +#else +# define ABS_PREFIX "" +#endif + +TEST(path_util, PathRelPath_Simple) { - PATH_REL("/foo/bar/blender.blend", "/foo/bar/", "//blender.blend"); - PATH_REL("/foo/bar/blender.blend", "/foo/bar", "//bar/blender.blend"); + PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar/", "//blender.blend"); +} - /* Check for potential buffer overflows. */ - { - char abs_path_in[FILE_MAX]; - abs_path_in[0] = '/'; - for (int i = 1; i < FILE_MAX - 1; i++) { - abs_path_in[i] = 'A'; - } - abs_path_in[FILE_MAX - 1] = '\0'; - char abs_path_out[FILE_MAX]; - abs_path_out[0] = '/'; - abs_path_out[1] = '/'; - for (int i = 2; i < FILE_MAX - 1; i++) { - abs_path_out[i] = 'A'; - } - abs_path_out[FILE_MAX - 1] = '\0'; - PATH_REL(abs_path_in, "/", abs_path_out); - - const char *ref_path_in = "/foo/bar/"; - const size_t ref_path_in_len = strlen(ref_path_in); - strcpy(abs_path_in, ref_path_in); - for (int i = ref_path_in_len; i < FILE_MAX - 1; i++) { - abs_path_in[i] = 'A'; - } - abs_path_in[FILE_MAX - 1] = '\0'; - abs_path_out[0] = '/'; - abs_path_out[1] = '/'; - for (int i = 2; i < FILE_MAX - (int(ref_path_in_len) - 1); i++) { - abs_path_out[i] = 'A'; - } - abs_path_out[FILE_MAX - (ref_path_in_len - 1)] = '\0'; - PATH_REL(abs_path_in, ref_path_in, abs_path_out); +TEST(path_util, PathRelPath_SimpleSubdir) +{ + PATH_REL(ABS_PREFIX "/foo/bar/blender.blend", ABS_PREFIX "/foo/bar", "//bar/blender.blend"); +} + +TEST(path_util, PathRelPath_BufferOverflowRoot) +{ + char abs_path_in[FILE_MAX]; + const char *abs_prefix = ABS_PREFIX "/"; + for (int i = STRNCPY_RLEN(abs_path_in, abs_prefix); i < FILE_MAX - 1; i++) { + abs_path_in[i] = 'A'; + } + abs_path_in[FILE_MAX - 1] = '\0'; + char abs_path_out[FILE_MAX]; + for (int i = STRNCPY_RLEN(abs_path_out, "//"); i < FILE_MAX - 1; i++) { + abs_path_out[i] = 'A'; + } + abs_path_out[FILE_MAX - std::max((strlen(abs_prefix) - 1), size_t(1))] = '\0'; + PATH_REL(abs_path_in, abs_prefix, abs_path_out); +} + +TEST(path_util, PathRelPath_BufferOverflowSubdir) +{ + char abs_path_in[FILE_MAX]; + const char *ref_path_in = ABS_PREFIX "/foo/bar/"; + const size_t ref_path_in_len = strlen(ref_path_in); + for (int i = STRNCPY_RLEN(abs_path_in, ref_path_in); i < FILE_MAX - 1; i++) { + abs_path_in[i] = 'A'; } + abs_path_in[FILE_MAX - 1] = '\0'; + char abs_path_out[FILE_MAX]; + for (int i = STRNCPY_RLEN(abs_path_out, "//"); i < FILE_MAX - (int(ref_path_in_len) - 1); i++) { + abs_path_out[i] = 'A'; + } + abs_path_out[FILE_MAX - std::max((ref_path_in_len - 1), size_t(1))] = '\0'; + PATH_REL(abs_path_in, ref_path_in, abs_path_out); } -# undef PATH_REL +#undef PATH_REL +#undef ABS_PREFIX -#endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tests for: #BLI_path_contains + * \{ */ -/* BLI_path_contains */ TEST(path_util, PathContains) { EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path")) << "A path contains itself"; @@ -692,4 +894,6 @@ TEST(path_util, PathContains_Windows_case_insensitive) EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "c:\\SOME\\path\\inside")) << "On Windows path comparison should ignore case"; } -#endif +#endif /* WIN32 */ + +/** \} */ diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc index 9bdf6075c70..d726fbccf20 100644 --- a/source/blender/blenlib/tests/BLI_string_test.cc +++ b/source/blender/blenlib/tests/BLI_string_test.cc @@ -515,6 +515,103 @@ TEST(string, StrFormatDecimalUnits) EXPECT_STREQ("-2.1B", size_str); } +/* BLI_str_format_integer_unit */ +TEST(string, StrFormatIntegerUnits) +{ + char size_str[7]; + int size; + + BLI_str_format_integer_unit(size_str, size = 0); + EXPECT_STREQ("0", size_str); + BLI_str_format_integer_unit(size_str, size = 1); + EXPECT_STREQ("1", size_str); + BLI_str_format_integer_unit(size_str, size = 10); + EXPECT_STREQ("10", size_str); + BLI_str_format_integer_unit(size_str, size = 15); + EXPECT_STREQ("15", size_str); + BLI_str_format_integer_unit(size_str, size = 100); + EXPECT_STREQ("100", size_str); + BLI_str_format_integer_unit(size_str, size = 155); + EXPECT_STREQ("155", size_str); + BLI_str_format_integer_unit(size_str, size = 1000); + EXPECT_STREQ("1K", size_str); + BLI_str_format_integer_unit(size_str, size = 1555); + EXPECT_STREQ("1K", size_str); + BLI_str_format_integer_unit(size_str, size = 10000); + EXPECT_STREQ("10K", size_str); + BLI_str_format_integer_unit(size_str, size = 15555); + EXPECT_STREQ("15K", size_str); + BLI_str_format_integer_unit(size_str, size = 100000); + EXPECT_STREQ(".1M", size_str); + BLI_str_format_integer_unit(size_str, size = 155555); + EXPECT_STREQ(".1M", size_str); + BLI_str_format_integer_unit(size_str, size = 1000000); + EXPECT_STREQ("1M", size_str); + BLI_str_format_integer_unit(size_str, size = 1555555); + EXPECT_STREQ("1M", size_str); + BLI_str_format_integer_unit(size_str, size = 2555555); + EXPECT_STREQ("2M", size_str); + BLI_str_format_integer_unit(size_str, size = 10000000); + EXPECT_STREQ("10M", size_str); + BLI_str_format_integer_unit(size_str, size = 15555555); + EXPECT_STREQ("15M", size_str); + BLI_str_format_integer_unit(size_str, size = 100000000); + EXPECT_STREQ(".1B", size_str); + BLI_str_format_integer_unit(size_str, size = 155555555); + EXPECT_STREQ(".1B", size_str); + BLI_str_format_integer_unit(size_str, size = 255555555); + EXPECT_STREQ(".2B", size_str); + BLI_str_format_integer_unit(size_str, size = 1000000000); + EXPECT_STREQ("1B", size_str); + + /* Largest possible value. */ + BLI_str_format_integer_unit(size_str, size = INT32_MAX); + EXPECT_STREQ("2B", size_str); + + BLI_str_format_integer_unit(size_str, size = -0); + EXPECT_STREQ("0", size_str); + BLI_str_format_integer_unit(size_str, size = -1); + EXPECT_STREQ("-1", size_str); + BLI_str_format_integer_unit(size_str, size = -10); + EXPECT_STREQ("-10", size_str); + BLI_str_format_integer_unit(size_str, size = -15); + EXPECT_STREQ("-15", size_str); + BLI_str_format_integer_unit(size_str, size = -100); + EXPECT_STREQ("-100", size_str); + BLI_str_format_integer_unit(size_str, size = -155); + EXPECT_STREQ("-155", size_str); + BLI_str_format_integer_unit(size_str, size = -1000); + EXPECT_STREQ("-1K", size_str); + BLI_str_format_integer_unit(size_str, size = -1555); + EXPECT_STREQ("-1K", size_str); + BLI_str_format_integer_unit(size_str, size = -10000); + EXPECT_STREQ("-10K", size_str); + BLI_str_format_integer_unit(size_str, size = -15555); + EXPECT_STREQ("-15K", size_str); + BLI_str_format_integer_unit(size_str, size = -100000); + EXPECT_STREQ("-.1M", size_str); + BLI_str_format_integer_unit(size_str, size = -155555); + EXPECT_STREQ("-.1M", size_str); + BLI_str_format_integer_unit(size_str, size = -1000000); + EXPECT_STREQ("-1M", size_str); + BLI_str_format_integer_unit(size_str, size = -1555555); + EXPECT_STREQ("-1M", size_str); + BLI_str_format_integer_unit(size_str, size = -10000000); + EXPECT_STREQ("-10M", size_str); + BLI_str_format_integer_unit(size_str, size = -15555555); + EXPECT_STREQ("-15M", size_str); + BLI_str_format_integer_unit(size_str, size = -100000000); + EXPECT_STREQ("-.1B", size_str); + BLI_str_format_integer_unit(size_str, size = -155555555); + EXPECT_STREQ("-.1B", size_str); + BLI_str_format_integer_unit(size_str, size = -1000000000); + EXPECT_STREQ("-1B", size_str); + + /* Smallest possible value. */ + BLI_str_format_integer_unit(size_str, size = -INT32_MAX); + EXPECT_STREQ("-2B", size_str); +} + struct WordInfo { WordInfo() = default; WordInfo(int start, int end) : start(start), end(end) diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index ec1768232c8..569798048f6 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -2143,7 +2143,7 @@ static void direct_link_id_common( BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag) { if (!BLO_read_data_is_undo(reader)) { - /* When actually reading a file, we do want to reset/re-generate session uuids. + /* When actually reading a file, we do want to reset/re-generate session UUIDS. * In undo case, we want to re-use existing ones. */ id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; } diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index e2b98b2283f..a2bd7fd2fd1 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -3630,6 +3630,29 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 304, 5)) { + /* Fix for T101622 - update flags of sequence editor regions that were not initialized + * properly. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + if (sl->spacetype == SPACE_SEQ) { + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_TOOLS) { + region->v2d.flag &= ~V2D_VIEWSYNC_AREA_VERTICAL; + } + if (region->regiontype == RGN_TYPE_CHANNELS) { + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; + } + } + } + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 8da28af3ca7..c45f9dbe49c 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -2058,7 +2058,7 @@ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int ns } else { BLI_assert(is_power_of_2_i(nseg) && nseg <= bp->pro_spacing.seg_2); - /* Find spacing between subsamples in prof_co_2. */ + /* Find spacing between sub-samples in `prof_co_2`. */ int subsample_spacing = bp->pro_spacing.seg_2 / nseg; copy_v3_v3(r_co, pro->prof_co_2 + 3 * i * subsample_spacing); } diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c index 14ec45f14b0..bdc36559e05 100644 --- a/source/blender/bmesh/tools/bmesh_wireframe.c +++ b/source/blender/bmesh/tools/bmesh_wireframe.c @@ -175,7 +175,7 @@ void BM_mesh_wireframe(BMesh *bm, BMVert **verts_neg = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__); BMVert **verts_pos = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__); - /* Will over-alloc, but makes for easy lookups by index to keep aligned. */ + /* Will over-allocate, but makes for easy lookups by index to keep aligned. */ BMVert **verts_boundary = use_boundary ? MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__) : NULL; diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h index 16d1e2e6bb5..ffd02ed5a2f 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.h +++ b/source/blender/compositor/operations/COM_ConvertOperation.h @@ -98,7 +98,7 @@ class ConvertVectorToValueOperation : public ConvertBaseOperation { class ConvertRGBToYCCOperation : public ConvertBaseOperation { private: - /** YCbCr mode (Jpeg, ITU601, ITU709) */ + /** YCbCr mode (JPEG, ITU601, ITU709) */ int mode_; public: @@ -116,7 +116,7 @@ class ConvertRGBToYCCOperation : public ConvertBaseOperation { class ConvertYCCToRGBOperation : public ConvertBaseOperation { private: - /** YCbCr mode (Jpeg, ITU601, ITU709) */ + /** YCbCr mode (JPEG, ITU601, ITU709) */ int mode_; public: diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index 90cbe0988ad..bab0b5385ec 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ./algorithms + algorithms ../../blenkernel ../../blenlib ../../gpu diff --git a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh index 9d0851eff84..f6d479f9bbe 100644 --- a/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh +++ b/source/blender/compositor/realtime_compositor/algorithms/COM_algorithm_parallel_reduction.hh @@ -27,6 +27,13 @@ float sum_blue(Context &context, GPUTexture *texture); * coefficients to compute the luminance. */ float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); +/* Computes the sum of the logarithm of the luminance of all pixels in the given texture, using the + * given luminance coefficients to compute the luminance. */ +float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the sum of the colors of all pixels in the given texture. */ +float4 sum_color(Context &context, GPUTexture *texture); + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -55,4 +62,42 @@ float sum_luminance_squared_difference(Context &context, float3 luminance_coefficients, float subtrahend); +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +/* Computes the maximum luminance of all pixels in the given texture, using the given luminance + * coefficients to compute the luminance. */ +float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the maximum float of all pixels in the given float texture, limited to the given range. + * Values outside of the given range are ignored. If non of the pixel values are in the range, the + * lower bound of the range is returned. For instance, if the given range is [-10, 10] and the + * image contains the values {2, 5, 11}, the maximum will be 5, since 11 is outside of the range. + * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite + * values, so enforcing an upper bound is beneficial. */ +float maximum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound); + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +/* Computes the minimum luminance of all pixels in the given texture, using the given luminance + * coefficients to compute the luminance. */ +float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients); + +/* Computes the minimum float of all pixels in the given float texture, limited to the given range. + * Values outside of the given range are ignored. If non of the pixel values are in the range, the + * upper bound of the range is returned. For instance, if the given range is [-10, 10] and the + * image contains the values {-11, 2, 5}, the minimum will be 2, since -11 is outside of the range. + * This is particularly useful for Z Depth normalization, since Z Depth can contain near infinite + * values, so enforcing a lower bound is beneficial. */ +float minimum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound); + } // namespace blender::realtime_compositor diff --git a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc index 3266ccd14eb..9672431992d 100644 --- a/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc +++ b/source/blender/compositor/realtime_compositor/algorithms/intern/algorithm_parallel_reduction.cc @@ -134,6 +134,34 @@ float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coef return sum; } +float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_log_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float sum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + +float4 sum_color(Context &context, GPUTexture *texture) +{ + GPUShader *shader = context.shader_manager().get("compositor_sum_color"); + GPU_shader_bind(shader); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_RGBA32F); + const float4 sum = float4(reduced_value); + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return sum; +} + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -202,4 +230,80 @@ float sum_luminance_squared_difference(Context &context, return sum; } +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_maximum_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float maximum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return maximum; +} + +float maximum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound) +{ + GPUShader *shader = context.shader_manager().get("compositor_maximum_float_in_range"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "lower_bound", lower_bound); + GPU_shader_uniform_1f(shader, "upper_bound", upper_bound); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float maximum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return maximum; +} + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients) +{ + GPUShader *shader = context.shader_manager().get("compositor_minimum_luminance"); + GPU_shader_bind(shader); + + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float minimum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return minimum; +} + +float minimum_float_in_range(Context &context, + GPUTexture *texture, + float lower_bound, + float upper_bound) +{ + GPUShader *shader = context.shader_manager().get("compositor_minimum_float_in_range"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "lower_bound", lower_bound); + GPU_shader_uniform_1f(shader, "upper_bound", upper_bound); + + float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F); + const float minimum = *reduced_value; + MEM_freeN(reduced_value); + GPU_shader_unbind(); + + return minimum; +} + } // namespace blender::realtime_compositor diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index f95c0700a47..c84852788fd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -453,6 +453,11 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD if (id == nullptr) { return IDWALK_RET_NOP; } + if (!ID_TYPE_IS_COW(GS(id->name))) { + /* No need to go further if the id never had a cow copy in the depsgraph. This function is + * only concerned with keeping the mapping between original and COW ids intact. */ + return IDWALK_RET_NOP; + } DepsgraphNodeBuilder *builder = static_cast<DepsgraphNodeBuilder *>(cb_data->user_data); ID *id_cow_self = cb_data->id_self; diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 4636011e18b..11998860ef3 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -191,8 +191,8 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data) bool is_neg_scale = is_negative_m4(dob->mat); SET_FLAG_FROM_TEST(data->temp_dupli_object.transflag, is_neg_scale, OB_NEG_SCALE); - copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); - invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.obmat); + copy_m4_m4(data->temp_dupli_object.object_to_world, dob->mat); + invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.object_to_world); data->next_object = &data->temp_dupli_object; BLI_assert(deg::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id)); return true; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index a5b29ae56a9..62a9158928d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -284,7 +284,7 @@ void invalidate_tagged_evaluated_transform(ID *id) switch (id_type) { case ID_OB: { Object *object = (Object *)id; - copy_vn_fl((float *)object->obmat, 16, NAN); + copy_vn_fl((float *)object->object_to_world, 16, NAN); break; } default: diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index a645bd6b6af..4010b491141 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -71,7 +71,7 @@ set(SRC intern/draw_attributes.cc intern/draw_cache_impl_curve.cc intern/draw_cache_impl_curves.cc - intern/draw_cache_impl_gpencil.c + intern/draw_cache_impl_gpencil.cc intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.cc intern/draw_cache_impl_particles.c @@ -95,6 +95,7 @@ set(SRC intern/draw_manager_text.cc intern/draw_manager_texture.c intern/draw_pbvh.cc + intern/draw_pointcloud.cc intern/draw_select_buffer.c intern/draw_shader.cc intern/draw_texture_pool.cc diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index eee6a5a7cb5..05e62764bb1 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -182,7 +182,7 @@ static void basic_cache_populate(void *vedata, Object *ob) } } - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 942ab5502c7..eb111610706 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -403,7 +403,7 @@ static bool eevee_lightprobes_culling_test(Object *ob) const float max[3] = {1.0f, 1.0f, 1.0f}; BKE_boundbox_init_from_minmax(&bbox, min, max); - copy_m4_m4(tmp, ob->obmat); + copy_m4_m4(tmp, ob->object_to_world); normalize_v3(tmp[2]); mul_v3_fl(tmp[2], probe->distinf); @@ -445,7 +445,7 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata /* Debug Display */ DRWCallBuffer *grp = vedata->stl->g_data->planar_display_shgrp; if (grp && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { - DRW_buffer_add_entry(grp, &pinfo->num_planar, ob->obmat); + DRW_buffer_add_entry(grp, &pinfo->num_planar, ob->object_to_world); } pinfo->num_planar++; @@ -488,30 +488,30 @@ void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *egrid, mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f); /* Matrix converting world space to cell ranges. */ - invert_m4_m4(egrid->mat, ob->obmat); + invert_m4_m4(egrid->mat, ob->object_to_world); /* First cell. */ copy_v3_fl(egrid->corner, -1.0f); add_v3_v3(egrid->corner, half_cell_dim); - mul_m4_v3(ob->obmat, egrid->corner); + mul_m4_v3(ob->object_to_world, egrid->corner); /* Opposite neighbor cell. */ copy_v3_fl3(egrid->increment_x, cell_dim[0], 0.0f, 0.0f); add_v3_v3(egrid->increment_x, half_cell_dim); add_v3_fl(egrid->increment_x, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_x); + mul_m4_v3(ob->object_to_world, egrid->increment_x); sub_v3_v3(egrid->increment_x, egrid->corner); copy_v3_fl3(egrid->increment_y, 0.0f, cell_dim[1], 0.0f); add_v3_v3(egrid->increment_y, half_cell_dim); add_v3_fl(egrid->increment_y, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_y); + mul_m4_v3(ob->object_to_world, egrid->increment_y); sub_v3_v3(egrid->increment_y, egrid->corner); copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, cell_dim[2]); add_v3_v3(egrid->increment_z, half_cell_dim); add_v3_fl(egrid->increment_z, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_z); + mul_m4_v3(ob->object_to_world, egrid->increment_z); sub_v3_v3(egrid->increment_z, egrid->corner); /* Visibility bias */ @@ -527,7 +527,7 @@ void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprob LightProbe *probe = (LightProbe *)ob->data; /* Update transforms */ - copy_v3_v3(eprobe->position, ob->obmat[3]); + copy_v3_v3(eprobe->position, ob->object_to_world[3]); /* Attenuation */ eprobe->attenuation_type = probe->attenuation_type; @@ -535,7 +535,7 @@ void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprob unit_m4(eprobe->attenuationmat); scale_m4_fl(eprobe->attenuationmat, probe->distinf); - mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat); + mul_m4_m4m4(eprobe->attenuationmat, ob->object_to_world, eprobe->attenuationmat); invert_m4(eprobe->attenuationmat); /* Parallax */ @@ -550,7 +550,7 @@ void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprob scale_m4_fl(eprobe->parallaxmat, probe->distinf); } - mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat); + mul_m4_m4m4(eprobe->parallaxmat, ob->object_to_world, eprobe->parallaxmat); invert_m4(eprobe->parallaxmat); } @@ -566,8 +566,8 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob, vis_test->cached = false; /* Computing mtx : matrix that mirror position around object's XY plane. */ - normalize_m4_m4(normat, ob->obmat); /* object > world */ - invert_m4_m4(imat, normat); /* world > object */ + normalize_m4_m4(normat, ob->object_to_world); /* object > world */ + invert_m4_m4(imat, normat); /* world > object */ /* XY reflection plane */ imat[0][2] = -imat[0][2]; imat[1][2] = -imat[1][2]; @@ -576,38 +576,38 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob, mul_m4_m4m4(eplanar->mtx, normat, imat); /* world > object > mirrored obj > world */ /* Compute clip plane equation / normal. */ - copy_v3_v3(eplanar->plane_equation, ob->obmat[2]); + copy_v3_v3(eplanar->plane_equation, ob->object_to_world[2]); normalize_v3(eplanar->plane_equation); /* plane normal */ - eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->obmat[3]); + eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->object_to_world[3]); eplanar->clipsta = probe->clipsta; /* Compute XY clip planes. */ - normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]); - normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]); + normalize_v3_v3(eplanar->clip_vec_x, ob->object_to_world[0]); + normalize_v3_v3(eplanar->clip_vec_y, ob->object_to_world[1]); float vec[3] = {0.0f, 0.0f, 0.0f}; vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec); vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec); vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec); vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + mul_m4_v3(ob->object_to_world, vec); /* Point on the edge */ eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec); /* Facing factors */ diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 312305a31f7..f8250f9520d 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -132,7 +132,7 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) const float light_threshold = draw_ctx->scene->eevee.light_threshold; /* Position */ - copy_v3_v3(evli->position, ob->obmat[3]); + copy_v3_v3(evli->position, ob->object_to_world[3]); /* Color */ copy_v3_v3(evli->color, &la->r); @@ -153,7 +153,7 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) evli->invsqrdist_volume = 1.0f / max_ff(1e-4f, square_f(att_radius_volume)); /* Vectors */ - normalize_m4_m4_ex(mat, ob->obmat, scale); + normalize_m4_m4_ex(mat, ob->object_to_world, scale); copy_v3_v3(evli->forwardvec, mat[2]); normalize_v3(evli->forwardvec); negate_v3(evli->forwardvec); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index b5f81f3a307..b134d7f6dc6 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -810,7 +810,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); if (ob->sculpt && ob->sculpt->pbvh) { @@ -924,17 +924,14 @@ void EEVEE_particle_hair_cache_populate(EEVEE_Data *vedata, if (matcache.depth_grp) { *matcache.depth_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.depth_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat); } if (matcache.shading_grp) { *matcache.shading_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.shading_grp, matcache.shading_gpumat); - DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat); } if (matcache.shadow_grp) { *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub( ob, psys, md, matcache.shadow_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat); *cast_shadow = true; } @@ -954,16 +951,13 @@ void EEVEE_object_curves_cache_populate(EEVEE_Data *vedata, if (matcache.depth_grp) { *matcache.depth_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.depth_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat); } if (matcache.shading_grp) { *matcache.shading_grp_p = DRW_shgroup_curves_create_sub( ob, matcache.shading_grp, matcache.shading_gpumat); - DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat); } if (matcache.shadow_grp) { *matcache.shadow_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.shadow_grp, NULL); - DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat); *cast_shadow = true; } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index a3ca19c88e1..9f7fb1c154c 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -292,7 +292,7 @@ void EEVEE_motion_blur_curves_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata) int mb_step = effects->motion_blur_step; /* Store transform. */ - copy_m4_m4(mb_data->obmat[mb_step], ob->obmat); + copy_m4_m4(mb_data->obmat[mb_step], ob->object_to_world); EEVEE_HairMotionData *mb_curves = EEVEE_motion_blur_curves_data_get(mb_data); @@ -362,7 +362,7 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), if (mb_data) { int mb_step = effects->motion_blur_step; /* Store transform. */ - copy_m4_m4(mb_data->obmat[mb_step], ob->obmat); + copy_m4_m4(mb_data->obmat[mb_step], ob->object_to_world); EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get(mb_data); diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 9e571b1d15b..1cf3c7c6da1 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -153,7 +153,7 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) for (int i = 0; i < 8; i++) { float vec[3]; copy_v3_v3(vec, bb->vec[i]); - mul_m4_v3(ob->obmat, vec); + mul_m4_v3(ob->object_to_world, vec); minmax_v3v3_v3(min, max, vec); } diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 05b2bafdb3a..872696a8b7c 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -299,7 +299,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, } float size[3]; - mat4_to_size(size, ob->obmat); + mat4_to_size(size, ob->object_to_world); /* Check if any of the axes have 0 length. (see T69070) */ const float epsilon = 1e-8f; if ((size[0] < epsilon) || (size[1] < epsilon) || (size[2] < epsilon)) { diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl index 90272400915..5af317b7398 100644 --- a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl @@ -96,7 +96,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) /* Mix all colors to get the corner color. */ vec4 col3 = (col + col1 + col2) / 3.0; - vec2 mix_fac = uv_border * 0.5; + vec2 mix_fac = saturate(uv_border * 0.5); return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y); } else if (any(border)) { @@ -108,7 +108,7 @@ vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) uv = cubemap_face_coord(cubevec.xyz, face); coord = vec3(uv, cubevec.w * 6.0 + face); - float mix_fac = max(uv_border.x, uv_border.y) * 0.5; + float mix_fac = saturate(max(uv_border.x, uv_border.y) * 0.5); return mix(col, textureLod(tex, coord, lod), mix_fac); } else { diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl index 51a351babd3..5f04cdcebfa 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl @@ -95,7 +95,11 @@ void main() weights = dof_layer_weight(cocs) * dof_sample_weight(cocs); /* Filter NaNs. */ - weights = select(weights, vec4(0.0), equal(cocs, vec4(0.0))); + for (int i = 0; i < 4; i++) { + if (isnan(weights[i]) || isinf(weights[i])) { + weights[i] = 0.0; + } + } color1 = colors[0] * weights[0]; color2 = colors[1] * weights[1]; diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index 062a40f35c2..ccf6d6e2042 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -30,7 +30,7 @@ void main() vec3 world_pos = pos; #elif defined(POINTCLOUD_SHADER) pointcloud_get_pos_and_radius(pointPosition, pointRadius); - pointID = gl_VertexID; + pointID = pointcloud_get_point_id(); #else vec3 world_pos = point_object_to_world(pos); #endif diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl index 8f49c7bd265..7a22b2c53d7 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl @@ -37,7 +37,7 @@ void main() vec3 world_pos = pos; #elif defined(POINTCLOUD_SHADER) pointcloud_get_pos_and_radius(pointPosition, pointRadius); - pointID = gl_VertexID; + pointID = pointcloud_get_point_id(); #else vec3 world_pos = point_object_to_world(pos); #endif diff --git a/source/blender/draw/engines/eevee_next/eevee_light.cc b/source/blender/draw/engines/eevee_next/eevee_light.cc index 8a5de15229d..aa8268dbaa7 100644 --- a/source/blender/draw/engines/eevee_next/eevee_light.cc +++ b/source/blender/draw/engines/eevee_next/eevee_light.cc @@ -58,7 +58,7 @@ void Light::sync(/* ShadowModule &shadows , */ const Object *ob, float threshold this->influence_radius_invsqr_volume = 1.0f / square_f(max_ff(influence_radius_volume, 1e-8f)); this->color = float3(&la->r) * la->energy; - normalize_m4_m4_ex(this->object_mat.ptr(), ob->obmat, scale); + normalize_m4_m4_ex(this->object_mat.ptr(), ob->object_to_world, scale); /* Make sure we have consistent handedness (in case of negatively scaled Z axis). */ float3 cross = math::cross(float3(this->_right), float3(this->_up)); if (math::dot(cross, float3(this->_back)) < 0.0f) { diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index e6b37b4ad47..0242f732f27 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -182,7 +182,7 @@ PassMain::Sub *ForwardPipeline::prepass_transparent_add(const Object *ob, if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) { state |= DRW_STATE_CULL_BACK; } - float sorting_value = math::dot(float3(ob->obmat[3]), camera_forward_); + float sorting_value = math::dot(float3(ob->object_to_world[3]), camera_forward_); PassMain::Sub *pass = &transparent_ps_.sub(GPU_material_get_name(gpumat), sorting_value); pass->state_set(state); pass->material_set(*inst_.manager, gpumat); @@ -197,7 +197,7 @@ PassMain::Sub *ForwardPipeline::material_transparent_add(const Object *ob, if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) { state |= DRW_STATE_CULL_BACK; } - float sorting_value = math::dot(float3(ob->obmat[3]), camera_forward_); + float sorting_value = math::dot(float3(ob->object_to_world[3]), camera_forward_); PassMain::Sub *pass = &transparent_ps_.sub(GPU_material_get_name(gpumat), sorting_value); pass->state_set(state); pass->material_set(*inst_.manager, gpumat); diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index 08cda6f47cf..cbd735ec29c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -248,17 +248,17 @@ static void gpencil_stroke_sync(bGPDlayer * /*gpl*/, return; } + GPUBatch *geom = DRW_cache_gpencil_get(iter.ob, iter.cfra); + if (show_fill) { - GPUBatch *geom = DRW_cache_gpencil_fills_get(iter.ob, iter.cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; gpencil_drawcall_add(iter, geom, material, vfirst, vcount, false); } if (show_stroke) { - GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter.ob, iter.cfra); /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; + int vfirst = gps->runtime.stroke_start * 3; /* Include "potential" cyclic vertex and start adj vertex (see shader). */ int vcount = gps->totpoints + 1 + 1; gpencil_drawcall_add(iter, geom, material, vfirst, vcount, true); diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc index b9a78e8547e..52401c8003e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc @@ -106,16 +106,16 @@ bool VelocityModule::step_object_sync(Object *ob, vel.obj.ofs[step_] = object_steps_usage[step_]++; vel.obj.resource_id = resource_handle.resource_index(); vel.id = (ID *)ob->data; - object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->obmat; + object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->object_to_world; if (step_ == STEP_CURRENT) { /* Replace invalid steps. Can happen if object was hidden in one of those steps. */ if (vel.obj.ofs[STEP_PREVIOUS] == -1) { vel.obj.ofs[STEP_PREVIOUS] = object_steps_usage[STEP_PREVIOUS]++; - object_steps[STEP_PREVIOUS]->get_or_resize(vel.obj.ofs[STEP_PREVIOUS]) = ob->obmat; + object_steps[STEP_PREVIOUS]->get_or_resize(vel.obj.ofs[STEP_PREVIOUS]) = ob->object_to_world; } if (vel.obj.ofs[STEP_NEXT] == -1) { vel.obj.ofs[STEP_NEXT] = object_steps_usage[STEP_NEXT]++; - object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->obmat; + object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->object_to_world; } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl index 38debf14eda..87a5bf71c45 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl @@ -16,30 +16,18 @@ void main() float hardness; vec2 thickness; - gl_Position = gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - /* TODO */ - vec4(1024.0, 1024.0, 1.0 / 1024.0, 1.0 / 1024.0), - interp.P, - interp.N, - g_color, - strength, - g_uvs, - sspos, - aspect, - thickness, - hardness); + gl_Position = gpencil_vertex( + /* TODO */ + vec4(1024.0, 1024.0, 1.0 / 1024.0, 1.0 / 1024.0), + interp.P, + interp.N, + g_color, + strength, + g_uvs, + sspos, + aspect, + thickness, + hardness); #ifdef MAT_VELOCITY /* GPencil do not support deformation motion blur. */ vec3 lP_curr = transform_point(ModelMatrixInverse, interp.P); diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index a41918e7e0d..06bf531cded 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -39,9 +39,9 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) tgp_ob->layers.first = tgp_ob->layers.last = NULL; tgp_ob->vfx.first = tgp_ob->vfx.last = NULL; - tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->obmat[3]); + tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->object_to_world[3]); tgp_ob->is_drawmode3d = (gpd->draw_mode == GP_DRAWMODE_3D) || pd->draw_depth_only; - tgp_ob->object_scale = mat4_to_scale(ob->obmat); + tgp_ob->object_scale = mat4_to_scale(ob->object_to_world); /* Check if any material with holdout flag enabled. */ tgp_ob->do_mat_holdout = false; @@ -71,7 +71,7 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) add_v3_fl(size, 1e-8f); rescale_m4(mat, size); /* BBox space to World. */ - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); if (DRW_view_is_persp_get(NULL)) { /* BBox center to camera vector. */ sub_v3_v3v3(tgp_ob->plane_normal, pd->camera_pos, mat[3]); @@ -96,9 +96,9 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) unit_m4(tgp_ob->plane_mat); copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal); orthogonalize_m4(tgp_ob->plane_mat, 2); - mul_mat3_m4_v3(ob->obmat, size); + mul_mat3_m4_v3(ob->object_to_world, size); float radius = len_v3(size); - mul_m4_v3(ob->obmat, center); + mul_m4_v3(ob->object_to_world, center); rescale_m4(tgp_ob->plane_mat, (float[3]){radius, radius, radius}); copy_v3_v3(tgp_ob->plane_mat[3], center); diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index e54ac99a888..07b72c97875 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -387,20 +387,20 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob) } else if (la->type == LA_AREA) { /* Simulate area lights using a spot light. */ - normalize_m4_m4(mat, ob->obmat); + normalize_m4_m4(mat, ob->object_to_world); invert_m4(mat); gp_light->type = GP_LIGHT_TYPE_SPOT; gp_light->spot_size = cosf(M_PI_2); gp_light->spot_blend = (1.0f - gp_light->spot_size) * 1.0f; } else if (la->type == LA_SUN) { - normalize_v3_v3(gp_light->forward, ob->obmat[2]); + normalize_v3_v3(gp_light->forward, ob->object_to_world[2]); gp_light->type = GP_LIGHT_TYPE_SUN; } else { gp_light->type = GP_LIGHT_TYPE_POINT; } - copy_v4_v4(gp_light->position, ob->obmat[3]); + copy_v4_v4(gp_light->position, ob->object_to_world[3]); copy_v3_v3(gp_light->color, &la->r); mul_v3_fl(gp_light->color, la->energy * light_power_get(la)); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index b24e4c605e4..78e658d35eb 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -342,7 +342,6 @@ typedef struct gpIterPopulateData { int stroke_index_offset; /* Infos for call batching. */ struct GPUBatch *geom; - bool instancing; int vfirst, vcount; } gpIterPopulateData; @@ -352,12 +351,7 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) { #if !DISABLE_BATCHING if (iter->geom != NULL) { - if (iter->instancing) { - DRW_shgroup_call_instance_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); - } - else { - DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); - } + DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); } #endif @@ -367,25 +361,22 @@ static void gpencil_drawcall_flush(gpIterPopulateData *iter) } /* Group draw-calls that are consecutive and with the same type. Reduces GPU driver overhead. */ -static void gpencil_drawcall_add( - gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count) +static void gpencil_drawcall_add(gpIterPopulateData *iter, + struct GPUBatch *geom, + int v_first, + int v_count) { #if DISABLE_BATCHING - if (instancing) { - DRW_shgroup_call_instance_range(iter->grp, iter->ob, geom, v_first, v_count); - } - else { - DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count); - } + DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count); + return; #endif int last = iter->vfirst + iter->vcount; /* Interrupt draw-call grouping if the sequence is not consecutive. */ - if ((geom != iter->geom) || (v_first - last > 3)) { + if ((geom != iter->geom) || (v_first - last > 0)) { gpencil_drawcall_flush(iter); } iter->geom = geom; - iter->instancing = instancing; if (iter->vfirst == -1) { iter->vfirst = v_first; } @@ -516,22 +507,33 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW); + GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_get(iter->ob, show_fill) : + DRW_cache_gpencil_get(iter->ob, iter->pd->cfra); + if (geom != iter->geom) { + gpencil_drawcall_flush(iter); + + GPUVertBuf *position_tx = do_sbuffer ? + DRW_cache_gpencil_sbuffer_position_buffer_get(iter->ob, + show_fill) : + DRW_cache_gpencil_position_buffer_get(iter->ob, iter->pd->cfra); + GPUVertBuf *color_tx = do_sbuffer ? + DRW_cache_gpencil_sbuffer_color_buffer_get(iter->ob, show_fill) : + DRW_cache_gpencil_color_buffer_get(iter->ob, iter->pd->cfra); + DRW_shgroup_buffer_texture(iter->grp, "gp_pos_tx", position_tx); + DRW_shgroup_buffer_texture(iter->grp, "gp_col_tx", color_tx); + } + if (show_fill) { - GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_fill_get(iter->ob) : - DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; - gpencil_drawcall_add(iter, geom, false, vfirst, vcount); + gpencil_drawcall_add(iter, geom, vfirst, vcount); } if (show_stroke) { - GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_stroke_get(iter->ob) : - DRW_cache_gpencil_strokes_get(iter->ob, iter->pd->cfra); - /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; - /* Include "potential" cyclic vertex and start adj vertex (see shader). */ - int vcount = gps->totpoints + 1 + 1; - gpencil_drawcall_add(iter, geom, true, vfirst, vcount); + int vfirst = gps->runtime.stroke_start * 3; + bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2); + int vcount = (gps->totpoints + (int)is_cyclic) * 2 * 3; + gpencil_drawcall_add(iter, geom, vfirst, vcount); } iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1; diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index a7d8570dbaa..9b1129e77be 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -96,7 +96,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it float winmat[4][4], persmat[4][4]; float blur_size[2] = {fx->radius[0], fx->radius[1]}; DRW_view_persmat_get(NULL, persmat, false); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); if (fx->flag & FX_BLUR_DOF_MODE) { /* Compute circle of confusion size. */ @@ -108,7 +108,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it DRW_view_winmat_get(NULL, winmat, false); const float *vp_size = DRW_viewport_size_get(); float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w; mul_v2_fl(blur_size, distance_factor); } @@ -175,11 +175,11 @@ static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter const float *vp_size = DRW_viewport_size_get(); const float *vp_size_inv = DRW_viewport_invert_size_get(); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(offset, distance_factor); mul_v2_v2(offset, vp_size_inv); @@ -248,8 +248,8 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat mul_v2_v2(pixel_size, vp_size_inv); /* Fixed pixelisation center from object center. */ - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - mul_v3_m4v3(ob_center, persmat, ob->obmat[3]); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); + mul_v3_m4v3(ob_center, persmat, ob->object_to_world[3]); mul_v3_fl(ob_center, 1.0f / w); const bool use_antialiasing = ((fx->flag & FX_PIXEL_FILTER_NEAREST) == 0); @@ -260,7 +260,7 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); mul_v2_fl(pixel_size, (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w); /* Center to texel */ @@ -310,7 +310,9 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData const float *vp_size_inv = DRW_viewport_invert_size_get(); const float ratio = vp_size_inv[1] / vp_size_inv[0]; - copy_v3_v3(rot_center, (use_obj_pivot && fx->object) ? fx->object->obmat[3] : ob->obmat[3]); + copy_v3_v3(rot_center, + (use_obj_pivot && fx->object) ? fx->object->object_to_world[3] : + ob->object_to_world[3]); const float w = fabsf(mul_project_m4_v3_zfac(persmat, rot_center)); mul_v3_m4v3(rot_center, persmat, rot_center); @@ -318,7 +320,7 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(offset, distance_factor); mul_v2_v2(offset, vp_size_inv); @@ -485,13 +487,13 @@ static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *it const float *vp_size = DRW_viewport_size_get(); const float *vp_size_inv = DRW_viewport_invert_size_get(); - const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - mul_v3_m4v3(wave_center, persmat, ob->obmat[3]); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->object_to_world[3])); + mul_v3_m4v3(wave_center, persmat, ob->object_to_world[3]); mul_v3_fl(wave_center, 1.0f / w); /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(ob->obmat); + float scale = mat4_to_scale(ob->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; wave_center[0] = wave_center[0] * 0.5f + 0.5f; @@ -542,7 +544,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterV DRW_view_persmat_get(NULL, persmat, false); const float *vp_size = DRW_viewport_size_get(); - copy_v3_v3(swirl_center, fx->object->obmat[3]); + copy_v3_v3(swirl_center, fx->object->object_to_world[3]); const float w = fabsf(mul_project_m4_v3_zfac(persmat, swirl_center)); mul_v3_m4v3(swirl_center, persmat, swirl_center); @@ -550,7 +552,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterV /* Modify by distance to camera and object scale. */ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; - float scale = mat4_to_scale(fx->object->obmat); + float scale = mat4_to_scale(fx->object->object_to_world); float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; mul_v2_fl(swirl_center, 0.5f); diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h index 4c621e955b9..3f0f73e7c13 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h +++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h @@ -41,6 +41,9 @@ enum gpLightType { GP_LIGHT_TYPE_AMBIENT = 3u, }; +#define GP_IS_STROKE_VERTEX_BIT (1 << 30) +#define GP_VERTEX_ID_SHIFT 2 + /* Avoid compiler funkiness with enum types not being strongly typed in C. */ #ifndef GPU_SHADER # define gpMaterialFlag uint diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index 7ddfdc5f65c..642939136c8 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -1,92 +1,4 @@ -/* Must match C declaration. */ -struct gpMaterial { - vec4 stroke_color; - vec4 fill_color; - vec4 fill_mix_color; - vec4 fill_uv_rot_scale; - vec4 fill_uv_offset; - /* Put float/int at the end to avoid padding error */ - /* Some drivers are completely messing the alignment or the fetches here. - * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */ - vec4 gp_mat_packed_1; - // float stroke_texture_mix; - // float stroke_u_scale; - // float fill_texture_mix; - // int gp_flag; - /* Please ensure 16 byte alignment (multiple of vec4). */ -}; - -#define MATERIAL(m) materials[m + gpMaterialOffset] - -#define stroke_texture_mix gp_mat_packed_1.x -#define stroke_u_scale gp_mat_packed_1.y -#define fill_texture_mix gp_mat_packed_1.z -#define GP_FLAG(m) floatBitsToInt(MATERIAL(m).gp_mat_packed_1.w) - -/* flag */ -#define GP_STROKE_ALIGNMENT_STROKE 1 -#define GP_STROKE_ALIGNMENT_OBJECT 2 -#define GP_STROKE_ALIGNMENT_FIXED 3 -#define GP_STROKE_ALIGNMENT 0x3 -#define GP_STROKE_OVERLAP (1 << 2) -#define GP_STROKE_TEXTURE_USE (1 << 3) -#define GP_STROKE_TEXTURE_STENCIL (1 << 4) -#define GP_STROKE_TEXTURE_PREMUL (1 << 5) -#define GP_STROKE_DOTS (1 << 6) -#define GP_STROKE_HOLDOUT (1 << 7) -#define GP_FILL_HOLDOUT (1 << 8) -#define GP_FILL_TEXTURE_USE (1 << 10) -#define GP_FILL_TEXTURE_PREMUL (1 << 11) -#define GP_FILL_TEXTURE_CLIP (1 << 12) -#define GP_FILL_GRADIENT_USE (1 << 13) -#define GP_FILL_GRADIENT_RADIAL (1 << 14) -/* High bits are used to pass material ID to fragment shader. */ -#define GP_MATID_SHIFT 16 - -/* Multiline defines can crash blender with certain GPU drivers. */ -/* clang-format off */ -#define GP_FILL_FLAGS (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP | GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL | GP_FILL_HOLDOUT) -/* clang-format on */ - -#define GP_FLAG_TEST(flag, val) (((flag) & (val)) != 0) - -/* Must match C declaration. */ -struct gpLight { - vec4 color_type; - vec4 right; - vec4 up; - vec4 forward; - vec4 position; - /* Please ensure 16 byte alignment (multiple of vec4). */ -}; - -#define spot_size right.w -#define spot_blend up.w - -#define GP_LIGHT_TYPE_POINT 0.0 -#define GP_LIGHT_TYPE_SPOT 1.0 -#define GP_LIGHT_TYPE_SUN 2.0 -#define GP_LIGHT_TYPE_AMBIENT 3.0 - -#ifdef GP_MATERIAL_BUFFER_LEN - -layout(std140) uniform gpMaterialBlock -{ - gpMaterial materials[GP_MATERIAL_BUFFER_LEN]; -}; - -#endif - -#ifdef GPENCIL_LIGHT_BUFFER_LEN - -layout(std140) uniform gpLightBlock -{ - gpLight lights[GPENCIL_LIGHT_BUFFER_LEN]; -}; - -#endif - /* Must match eGPLayerBlendModes */ #define MODE_REGULAR 0 #define MODE_HARDLIGHT 1 @@ -149,510 +61,3 @@ void blend_mode_output( break; } } - -#ifndef USE_GPU_SHADER_CREATE_INFO - -IN_OUT ShaderStageInterface -{ - vec4 finalColorMul; - vec4 finalColorAdd; - vec3 finalPos; - vec2 finalUvs; - noperspective float strokeThickness; - noperspective float unclampedThickness; - noperspective float strokeHardeness; - flat vec2 strokeAspect; - flat vec2 strokePt1; - flat vec2 strokePt2; - flat int matFlag; - flat float depth; -}; - -#endif - -#ifdef GPU_FRAGMENT_SHADER - -# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0)) - -float stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac) -{ - /* We create our own uv space to avoid issues with triangulation and linear - * interpolation artifacts. */ - vec2 line = p2.xy - p1.xy; - vec2 pos = gl_FragCoord.xy - p1.xy; - float line_len = length(line); - float half_line_len = line_len * 0.5; - /* Normalize */ - line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0); - /* Create a uv space that englobe the whole segment into a capsule. */ - vec2 uv_end; - uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0); - uv_end.y = dot(vec2(-line.y, line.x), pos); - /* Divide by stroke radius. */ - uv_end /= thickness; - uv_end *= aspect; - - float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0); - if (hardfac > 0.999) { - return step(1e-8, dist); - } - else { - /* Modulate the falloff profile */ - float hardness = 1.0 - hardfac; - dist = pow(dist, mix(0.01, 10.0, hardness)); - return smoothstep(0.0, 1.0, dist); - } -} - -#endif - -uniform vec2 sizeViewport; -uniform vec2 sizeViewportInv; - -/* Per Object */ -uniform bool strokeOrder3d; -uniform int gpMaterialOffset; -uniform float thicknessScale; -uniform float thicknessWorldScale; -#define thicknessIsScreenSpace (thicknessWorldScale < 0.0) - -#ifdef GPU_VERTEX_SHADER - -/* Per Layer */ -uniform float thicknessOffset; -uniform float vertexColorOpacity; -uniform vec4 layerTint; -uniform float layerOpacity; /* Used for onion skin. */ -uniform float strokeIndexOffset = 0.0; - -/* All of these attributes are quad loaded the same way - * as GL_LINES_ADJACENCY would feed a geometry shader: - * - ma reference the previous adjacency point. - * - ma1 reference the current line first point. - * - ma2 reference the current line second point. - * - ma3 reference the next adjacency point. - * Note that we are rendering quad instances and not using any index buffer (except for fills). - */ -/* x is material index, y is stroke_id, z is point_id, w is aspect & rotation & hardness packed. */ -in ivec4 ma; -in ivec4 ma1; -in ivec4 ma2; -in ivec4 ma3; -/* Position contains thickness in 4th component. */ -in vec4 pos; /* Prev adj vert */ -in vec4 pos1; /* Current edge */ -in vec4 pos2; /* Current edge */ -in vec4 pos3; /* Next adj vert */ -/* xy is UV for fills, z is U of stroke, w is strength. */ -in vec4 uv1; -in vec4 uv2; -in vec4 col1; -in vec4 col2; -in vec4 fcol1; -/* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation - * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */ -# define stroke_id1 ma1.y -# define point_id1 ma1.z -# define thickness1 pos1.w -# define thickness2 pos2.w -# define strength1 uv1.w -# define strength2 uv2.w -/* Packed! need to be decoded. */ -# define hardness1 ma1.w -# define hardness2 ma2.w -# define uvrot1 ma1.w -# define aspect1 ma1.w - -vec2 decode_aspect(int packed_data) -{ - float asp = float(uint(packed_data) & 0x1FFu) * (1.0 / 255.0); - return (asp > 1.0) ? vec2(1.0, (asp - 1.0)) : vec2(asp, 1.0); -} - -float decode_uvrot(int packed_data) -{ - uint udata = uint(packed_data); - float uvrot = 1e-8 + float((udata & 0x1FE00u) >> 9u) * (1.0 / 255.0); - return ((udata & 0x20000u) != 0u) ? -uvrot : uvrot; -} - -float decode_hardness(int packed_data) -{ - return float((uint(packed_data) & 0x3FC0000u) >> 18u) * (1.0 / 255.0); -} - -void discard_vert() -{ - /* We set the vertex at the camera origin to generate 0 fragments. */ - gl_Position = vec4(0.0, 0.0, -3e36, 0.0); -} - -vec2 project_to_screenspace(vec4 v) -{ - return ((v.xy / v.w) * 0.5 + 0.5) * sizeViewport; -} - -vec2 rotate_90deg(vec2 v) -{ - /* Counter Clock-Wise. */ - return vec2(-v.y, v.x); -} - -mat4 model_matrix_get() -{ - return ModelMatrix; -} - -vec3 transform_point(mat4 m, vec3 v) -{ - return (m * vec4(v, 1.0)).xyz; -} - -vec2 safe_normalize(vec2 v) -{ - float len_sqr = dot(v, v); - if (len_sqr > 0.0) { - return v / sqrt(len_sqr); - } - else { - return vec2(1.0, 0.0); - } -} - -vec2 safe_normalize_len(vec2 v, out float len) -{ - len = sqrt(dot(v, v)); - if (len > 0.0) { - return v / len; - } - else { - return vec2(1.0, 0.0); - } -} - -float stroke_thickness_modulate(float thickness) -{ - /* Modify stroke thickness by object and layer factors. */ - thickness *= thicknessScale; - thickness += thicknessOffset; - thickness = max(1.0, thickness); - - if (thicknessIsScreenSpace) { - /* Multiply offset by view Z so that offset is constant in screenspace. - * (e.i: does not change with the distance to camera) */ - thickness *= gl_Position.w; - } - else { - /* World space point size. */ - thickness *= thicknessWorldScale * drw_view.winmat[1][1] * sizeViewport.y; - } - return thickness; -} - -float clamp_small_stroke_thickness(float thickness) -{ - /* To avoid aliasing artifacts, we clamp the line thickness and - * reduce its opacity in the fragment shader. */ - float min_thickness = gl_Position.w * 1.3; - thickness = max(min_thickness, thickness); - - return thickness; -} - -# ifdef GP_MATERIAL_BUFFER_LEN -void color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex) -{ - /* Mix stroke with other colors. */ - vec4 mixed_col = stroke_col; - mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a * vertexColorOpacity); - mixed_col.rgb = mix(mixed_col.rgb, layerTint.rgb, layerTint.a); - mixed_col.a *= vert_strength * layerOpacity; - /** - * This is what the fragment shader looks like. - * out = col * finalColorMul + col.a * finalColorAdd. - * finalColorMul is how much of the texture color to keep. - * finalColorAdd is how much of the mixed color to add. - * Note that we never add alpha. This is to keep the texture act as a stencil. - * We do however, modulate the alpha (reduce it). - */ - /* We add the mixed color. This is 100% mix (no texture visible). */ - finalColorMul = vec4(mixed_col.aaa, mixed_col.a); - finalColorAdd = vec4(mixed_col.rgb * mixed_col.a, 0.0); - /* Then we blend according to the texture mix factor. - * Note that we keep the alpha modulation. */ - finalColorMul.rgb *= mix_tex; - finalColorAdd.rgb *= 1.0 - mix_tex; -} -# endif - -void stroke_vertex() -{ - int m = ma1.x; - bool is_dot = false; - bool is_squares = false; - -# ifdef GP_MATERIAL_BUFFER_LEN - if (m != -1) { - is_dot = GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_ALIGNMENT); - is_squares = !GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_DOTS); - } -# endif - - /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */ - if (!is_dot && ma.x == -1 && ma2.x == -1) { - is_dot = true; - is_squares = false; - } - - /* Endpoints, we discard the vertices. */ - if (ma1.x == -1 || (!is_dot && ma2.x == -1)) { - discard_vert(); - return; - } - - mat4 model_mat = model_matrix_get(); - - /* Avoid using a vertex attribute for quad positioning. */ - float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */ - float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */ - - bool use_curr = is_dot || (x == -1.0); - - vec3 wpos_adj = transform_point(model_mat, (use_curr) ? pos.xyz : pos3.xyz); - vec3 wpos1 = transform_point(model_mat, pos1.xyz); - vec3 wpos2 = transform_point(model_mat, pos2.xyz); - - vec4 ndc_adj = point_world_to_ndc(wpos_adj); - vec4 ndc1 = point_world_to_ndc(wpos1); - vec4 ndc2 = point_world_to_ndc(wpos2); - - gl_Position = (use_curr) ? ndc1 : ndc2; - finalPos = (use_curr) ? wpos1 : wpos2; - - vec2 ss_adj = project_to_screenspace(ndc_adj); - vec2 ss1 = project_to_screenspace(ndc1); - vec2 ss2 = project_to_screenspace(ndc2); - /* Screenspace Lines tangents. */ - float line_len; - vec2 line = safe_normalize_len(ss2 - ss1, line_len); - vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2)); - - float thickness = abs((use_curr) ? thickness1 : thickness2); - thickness = stroke_thickness_modulate(thickness); - float clampedThickness = clamp_small_stroke_thickness(thickness); - - finalUvs = vec2(x, y) * 0.5 + 0.5; - strokeHardeness = decode_hardness(use_curr ? hardness1 : hardness2); - - if (is_dot) { -# ifdef GP_MATERIAL_BUFFER_LEN - int alignement = GP_FLAG(m) & GP_STROKE_ALIGNMENT; - /* For one point strokes use object alignment. */ - if (ma.x == -1 && ma2.x == -1 && alignement == GP_STROKE_ALIGNMENT_STROKE) { - alignement = GP_STROKE_ALIGNMENT_OBJECT; - } -# endif - - vec2 x_axis; -# ifdef GP_MATERIAL_BUFFER_LEN - if (alignement == GP_STROKE_ALIGNMENT_STROKE) { - x_axis = (ma2.x == -1) ? line_adj : line; - } - else if (alignement == GP_STROKE_ALIGNMENT_FIXED) { - /* Default for no-material drawing. */ - x_axis = vec2(1.0, 0.0); - } - else -# endif - { /* GP_STROKE_ALIGNMENT_OBJECT */ - vec4 ndc_x = point_world_to_ndc(wpos1 + model_mat[0].xyz); - vec2 ss_x = project_to_screenspace(ndc_x); - x_axis = safe_normalize(ss_x - ss1); - } - - /* Rotation: Encoded as Cos + Sin sign. */ - float uv_rot = decode_uvrot(uvrot1); - float rot_sin = sqrt(max(0.0, 1.0 - uv_rot * uv_rot)) * sign(uv_rot); - float rot_cos = abs(uv_rot); - x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis; - -# ifdef GP_MATERIAL_BUFFER_LEN - if (is_dot) { - float alignment_cos = MATERIAL(m).fill_uv_offset.z; - float alignment_sin = MATERIAL(m).fill_uv_offset.w; - x_axis = mat2(alignment_cos, -alignment_sin, alignment_sin, alignment_cos) * x_axis; - } -# endif - - vec2 y_axis = rotate_90deg(x_axis); - - strokeAspect = decode_aspect(aspect1); - - x *= strokeAspect.x; - y *= strokeAspect.y; - - /* Invert for vertex shader. */ - strokeAspect = 1.0 / strokeAspect; - - gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * clampedThickness; - - strokePt1 = ss1; - strokePt2 = ss1 + x_axis * 0.5; - strokeThickness = (is_squares) ? 1e18 : (clampedThickness / gl_Position.w); - unclampedThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w); - } - else { - bool is_stroke_start = (ma.x == -1 && x == -1); - bool is_stroke_end = (ma3.x == -1 && x == 1); - - /* Mitter tangent vector. */ - vec2 miter_tan = safe_normalize(line_adj + line); - float miter_dot = dot(miter_tan, line_adj); - /* Break corners after a certain angle to avoid really thick corners. */ - const float miter_limit = 0.5; /* cos(60°) */ - bool miter_break = (miter_dot < miter_limit); - miter_tan = (miter_break || is_stroke_start || is_stroke_end) ? line : (miter_tan / miter_dot); - - vec2 miter = rotate_90deg(miter_tan); - - strokePt1.xy = ss1; - strokePt2.xy = ss2; - strokeThickness = clampedThickness / gl_Position.w; - unclampedThickness = thickness / gl_Position.w; - strokeAspect = vec2(1.0); - - vec2 screen_ofs = miter * y; - - /* Reminder: we packed the cap flag into the sign of strength and thickness sign. */ - if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) || - (miter_break && !is_stroke_start && !is_stroke_end)) { - screen_ofs += line * x; - } - - gl_Position.xy += screen_ofs * sizeViewportInv.xy * clampedThickness; - - finalUvs.x = (use_curr) ? uv1.z : uv2.z; -# ifdef GP_MATERIAL_BUFFER_LEN - finalUvs.x *= MATERIAL(m).stroke_u_scale; -# endif - } - -# ifdef GP_MATERIAL_BUFFER_LEN - vec4 vert_col = (use_curr) ? col1 : col2; - float vert_strength = abs((use_curr) ? strength1 : strength2); - vec4 stroke_col = MATERIAL(m).stroke_color; - float mix_tex = MATERIAL(m).stroke_texture_mix; - - /* Special case: We don't use vertex color if material Holdout. */ - if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_HOLDOUT)) { - vert_col = vec4(0.0); - } - - color_output(stroke_col, vert_col, vert_strength, mix_tex); - - matFlag = GP_FLAG(m) & ~GP_FILL_FLAGS; -# endif - - if (strokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - depth = -1.0; - } -# ifdef GP_MATERIAL_BUFFER_LEN - else if (GP_FLAG_TEST(GP_FLAG(m), GP_STROKE_OVERLAP)) { - /* Use the index of the point as depth. - * This means the stroke can overlap itself. */ - depth = (point_id1 + strokeIndexOffset + 1.0) * 0.0000002; - } -# endif - else { - /* Use the index of first point of the stroke as depth. - * We render using a greater depth test this means the stroke - * cannot overlap itself. - * We offset by one so that the fill can be overlapped by its stroke. - * The offset is ok since we pad the strokes data because of adjacency infos. */ - depth = (stroke_id1 + strokeIndexOffset + 1.0) * 0.0000002; - } -} - -void fill_vertex() -{ - mat4 model_mat = model_matrix_get(); - - vec3 wpos = transform_point(model_mat, pos1.xyz); - gl_Position = point_world_to_ndc(wpos); - finalPos = wpos; - -# ifdef GP_MATERIAL_BUFFER_LEN - int m = ma1.x; - - vec4 fill_col = MATERIAL(m).fill_color; - float mix_tex = MATERIAL(m).fill_texture_mix; - - /* Special case: We don't modulate alpha in gradient mode. */ - if (GP_FLAG_TEST(GP_FLAG(m), GP_FILL_GRADIENT_USE)) { - fill_col.a = 1.0; - } - - /* Decode fill opacity. */ - vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0)); - float fill_opacity = fcol1.a - (fcol_decode.a * 10); - fcol_decode.a /= 10000.0; - - /* Special case: We don't use vertex color if material Holdout. */ - if (GP_FLAG_TEST(GP_FLAG(m), GP_FILL_HOLDOUT)) { - fcol_decode = vec4(0.0); - } - - /* Apply opacity. */ - fill_col.a *= fill_opacity; - /* If factor is > 1 force opacity. */ - if (fill_opacity > 1.0) { - fill_col.a += fill_opacity - 1.0; - } - - fill_col.a = clamp(fill_col.a, 0.0, 1.0); - - color_output(fill_col, fcol_decode, 1.0, mix_tex); - - matFlag = GP_FLAG(m) & GP_FILL_FLAGS; - matFlag |= m << GP_MATID_SHIFT; - - vec2 loc = MATERIAL(m).fill_uv_offset.xy; - mat2x2 rot_scale = mat2x2(MATERIAL(m).fill_uv_rot_scale.xy, MATERIAL(m).fill_uv_rot_scale.zw); - finalUvs = rot_scale * uv1.xy + loc; -# endif - - strokeHardeness = 1.0; - strokeThickness = 1e18; - unclampedThickness = 1e20; - strokeAspect = vec2(1.0); - strokePt1 = strokePt2 = vec2(0.0); - - if (strokeOrder3d) { - /* Use the fragment depth (see fragment shader). */ - depth = -1.0; - /* We still offset the fills a little to avoid overlaps */ - gl_Position.z += 0.000002; - } - else { - /* Use the index of first point of the stroke as depth. */ - depth = (stroke_id1 + strokeIndexOffset) * 0.0000002; - } -} - -void gpencil_vertex() -{ - /* Trick to detect if a drawcall is stroke or fill. - * This does mean that we need to draw an empty stroke segment before starting - * to draw the real stroke segments. */ - bool is_fill = (gl_InstanceID == 0); - - if (!is_fill) { - stroke_vertex(); - } - else { - fill_vertex(); - } -} - -#endif diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl index 8ed03b23809..2e7544cea29 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl @@ -31,23 +31,11 @@ void main() vec4 vert_color; vec3 vert_N; + ivec4 ma1 = floatBitsToInt(texelFetch(gp_pos_tx, gpencil_stroke_point_id() * 3 + 1)); gpMaterial gp_mat = materials[ma1.x + gpMaterialOffset]; gpMaterialFlag gp_flag = floatBitsToUint(gp_mat._flag); - gl_Position = gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - vec4(viewportSize, 1.0 / viewportSize), + gl_Position = gpencil_vertex(vec4(viewportSize, 1.0 / viewportSize), gp_flag, gp_mat._alignment_rot, gp_interp.pos, @@ -60,7 +48,7 @@ void main() gp_interp.thickness, gp_interp.hardness); - if (GPENCIL_IS_STROKE_VERTEX) { + if (gpencil_is_stroke_vertex()) { if (!flag_test(gp_flag, GP_STROKE_ALIGNMENT)) { gp_interp.uv.x *= gp_mat._stroke_u_scale; } @@ -83,7 +71,7 @@ void main() /* Use the index of the point as depth. * This means the stroke can overlap itself. */ float point_index = float(ma1.z); - gp_interp.depth = (point_index + gpStrokeIndexOffset + 1.0) * 0.0000002; + gp_interp.depth = (point_index + gpStrokeIndexOffset + 2.0) * 0.0000002; } else { /* Use the index of first point of the stroke as depth. @@ -92,10 +80,13 @@ void main() * We offset by one so that the fill can be overlapped by its stroke. * The offset is ok since we pad the strokes data because of adjacency infos. */ float stroke_index = float(ma1.y); - gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002; + gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 2.0) * 0.0000002; } } else { + int stroke_point_id = gpencil_stroke_point_id(); + vec4 uv1 = texelFetch(gp_pos_tx, stroke_point_id * 3 + 2); + vec4 fcol1 = texelFetch(gp_col_tx, stroke_point_id * 2 + 1); vec4 fill_col = gp_mat.fill_color; /* Special case: We don't modulate alpha in gradient mode. */ @@ -137,7 +128,7 @@ void main() else { /* Use the index of first point of the stroke as depth. */ float stroke_index = float(ma1.y); - gp_interp.depth = (stroke_index + gpStrokeIndexOffset) * 0.0000002; + gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002; } } } diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh index edd51e71242..da2776254e6 100644 --- a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh +++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh @@ -22,10 +22,10 @@ GPU_SHADER_CREATE_INFO(gpencil_geometry) .do_static_compilation(true) .define("GP_LIGHT") .typedef_source("gpencil_defines.h") - .sampler(0, ImageType::FLOAT_2D, "gpFillTexture") - .sampler(1, ImageType::FLOAT_2D, "gpStrokeTexture") - .sampler(2, ImageType::DEPTH_2D, "gpSceneDepthTexture") - .sampler(3, ImageType::FLOAT_2D, "gpMaskTexture") + .sampler(2, ImageType::FLOAT_2D, "gpFillTexture") + .sampler(3, ImageType::FLOAT_2D, "gpStrokeTexture") + .sampler(4, ImageType::DEPTH_2D, "gpSceneDepthTexture") + .sampler(5, ImageType::FLOAT_2D, "gpMaskTexture") .uniform_buf(4, "gpMaterial", "materials[GPENCIL_MATERIAL_BUFFER_LEN]", Frequency::BATCH) .uniform_buf(3, "gpLight", "lights[GPENCIL_LIGHT_BUFFER_LEN]", Frequency::BATCH) .push_constant(Type::VEC2, "viewportSize") diff --git a/source/blender/draw/engines/overlay/overlay_armature.cc b/source/blender/draw/engines/overlay/overlay_armature.cc index 0cf9d91804a..8c9587e7a9a 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.cc +++ b/source/blender/draw/engines/overlay/overlay_armature.cc @@ -441,7 +441,7 @@ static void drw_shgroup_bone_octahedral(ArmatureDrawContext *ctx, const float outline_color[4]) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); if (ctx->solid) { OVERLAY_bone_instance_data_set_color(&inst_data, bone_color); OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color); @@ -461,7 +461,7 @@ static void drw_shgroup_bone_box(ArmatureDrawContext *ctx, const float outline_color[4]) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); if (ctx->solid) { OVERLAY_bone_instance_data_set_color(&inst_data, bone_color); OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color); @@ -479,9 +479,9 @@ static void drw_shgroup_bone_wire(ArmatureDrawContext *ctx, const float color[4]) { float head[3], tail[3]; - mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]); + mul_v3_m4v3(head, ctx->ob->object_to_world, bone_mat[3]); add_v3_v3v3(tail, bone_mat[3], bone_mat[1]); - mul_m4_v3(ctx->ob->obmat, tail); + mul_m4_v3(ctx->ob->object_to_world, tail); DRW_buffer_add_entry(ctx->wire, head, color); DRW_buffer_add_entry(ctx->wire, tail, color); @@ -496,9 +496,9 @@ static void drw_shgroup_bone_stick(ArmatureDrawContext *ctx, const float col_tail[4]) { float head[3], tail[3]; - mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]); + mul_v3_m4v3(head, ctx->ob->object_to_world, bone_mat[3]); add_v3_v3v3(tail, bone_mat[3], bone_mat[1]); - mul_m4_v3(ctx->ob->obmat, tail); + mul_m4_v3(ctx->ob->object_to_world, tail); DRW_buffer_add_entry(ctx->stick, head, tail, col_wire, col_bone, col_head, col_tail); } @@ -517,11 +517,11 @@ static void drw_shgroup_bone_envelope_distance(ArmatureDrawContext *ctx, mul_m4_v4(bone_mat, head_sph); mul_m4_v4(bone_mat, tail_sph); mul_m4_v4(bone_mat, xaxis); - mul_m4_v4(ctx->ob->obmat, head_sph); - mul_m4_v4(ctx->ob->obmat, tail_sph); - mul_m4_v4(ctx->ob->obmat, xaxis); + mul_m4_v4(ctx->ob->object_to_world, head_sph); + mul_m4_v4(ctx->ob->object_to_world, tail_sph); + mul_m4_v4(ctx->ob->object_to_world, xaxis); sub_v3_v3(xaxis, head_sph); - float obscale = mat4_to_scale(ctx->ob->obmat); + float obscale = mat4_to_scale(ctx->ob->object_to_world); head_sph[3] = *radius_head * obscale; head_sph[3] += *distance * obscale; tail_sph[3] = *radius_tail * obscale; @@ -544,10 +544,10 @@ static void drw_shgroup_bone_envelope(ArmatureDrawContext *ctx, mul_m4_v4(bone_mat, head_sph); mul_m4_v4(bone_mat, tail_sph); mul_m4_v4(bone_mat, xaxis); - mul_m4_v4(ctx->ob->obmat, head_sph); - mul_m4_v4(ctx->ob->obmat, tail_sph); - mul_m4_v4(ctx->ob->obmat, xaxis); - float obscale = mat4_to_scale(ctx->ob->obmat); + mul_m4_v4(ctx->ob->object_to_world, head_sph); + mul_m4_v4(ctx->ob->object_to_world, tail_sph); + mul_m4_v4(ctx->ob->object_to_world, xaxis); + float obscale = mat4_to_scale(ctx->ob->object_to_world); head_sph[3] = *radius_head * obscale; tail_sph[3] = *radius_tail * obscale; @@ -651,7 +651,7 @@ static void drw_shgroup_bone_custom_solid_mesh(ArmatureDrawContext *ctx, DRWCallBuffer *buf; if (surf || edges || ledges) { - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); } if (surf && ctx->custom_solid) { @@ -692,7 +692,7 @@ static void drw_shgroup_bone_custom_mesh_wire(ArmatureDrawContext *ctx, if (geom) { DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom); BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); OVERLAY_bone_instance_data_set_color_hint(&inst_data, color); OVERLAY_bone_instance_data_set_color(&inst_data, color); DRW_buffer_add_entry_struct(buf, inst_data.mat); @@ -724,7 +724,7 @@ static void drw_shgroup_custom_bone_curve(ArmatureDrawContext *ctx, if (ledges) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, ledges); OVERLAY_bone_instance_data_set_color_hint(&inst_data, outline_color); @@ -785,7 +785,7 @@ static void drw_shgroup_bone_custom_empty(ArmatureDrawContext *ctx, { const float final_color[4] = {color[0], color[1], color[2], 1.0f}; float mat[4][4]; - mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(mat, ctx->ob->object_to_world, bone_mat); switch (custom->empty_drawtype) { case OB_PLAINAXES: @@ -811,7 +811,7 @@ static void drw_shgroup_bone_point(ArmatureDrawContext *ctx, const float outline_color[4]) { BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, bone_mat); if (ctx->point_solid) { OVERLAY_bone_instance_data_set_color(&inst_data, bone_color); OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color); @@ -829,7 +829,7 @@ static void drw_shgroup_bone_axes(ArmatureDrawContext *ctx, const float color[4]) { float mat[4][4]; - mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat); + mul_m4_m4m4(mat, ctx->ob->object_to_world, bone_mat); /* Move to bone tail. */ add_v3_v3(mat[3], mat[1]); OVERLAY_empty_shape(ctx->extras, mat, 0.25f, OB_ARROWS, color); @@ -842,8 +842,8 @@ static void drw_shgroup_bone_relationship_lines_ex(ArmatureDrawContext *ctx, const float color[4]) { float s[3], e[3]; - mul_v3_m4v3(s, ctx->ob->obmat, start); - mul_v3_m4v3(e, ctx->ob->obmat, end); + mul_v3_m4v3(s, ctx->ob->object_to_world, start); + mul_v3_m4v3(e, ctx->ob->object_to_world, end); /* reverse order to have less stipple overlap */ OVERLAY_extra_line_dashed(ctx->extras, s, e, color); } @@ -1909,7 +1909,7 @@ static void draw_bone_degrees_of_freedom(ArmatureDrawContext *ctx, bPoseChannel mul_m4_m4m4(posetrans, posetrans, tmp); /* into world space. */ - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, posetrans); + mul_m4_m4m4(inst_data.mat, ctx->ob->object_to_world, posetrans); if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) { bone_instance_data_set_angle_minmax( @@ -2079,7 +2079,7 @@ static void draw_bone_name(ArmatureDrawContext *ctx, float *head = pchan ? pchan->pose_head : eBone->head; float *tail = pchan ? pchan->pose_tail : eBone->tail; mid_v3_v3v3(vec, head, tail); - mul_m4_v3(ctx->ob->obmat, vec); + mul_m4_v3(ctx->ob->object_to_world, vec); DRW_text_cache_add(dt, vec, @@ -2177,7 +2177,8 @@ static bool pchan_culling_test_envelope(const DRWView *view, BoundSphere bsphere; pchan_culling_calc_bsphere(ob, pchan, &bsphere); bsphere.radius += max_ff(pchan->bone->rad_head, pchan->bone->rad_tail) * - mat4_to_size_max_axis(ob->obmat) * mat4_to_size_max_axis(pchan->disp_mat); + mat4_to_size_max_axis(ob->object_to_world) * + mat4_to_size_max_axis(pchan->disp_mat); return DRW_culling_sphere_test(view, &bsphere); } @@ -2188,13 +2189,13 @@ static bool pchan_culling_test_bbone(const DRWView *view, const bArmature *arm = static_cast<bArmature *>(ob->data); BLI_assert(arm->drawtype == ARM_B_BONE); UNUSED_VARS_NDEBUG(arm); - const float ob_scale = mat4_to_size_max_axis(ob->obmat); + const float ob_scale = mat4_to_size_max_axis(ob->object_to_world); const Mat4 *bbones_mat = (const Mat4 *)pchan->draw_data->bbone_matrix; for (int i = pchan->bone->segments; i--; bbones_mat++) { BoundSphere bsphere; float size[3]; mat4_to_size(size, bbones_mat->mat); - mul_v3_m4v3(bsphere.center, ob->obmat, bbones_mat->mat[3]); + mul_v3_m4v3(bsphere.center, ob->object_to_world, bbones_mat->mat[3]); bsphere.radius = len_v3(size) * ob_scale; if (DRW_culling_sphere_test(view, &bsphere)) { return true; diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.cc b/source/blender/draw/engines/overlay/overlay_edit_text.cc index ebadaa530e4..d1bca705ae6 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_text.cc +++ b/source/blender/draw/engines/overlay/overlay_edit_text.cc @@ -119,7 +119,7 @@ static void edit_text_cache_populate_select(OVERLAY_Data *vedata, Object *ob) add_v2_v2(box[3], &sb->x); } v2_quad_corners_to_mat4(box, final_mat); - mul_m4_m4m4(final_mat, ob->obmat, final_mat); + mul_m4_m4m4(final_mat, ob->object_to_world, final_mat); DRW_shgroup_call_obmat(pd->edit_text_selection_grp, geom, final_mat); } @@ -134,7 +134,7 @@ static void edit_text_cache_populate_cursor(OVERLAY_Data *vedata, Object *ob) float mat[4][4]; v2_quad_corners_to_mat4(cursor, mat); - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); struct GPUBatch *geom = DRW_cache_quad_get(); DRW_shgroup_call_obmat(pd->edit_text_cursor_grp, geom, mat); @@ -162,7 +162,7 @@ static void edit_text_cache_populate_boxes(OVERLAY_Data *vedata, Object *ob) vecs[3][1] -= tb->h; for (int j = 0; j < 4; j++) { - mul_v3_m4v3(vecs[j], ob->obmat, vecs[j]); + mul_v3_m4v3(vecs[j], ob->object_to_world, vecs[j]); } for (int j = 0; j < 4; j++) { OVERLAY_extra_line_dashed(cb, vecs[j], vecs[(j + 1) % 4], color); diff --git a/source/blender/draw/engines/overlay/overlay_extra.cc b/source/blender/draw/engines/overlay/overlay_extra.cc index 114123ab36e..27afe49a17b 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.cc +++ b/source/blender/draw/engines/overlay/overlay_extra.cc @@ -331,7 +331,7 @@ void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob) case OB_EMPTY_CONE: case OB_ARROWS: DRW_object_wire_theme_get(ob, view_layer, &color); - OVERLAY_empty_shape(cb, ob->obmat, ob->empty_drawsize, ob->empty_drawtype, color); + OVERLAY_empty_shape(cb, ob->object_to_world, ob->empty_drawsize, ob->empty_drawtype, color); break; case OB_EMPTY_IMAGE: OVERLAY_image_empty_cache_populate(vedata, ob); @@ -372,7 +372,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, case OB_BOUND_BOX: size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_cube, color, tmp); break; case OB_BOUND_SPHERE: @@ -380,7 +380,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, size[1] = size[2] = size[0]; size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_sphere, color, tmp); break; case OB_BOUND_CYLINDER: @@ -388,7 +388,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, size[1] = size[0]; size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_cylinder, color, tmp); break; case OB_BOUND_CONE: @@ -399,7 +399,7 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, /* Cone batch has base at 0 and is pointing towards +Y. */ swap_v3_v3(tmp[1], tmp[2]); tmp[3][2] -= size[2]; - mul_m4_m4m4(tmp, ob->obmat, tmp); + mul_m4_m4m4(tmp, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_cone, color, tmp); break; case OB_BOUND_CAPSULE: @@ -408,14 +408,14 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb, scale_m4_fl(tmp, size[0]); copy_v2_v2(tmp[3], center); tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]); - mul_m4_m4m4(final_mat, ob->obmat, tmp); + mul_m4_m4m4(final_mat, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat); negate_v3(tmp[2]); tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]); - mul_m4_m4m4(final_mat, ob->obmat, tmp); + mul_m4_m4m4(final_mat, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat); tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f); - mul_m4_m4m4(final_mat, ob->obmat, tmp); + mul_m4_m4m4(final_mat, ob->object_to_world, tmp); DRW_buffer_add_entry(cb->empty_capsule_body, color, final_mat); break; } @@ -489,7 +489,7 @@ static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, cons unit_m4(mat); } - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); DRW_buffer_add_entry(cb->empty_cube, color, mat); } @@ -511,7 +511,7 @@ static void OVERLAY_forcefield(OVERLAY_ExtraCallBuffers *cb, Object *ob, ViewLay }; } instdata; - copy_m4_m4(instdata.mat, ob->obmat); + copy_m4_m4(instdata.mat, ob->object_to_world); instdata.size_x = instdata.size_y = instdata.size_z = ob->empty_drawsize; switch (pd->forcefield) { @@ -531,16 +531,16 @@ static void OVERLAY_forcefield(OVERLAY_ExtraCallBuffers *cb, Object *ob, ViewLay instdata.size_x = instdata.size_y = instdata.size_z = pd->f_strength; float pos[4]; BKE_where_on_path(ob, 0.0f, pos, nullptr, nullptr, nullptr, nullptr); - copy_v3_v3(instdata.pos, ob->obmat[3]); + copy_v3_v3(instdata.pos, ob->object_to_world[3]); translate_m4(instdata.mat, pos[0], pos[1], pos[2]); DRW_buffer_add_entry(cb->field_curve, color, &instdata); BKE_where_on_path(ob, 1.0f, pos, nullptr, nullptr, nullptr, nullptr); - copy_v3_v3(instdata.pos, ob->obmat[3]); + copy_v3_v3(instdata.pos, ob->object_to_world[3]); translate_m4(instdata.mat, pos[0], pos[1], pos[2]); DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata); /* Restore */ - copy_v3_v3(instdata.pos, ob->obmat[3]); + copy_v3_v3(instdata.pos, ob->object_to_world[3]); } break; } @@ -625,7 +625,7 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob) }; } instdata; - copy_m4_m4(instdata.mat, ob->obmat); + copy_m4_m4(instdata.mat, ob->object_to_world); /* FIXME / TODO: clip_end has no meaning nowadays. * In EEVEE, Only clip_sta is used shadow-mapping. * Clip end is computed automatically based on light power. @@ -708,7 +708,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) }; } instdata; - copy_m4_m4(instdata.mat, ob->obmat); + copy_m4_m4(instdata.mat, ob->object_to_world); switch (prb->type) { case LIGHTPROBE_TYPE_CUBE: @@ -720,15 +720,15 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) if (show_influence) { char shape = (prb->attenuation_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE; float f = 1.0f - prb->falloff; - OVERLAY_empty_shape(cb, ob->obmat, prb->distinf, shape, color_p); - OVERLAY_empty_shape(cb, ob->obmat, prb->distinf * f, shape, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, prb->distinf, shape, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, prb->distinf * f, shape, color_p); } if (show_parallax) { char shape = (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE; float dist = ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) ? prb->distpar : prb->distinf; - OVERLAY_empty_shape(cb, ob->obmat, dist, shape, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, dist, shape, color_p); } break; case LIGHTPROBE_TYPE_GRID: @@ -738,8 +738,8 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) if (show_influence) { float f = 1.0f - prb->falloff; - OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf, OB_CUBE, color_p); - OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf * f, OB_CUBE, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, 1.0 + prb->distinf, OB_CUBE, color_p); + OVERLAY_empty_shape(cb, ob->object_to_world, 1.0 + prb->distinf * f, OB_CUBE, color_p); } /* Data dots */ @@ -777,7 +777,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob) zero_v3(instdata.mat[2]); DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata); - normalize_m4_m4(instdata.mat, ob->obmat); + normalize_m4_m4(instdata.mat, ob->object_to_world); OVERLAY_empty_shape(cb, instdata.mat, ob->empty_drawsize, OB_SINGLE_ARROW, color_p); break; } @@ -797,7 +797,7 @@ void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob) float *color_p; DRW_object_wire_theme_get(ob, view_layer, &color_p); - DRW_buffer_add_entry(cb->speaker, color_p, ob->obmat); + DRW_buffer_add_entry(cb->speaker, color_p, ob->object_to_world); } /** \} */ @@ -890,7 +890,7 @@ static void camera_view3d_reconstruction( float object_imat[4][4]; invert_m4_m4(object_imat, object_mat); - mul_m4_m4m4(tracking_object_mat, ob->obmat, object_imat); + mul_m4_m4m4(tracking_object_mat, ob->object_to_world, object_imat); } ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); @@ -1132,14 +1132,17 @@ void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob) DRW_object_wire_theme_get(ob, view_layer, &color_p); copy_v4_v4(instdata.color, color_p); - normalize_m4_m4(instdata.mat, ob->obmat); + normalize_m4_m4(instdata.mat, ob->object_to_world); /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here. */ if (is_selection_camera_stereo) { copy_v3_fl(scale, 1.0f); } else { - copy_v3_fl3(scale, len_v3(ob->obmat[0]), len_v3(ob->obmat[1]), len_v3(ob->obmat[2])); + copy_v3_fl3(scale, + len_v3(ob->object_to_world[0]), + len_v3(ob->object_to_world[1]), + len_v3(ob->object_to_world[2])); /* Avoid division by 0. */ if (ELEM(0.0f, scale[0], scale[1], scale[2])) { return; @@ -1255,7 +1258,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, if (ob->parent && (DRW_object_visibility_in_active_context(ob->parent) & OB_VISIBLE_SELF)) { float *parent_pos = ob->runtime.parent_display_origin; - OVERLAY_extra_line_dashed(cb, parent_pos, ob->obmat[3], relation_color); + OVERLAY_extra_line_dashed(cb, parent_pos, ob->object_to_world[3], relation_color); } /* Drawing the hook lines. */ @@ -1263,9 +1266,9 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, if (md->type == eModifierType_Hook) { HookModifierData *hmd = (HookModifierData *)md; float center[3]; - mul_v3_m4v3(center, ob->obmat, hmd->cent); + mul_v3_m4v3(center, ob->object_to_world, hmd->cent); if (hmd->object) { - OVERLAY_extra_line_dashed(cb, hmd->object->obmat[3], center, relation_color); + OVERLAY_extra_line_dashed(cb, hmd->object->object_to_world[3], center, relation_color); } OVERLAY_extra_point(cb, center, relation_color); } @@ -1275,10 +1278,12 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, Object *rbc_ob1 = ob->rigidbody_constraint->ob1; Object *rbc_ob2 = ob->rigidbody_constraint->ob2; if (rbc_ob1 && (DRW_object_visibility_in_active_context(rbc_ob1) & OB_VISIBLE_SELF)) { - OVERLAY_extra_line_dashed(cb, rbc_ob1->obmat[3], ob->obmat[3], relation_color); + OVERLAY_extra_line_dashed( + cb, rbc_ob1->object_to_world[3], ob->object_to_world[3], relation_color); } if (rbc_ob2 && (DRW_object_visibility_in_active_context(rbc_ob2) & OB_VISIBLE_SELF)) { - OVERLAY_extra_line_dashed(cb, rbc_ob2->obmat[3], ob->obmat[3], relation_color); + OVERLAY_extra_line_dashed( + cb, rbc_ob2->object_to_world[3], ob->object_to_world[3], relation_color); } } @@ -1307,7 +1312,8 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, } if (camob) { - OVERLAY_extra_line_dashed(cb, camob->obmat[3], ob->obmat[3], constraint_color); + OVERLAY_extra_line_dashed( + cb, camob->object_to_world[3], ob->object_to_world[3], constraint_color); } } else { @@ -1330,7 +1336,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, else { unit_m4(ct->matrix); } - OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color); + OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->object_to_world[3], constraint_color); } BKE_constraint_targets_flush(curcon, &targets, true); @@ -1387,7 +1393,7 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, copy_v3_v3(voxel_cubemat[3], min); /* move small cube into the domain (otherwise its centered on vertex of domain object) */ translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f); - mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat); + mul_m4_m4m4(voxel_cubemat, ob->object_to_world, voxel_cubemat); DRW_buffer_add_entry(cb->empty_cube, color, voxel_cubemat); } @@ -1493,15 +1499,15 @@ static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb, const bool is_library = ID_REAL_USERS(&ob->id) > 1 || ID_IS_LINKED(ob); BKE_view_layer_synced_ensure(scene, view_layer); if (ob == BKE_view_layer_active_object_get(view_layer)) { - DRW_buffer_add_entry(cb->center_active, ob->obmat[3]); + DRW_buffer_add_entry(cb->center_active, ob->object_to_world[3]); } else if (ob->base_flag & BASE_SELECTED) { DRWCallBuffer *cbuf = (is_library) ? cb->center_selected_lib : cb->center_selected; - DRW_buffer_add_entry(cbuf, ob->obmat[3]); + DRW_buffer_add_entry(cbuf, ob->object_to_world[3]); } else if (pd->v3d_flag & V3D_DRAW_CENTERS) { DRWCallBuffer *cbuf = (is_library) ? cb->center_deselected_lib : cb->center_deselected; - DRW_buffer_add_entry(cbuf, ob->obmat[3]); + DRW_buffer_add_entry(cbuf, ob->object_to_world[3]); } } @@ -1513,7 +1519,7 @@ static void OVERLAY_object_name(Object *ob, int theme_id) UI_GetThemeColor4ubv(theme_id, color); DRW_text_cache_add(dt, - ob->obmat[3], + ob->object_to_world[3], ob->id.name + 2, strlen(ob->id.name + 2), 10, @@ -1571,7 +1577,7 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob) /* Helpers for when we're transforming origins. */ if (draw_xform) { const float color_xform[4] = {0.15f, 0.15f, 0.15f, 0.7f}; - DRW_buffer_add_entry(cb->origin_xform, color_xform, ob->obmat); + DRW_buffer_add_entry(cb->origin_xform, color_xform, ob->object_to_world); } /* don't show object extras in set's */ if (!from_dupli) { @@ -1591,7 +1597,7 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob) OVERLAY_collision(cb, ob, color); } if (ob->dtx & OB_AXIS) { - DRW_buffer_add_entry(cb->empty_axes, color, ob->obmat); + DRW_buffer_add_entry(cb->empty_axes, color, ob->object_to_world); } if (draw_volume) { OVERLAY_volume_extra(cb, vedata, ob, md, scene, color); diff --git a/source/blender/draw/engines/overlay/overlay_facing.cc b/source/blender/draw/engines/overlay/overlay_facing.cc index 825036ecd05..44dab0f0a42 100644 --- a/source/blender/draw/engines/overlay/overlay_facing.cc +++ b/source/blender/draw/engines/overlay/overlay_facing.cc @@ -43,7 +43,7 @@ void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob) } const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_fade.cc b/source/blender/draw/engines/overlay/overlay_fade.cc index d6fd4f9127a..b9523a4eac9 100644 --- a/source/blender/draw/engines/overlay/overlay_fade.cc +++ b/source/blender/draw/engines/overlay/overlay_fade.cc @@ -53,7 +53,7 @@ void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob) } const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.cc b/source/blender/draw/engines/overlay/overlay_gpencil.cc index 30765b30ce6..f5988d91e72 100644 --- a/source/blender/draw/engines/overlay/overlay_gpencil.cc +++ b/source/blender/draw/engines/overlay/overlay_gpencil.cc @@ -243,7 +243,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) copy_v3_v3(col_grid, gpd->grid.color); col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f); - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* Rotate and scale except align to cursor. */ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -286,7 +286,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) copy_v3_v3(mat[3], cursor->location); } else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) { - copy_v3_v3(mat[3], ob->obmat[3]); + copy_v3_v3(mat[3], ob->object_to_world[3]); } translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f); @@ -397,7 +397,7 @@ static void overlay_gpencil_draw_stroke_color_name(bGPDlayer * /*gpl*/, UI_GetThemeColor4ubv(theme_id, color); float fpt[3]; - mul_v3_m4v3(fpt, ob->obmat, &pt->x); + mul_v3_m4v3(fpt, ob->object_to_world, &pt->x); struct DRWTextStore *dt = DRW_text_cache_ensure(); DRW_text_cache_add(dt, diff --git a/source/blender/draw/engines/overlay/overlay_image.cc b/source/blender/draw/engines/overlay/overlay_image.cc index f42867622e4..7b99bd6bd18 100644 --- a/source/blender/draw/engines/overlay/overlay_image.cc +++ b/source/blender/draw/engines/overlay/overlay_image.cc @@ -392,7 +392,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob) float image_aspect[2]; overlay_image_calc_aspect(ima, size, image_aspect); - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); mul_v3_fl(mat[0], image_aspect[0] * 0.5f * ob->empty_drawsize); mul_v3_fl(mat[1], image_aspect[1] * 0.5f * ob->empty_drawsize); madd_v3_v3fl(mat[3], mat[0], ob->ima_ofs[0] * 2.0f + 1.0f); diff --git a/source/blender/draw/engines/overlay/overlay_lattice.cc b/source/blender/draw/engines/overlay/overlay_lattice.cc index 7b59aa78c89..72c3335d871 100644 --- a/source/blender/draw/engines/overlay/overlay_lattice.cc +++ b/source/blender/draw/engines/overlay/overlay_lattice.cc @@ -52,7 +52,7 @@ void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob) DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false); - OVERLAY_extra_wire(cb, geom, ob->obmat, color); + OVERLAY_extra_wire(cb, geom, ob->object_to_world, color); } void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata) diff --git a/source/blender/draw/engines/overlay/overlay_metaball.cc b/source/blender/draw/engines/overlay/overlay_metaball.cc index 2fc6910fe44..dd0a862337e 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.cc +++ b/source/blender/draw/engines/overlay/overlay_metaball.cc @@ -45,10 +45,10 @@ static void metaball_instance_data_set( BoneInstanceData *data, Object *ob, const float *pos, const float radius, const float color[4]) { /* Bone point radius is 0.05. Compensate for that. */ - mul_v3_v3fl(data->mat[0], ob->obmat[0], radius / 0.05f); - mul_v3_v3fl(data->mat[1], ob->obmat[1], radius / 0.05f); - mul_v3_v3fl(data->mat[2], ob->obmat[2], radius / 0.05f); - mul_v3_m4v3(data->mat[3], ob->obmat, pos); + mul_v3_v3fl(data->mat[0], ob->object_to_world[0], radius / 0.05f); + mul_v3_v3fl(data->mat[1], ob->object_to_world[1], radius / 0.05f); + mul_v3_v3fl(data->mat[2], ob->object_to_world[2], radius / 0.05f); + mul_v3_m4v3(data->mat[3], ob->object_to_world, pos); /* WATCH: Reminder, alpha is wire-size. */ OVERLAY_bone_instance_data_set_color(data, color); } diff --git a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc index 5222abfc743..79ac92a187c 100644 --- a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc +++ b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc @@ -85,7 +85,7 @@ void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob) } const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index 5ea02376b67..c2df665eba3 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -43,7 +43,7 @@ static void gpencil_depth_plane(Object *ob, float r_plane[4]) add_v3_fl(size, 1e-8f); rescale_m4(mat, size); /* BBox space to World. */ - mul_m4_m4m4(mat, ob->obmat, mat); + mul_m4_m4m4(mat, ob->object_to_world, mat); /* BBox center in world space. */ copy_v3_v3(center, mat[3]); /* View Vector. */ @@ -138,6 +138,7 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); GPUShader *sh_curves = OVERLAY_shader_outline_prepass_curves(); + pd->outlines_curves_grp = grp = DRW_shgroup_create(sh_curves, psl->outlines_prepass_ps); DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); @@ -172,7 +173,6 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) typedef struct iterData { Object *ob; DRWShadingGroup *stroke_grp; - DRWShadingGroup *fill_grp; int cfra; float plane[4]; } iterData; @@ -188,17 +188,22 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl, const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0; const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D); - float object_scale = mat4_to_scale(iter->ob->obmat); + float object_scale = mat4_to_scale(iter->ob->object_to_world); /* Negate thickness sign to tag that strokes are in screen space. * Convert to world units (by default, 1 meter = 2000 pixels). */ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f); + GPUVertBuf *position_tx = DRW_cache_gpencil_position_buffer_get(iter->ob, iter->cfra); + GPUVertBuf *color_tx = DRW_cache_gpencil_color_buffer_get(iter->ob, iter->cfra); + DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp); DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d); DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale); DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", float(gpl->line_change)); DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale); DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane); + DRW_shgroup_buffer_texture(grp, "gp_pos_tx", position_tx); + DRW_shgroup_buffer_texture(grp, "gp_col_tx", color_tx); } static void gpencil_stroke_cache_populate(bGPDlayer * /*gpl*/, @@ -219,20 +224,19 @@ static void gpencil_stroke_cache_populate(bGPDlayer * /*gpl*/, return; } + struct GPUBatch *geom = DRW_cache_gpencil_get(iter->ob, iter->cfra); + if (show_fill) { - struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra); int vfirst = gps->runtime.fill_start * 3; int vcount = gps->tot_triangles * 3; - DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount); + DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); } if (show_stroke) { - struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra); - /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; - /* Include "potential" cyclic vertex and start adj vertex (see shader). */ - int vcount = gps->totpoints + 1 + 1; - DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); + int vfirst = gps->runtime.stroke_start * 3; + bool is_cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2); + int vcount = (gps->totpoints + (int)is_cyclic) * 2 * 3; + DRW_shgroup_call_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); } } @@ -247,7 +251,6 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) iterData iter{}; iter.ob = ob; iter.stroke_grp = pd->outlines_gpencil_grp; - iter.fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp); iter.cfra = pd->cfra; if (gpd->draw_mode == GP_DRAWMODE_2D) { @@ -280,6 +283,18 @@ static void OVERLAY_outline_curves(OVERLAY_PrivateData *pd, Object *ob) DRW_shgroup_curves_create_sub(ob, shgroup, nullptr); } +static void OVERLAY_outline_pointcloud(OVERLAY_PrivateData *pd, Object *ob) +{ + if (pd->wireframe_mode) { + /* Looks bad in this case. Could be relaxed if we draw a + * wireframe of some sort in the future. */ + return; + } + + DRWShadingGroup *shgroup = pd->outlines_ptcloud_grp; + DRW_shgroup_pointcloud_create_sub(ob, shgroup, nullptr); +} + void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, Object *ob, OVERLAY_DupliData *dupli, @@ -311,9 +326,8 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, return; } - if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) { - /* Looks bad in this case. Could be relaxed if we draw a - * wireframe of some sort in the future. */ + if (ob->type == OB_POINTCLOUD) { + OVERLAY_outline_pointcloud(pd, ob); return; } @@ -336,18 +350,12 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, } if (geom) { - shgroup = (ob->type == OB_POINTCLOUD) ? pd->outlines_ptcloud_grp : pd->outlines_grp; + shgroup = pd->outlines_grp; } } if (shgroup && geom) { - if (ob->type == OB_POINTCLOUD) { - /* Draw range to avoid drawcall batching messing up the instance attribute. */ - DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0); - } - else { - DRW_shgroup_call(shgroup, geom, ob); - } + DRW_shgroup_call(shgroup, geom, ob); } if (init_dupli) { diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.cc b/source/blender/draw/engines/overlay/overlay_sculpt.cc index 8f142d68350..3377aa5394b 100644 --- a/source/blender/draw/engines/overlay/overlay_sculpt.cc +++ b/source/blender/draw/engines/overlay/overlay_sculpt.cc @@ -37,7 +37,7 @@ void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob) struct GPUBatch *sculpt_overlays; PBVH *pbvh = ob->sculpt->pbvh; - const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d); if (!pbvh) { /* It is possible to have SculptSession without PBVH. This happens, for example, when toggling diff --git a/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc index 1bba2a366a5..68de5dcd11d 100644 --- a/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc +++ b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc @@ -64,7 +64,7 @@ void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object) ".selection_curve_float"; bool is_point_domain; - GPUTexture **texture = DRW_curves_texture_for_evaluated_attribute( + GPUVertBuf **texture = DRW_curves_texture_for_evaluated_attribute( curves, name, &is_point_domain); if (texture == nullptr) { return; @@ -78,7 +78,7 @@ void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object) } DRW_shgroup_uniform_bool_copy(grp, "is_point_domain", is_point_domain); - DRW_shgroup_uniform_texture(grp, "selection_tx", *texture); + DRW_shgroup_buffer_texture(grp, "selection_tx", *texture); } void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata) diff --git a/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc index d57ea08d888..fd1657b3d59 100644 --- a/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc +++ b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc @@ -81,18 +81,16 @@ static void populate_cache_for_instance(Object &object, break; } case OB_POINTCLOUD: { - DRWShadingGroup *sub_grp = DRW_shgroup_create_sub( - pd.viewer_attribute_instance_pointcloud_grp); + DRWShadingGroup *sub_grp = DRW_shgroup_pointcloud_create_sub( + &object, pd.viewer_attribute_pointcloud_grp, nullptr); DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); - GPUBatch *batch = DRW_cache_pointcloud_surface_get(&object); - DRW_shgroup_call_instance_range(sub_grp, &object, batch, 0, 0); break; } case OB_CURVES_LEGACY: { DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp); DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); GPUBatch *batch = DRW_cache_curve_edge_wire_get(&object); - DRW_shgroup_call_obmat(sub_grp, batch, object.obmat); + DRW_shgroup_call_obmat(sub_grp, batch, object.object_to_world); break; } case OB_CURVES: { @@ -123,9 +121,11 @@ static void populate_cache_for_geometry(Object &object, case OB_POINTCLOUD: { PointCloud *pointcloud = static_cast<PointCloud *>(object.data); if (pointcloud->attributes().contains(".viewer")) { - GPUBatch *batch = DRW_cache_pointcloud_surface_viewer_attribute_get(&object); - DRW_shgroup_uniform_float_copy(pd.viewer_attribute_pointcloud_grp, "opacity", opacity); - DRW_shgroup_call_instance_range(pd.viewer_attribute_pointcloud_grp, &object, batch, 0, 0); + GPUVertBuf **vertbuf = DRW_pointcloud_evaluated_attribute(pointcloud, ".viewer"); + DRWShadingGroup *grp = DRW_shgroup_pointcloud_create_sub( + &object, pd.viewer_attribute_pointcloud_grp, nullptr); + DRW_shgroup_uniform_float_copy(grp, "opacity", opacity); + DRW_shgroup_buffer_texture_ref(grp, "attribute_tx", vertbuf); } break; } @@ -135,7 +135,7 @@ static void populate_cache_for_geometry(Object &object, if (curves.attributes().contains(".viewer")) { GPUBatch *batch = DRW_cache_curve_edge_wire_viewer_attribute_get(&object); DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curve_grp, "opacity", opacity); - DRW_shgroup_call_obmat(pd.viewer_attribute_curve_grp, batch, object.obmat); + DRW_shgroup_call_obmat(pd.viewer_attribute_curve_grp, batch, object.object_to_world); } break; } @@ -144,13 +144,13 @@ static void populate_cache_for_geometry(Object &object, const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); if (curves.attributes().contains(".viewer")) { bool is_point_domain; - GPUTexture **texture = DRW_curves_texture_for_evaluated_attribute( + GPUVertBuf **texture = DRW_curves_texture_for_evaluated_attribute( curves_id, ".viewer", &is_point_domain); DRWShadingGroup *grp = DRW_shgroup_curves_create_sub( &object, pd.viewer_attribute_curves_grp, nullptr); DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curves_grp, "opacity", opacity); DRW_shgroup_uniform_bool_copy(grp, "is_point_domain", is_point_domain); - DRW_shgroup_uniform_texture(grp, "color_tx", *texture); + DRW_shgroup_buffer_texture(grp, "color_tx", *texture); } break; } diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.cc b/source/blender/draw/engines/overlay/overlay_wireframe.cc index bff1bf46923..7053d0039cf 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.cc +++ b/source/blender/draw/engines/overlay/overlay_wireframe.cc @@ -132,12 +132,12 @@ static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, Part if (collection != nullptr) { sub_v3_v3(dupli_mat[3], collection->instance_offset); } - mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, dupli_parent->object_to_world, dupli_mat); } else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + copy_m4_m4(dupli_mat, dupli_object->ob->object_to_world); invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, ob->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, ob->object_to_world, dupli_mat); } } else { @@ -217,7 +217,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, } if (geom) { - OVERLAY_extra_wire(cb, geom, ob->obmat, color); + OVERLAY_extra_wire(cb, geom, ob->object_to_world, color); } } @@ -230,12 +230,12 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, if (dupli->wire_shgrp == cb->extra_loose_points) { float *color; DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->obmat, color); + OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->object_to_world, color); } else if (dupli->wire_shgrp == cb->extra_wire) { float *color; DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - OVERLAY_extra_wire(cb, dupli->wire_geom, ob->obmat, color); + OVERLAY_extra_wire(cb, dupli->wire_geom, ob->object_to_world, color); } else { DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob); @@ -264,7 +264,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob); if (geom) { - OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); + OVERLAY_extra_loose_points(cb, geom, ob->object_to_world, color); } return; } @@ -276,7 +276,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, /* Don't do that in edit Mesh mode, unless there is a modifier preview. */ if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) { const bool is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != nullptr); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI); const bool instance_parent_in_edit_mode = is_instance ? DRW_object_is_in_edit_mode( @@ -318,14 +318,14 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, if (is_mesh_verts_only) { geom = DRW_cache_mesh_all_verts_get(ob); if (geom) { - OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); + OVERLAY_extra_loose_points(cb, geom, ob->object_to_world, color); shgrp = cb->extra_loose_points; } } else { geom = DRW_cache_mesh_loose_edges_get(ob); if (geom) { - OVERLAY_extra_wire(cb, geom, ob->obmat, color); + OVERLAY_extra_wire(cb, geom, ob->object_to_world, color); shgrp = cb->extra_wire; } } diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh index 20d4797b76f..6a0bd03f030 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh @@ -27,7 +27,7 @@ GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_pointcloud) .fragment_source("overlay_viewer_attribute_frag.glsl") .fragment_out(0, Type::VEC4, "out_color") .fragment_out(1, Type::VEC4, "lineOutput") - .vertex_in(3, Type::VEC4, "attribute_value") + .sampler(3, ImageType::FLOAT_BUFFER, "attribute_tx") .vertex_out(overlay_viewer_attribute_iface) .additional_info("overlay_viewer_attribute_common", "draw_pointcloud"); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl index 7d8fb0c2cb8..851e0884354 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl @@ -34,20 +34,7 @@ void main() float unused_strength; vec2 unused_uv; - gl_Position = gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - vec4(sizeViewport, sizeViewportInv), + gl_Position = gpencil_vertex(vec4(sizeViewport, sizeViewportInv), world_pos, unused_N, unused_color, diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl index e706e8f9033..e7b7cafd898 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl @@ -6,5 +6,5 @@ void main() { vec3 world_pos = pointcloud_get_pos(); gl_Position = point_world_to_ndc(world_pos); - finalColor = attribute_value; + finalColor = pointcloud_get_customdata_vec4(attribute_tx); } diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c index 026a1f52ac1..07e2a42b808 100644 --- a/source/blender/draw/engines/select/select_engine.c +++ b/source/blender/draw/engines/select/select_engine.c @@ -205,7 +205,7 @@ static void select_cache_populate(void *vedata, Object *ob) struct Mesh *me = ob->data; if (e_data.context.select_mode & SCE_SELECT_FACE) { struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->object_to_world); } else if (ob->dt >= OB_SOLID) { #ifdef USE_CAGE_OCCLUSION @@ -213,17 +213,17 @@ static void select_cache_populate(void *vedata, Object *ob) #else struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me); #endif - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->object_to_world); } if (e_data.context.select_mode & SCE_SELECT_EDGE) { struct GPUBatch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me); - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_edges, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_edges, ob->object_to_world); } if (e_data.context.select_mode & SCE_SELECT_VERTEX) { struct GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me); - DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_verts, ob->obmat); + DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_verts, ob->object_to_world); } return; } @@ -231,7 +231,7 @@ static void select_cache_populate(void *vedata, Object *ob) float min[3], max[3]; select_id_object_min_max(ob, min, max); - if (DRW_culling_min_max_test(stl->g_data->view_subregion, ob->obmat, min, max)) { + if (DRW_culling_min_max_test(stl->g_data->view_subregion, ob->object_to_world, min, max)) { if (sel_data == NULL) { sel_data = (SELECTID_ObjectData *)DRW_drawdata_ensure( &ob->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), NULL, NULL); diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index fecdad5802c..15a16539a26 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -27,6 +27,7 @@ #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_node_types.h" +#include "DNA_pointcloud_types.h" #include "ED_paint.h" @@ -266,7 +267,7 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, const DRWContextState *draw_ctx = DRW_context_state_get(); const bool is_active = (ob == draw_ctx->obact); - const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) && !DRW_state_is_image_render(); const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == NULL); const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE); @@ -418,7 +419,7 @@ void workbench_cache_populate(void *ved, Object *ob) return; } - if (ELEM(ob->type, OB_MESH, OB_POINTCLOUD)) { + if (ob->type == OB_MESH) { bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false; eV3DShadingColorType color_type = workbench_color_type_get( wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow); @@ -442,6 +443,12 @@ void workbench_cache_populate(void *ved, Object *ob) DRWShadingGroup *grp = workbench_material_hair_setup(wpd, ob, CURVES_MATERIAL_NR, color_type); DRW_shgroup_curves_create_sub(ob, grp, NULL); } + else if (ob->type == OB_POINTCLOUD) { + int color_type = workbench_color_type_get(wpd, ob, NULL, NULL, NULL); + DRWShadingGroup *grp = workbench_material_ptcloud_setup( + wpd, ob, POINTCLOUD_MATERIAL_NR, color_type); + DRW_shgroup_pointcloud_create_sub(ob, grp, NULL); + } else if (ob->type == OB_VOLUME) { if (wpd->shading.type != OB_WIRE) { int color_type = workbench_color_type_get(wpd, ob, NULL, NULL, NULL); diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 492bce1e571..4aedaf443b9 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -511,6 +511,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, #define workbench_image_hair_setup(wpd, ob, mat_nr, ima, iuser, interp) \ workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_HAIR) +#define workbench_material_ptcloud_setup(wpd, ob, mat_nr, color_type) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, WORKBENCH_DATATYPE_POINTCLOUD, 0) +#define workbench_image_ptcloud_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_POINTCLOUD) + /* workbench_data.c */ void workbench_private_data_alloc(WORKBENCH_StorageList *stl); diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c index 0b34e849049..eb4d546648a 100644 --- a/source/blender/draw/engines/workbench/workbench_shadow.c +++ b/source/blender/draw/engines/workbench/workbench_shadow.c @@ -172,7 +172,7 @@ static const BoundBox *workbench_shadow_object_shadow_bbox_get(WORKBENCH_Private { if (oed->shadow_bbox_dirty || wpd->shadow_changed) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat); + mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->object_to_world); /* Get AABB in shadow space. */ INIT_MINMAX(oed->shadow_min, oed->shadow_max); diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index ce7773e7439..7c6df93f5a3 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -237,7 +237,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata, /* Combined texture to object, and object to world transform. */ float texture_to_world[4][4]; - mul_m4_m4m4(texture_to_world, ob->obmat, grid->texture_to_object); + mul_m4_m4m4(texture_to_world, ob->object_to_world, grid->texture_to_object); if (use_slice) { float invviewmat[4][4]; @@ -291,7 +291,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata, /* Compute density scale. */ const float density_scale = volume->display.density * - BKE_volume_density_scale(volume, ob->obmat); + BKE_volume_density_scale(volume, ob->object_to_world); DRW_shgroup_uniform_texture(grp, "densityTexture", grid->texture); /* TODO: implement shadow texture, see manta_smoke_calc_transparency. */ diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 8c6a51442e1..00ac2563c43 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -899,8 +899,6 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) switch (ob->type) { case OB_MESH: return DRW_cache_mesh_surface_get(ob); - case OB_POINTCLOUD: - return DRW_cache_pointcloud_surface_get(ob); default: return NULL; } @@ -959,8 +957,6 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, switch (ob->type) { case OB_MESH: return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len); - case OB_POINTCLOUD: - return DRW_cache_pointcloud_surface_shaded_get(ob, gpumat_array, gpumat_array_len); default: return NULL; } @@ -3006,24 +3002,6 @@ GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob) /** \name PointCloud * \{ */ -GPUBatch *DRW_cache_pointcloud_get_dots(Object *object) -{ - BLI_assert(object->type == OB_POINTCLOUD); - return DRW_pointcloud_batch_cache_get_dots(object); -} - -GPUBatch *DRW_cache_pointcloud_surface_get(Object *object) -{ - BLI_assert(object->type == OB_POINTCLOUD); - return DRW_pointcloud_batch_cache_get_surface(object); -} - -GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(Object *object) -{ - BLI_assert(object->type == OB_POINTCLOUD); - return DRW_pointcloud_batch_cache_get_surface_viewer_attribute(object); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -3308,6 +3286,9 @@ void drw_batch_cache_generate_requested(Object *ob) case OB_CURVES: DRW_curves_batch_cache_create_requested(ob); break; + case OB_POINTCLOUD: + DRW_pointcloud_batch_cache_create_requested(ob); + break; /* TODO: all cases. */ default: break; @@ -3358,7 +3339,9 @@ void DRW_batch_cache_free_old(Object *ob, int ctime) case OB_CURVES: DRW_curves_batch_cache_free_old((Curves *)ob->data, ctime); break; - /* TODO: all cases. */ + case OB_POINTCLOUD: + DRW_pointcloud_batch_cache_free_old((PointCloud *)ob->data, ctime); + break; default: break; } diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 058f28f094d..772cf3b12a5 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -13,6 +13,7 @@ extern "C" { struct GPUBatch; struct GPUMaterial; +struct GPUVertBuf; struct ModifierData; struct Object; struct PTCacheEdit; @@ -224,12 +225,6 @@ struct GPUBatch **DRW_cache_curves_surface_shaded_get(struct Object *ob, struct GPUBatch *DRW_cache_curves_face_wireframe_get(struct Object *ob); struct GPUBatch *DRW_cache_curves_edge_detection_get(struct Object *ob, bool *r_is_manifold); -/* PointCloud */ - -struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj); -struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj); -struct GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(struct Object *obj); - /* Volume */ typedef struct DRWVolumeGrid { @@ -257,14 +252,17 @@ struct GPUBatch *DRW_cache_volume_selection_surface_get(struct Object *ob); /* GPencil */ -struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra); -struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra); +struct GPUBatch *DRW_cache_gpencil_get(struct Object *ob, int cfra); +struct GPUVertBuf *DRW_cache_gpencil_position_buffer_get(struct Object *ob, int cfra); +struct GPUVertBuf *DRW_cache_gpencil_color_buffer_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_points_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_curve_handles_get(struct Object *ob, int cfra); struct GPUBatch *DRW_cache_gpencil_edit_curve_points_get(struct Object *ob, int cfra); -struct GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(struct Object *ob); -struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob); +struct GPUBatch *DRW_cache_gpencil_sbuffer_get(struct Object *ob, bool show_fill); +struct GPUVertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(struct Object *ob, + bool show_fill); +struct GPUVertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(struct Object *ob, bool show_fill); int DRW_gpencil_material_count_get(struct bGPdata *gpd); struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index c6e8539121f..5aa2203ca68 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -80,6 +80,7 @@ void DRW_batch_cache_free_old(struct Object *ob, int ctime); */ void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime); void DRW_curves_batch_cache_free_old(struct Curves *curves, int ctime); +void DRW_pointcloud_batch_cache_free_old(struct PointCloud *pointcloud, int ctime); /** \} */ @@ -131,7 +132,7 @@ int DRW_curves_material_count_get(struct Curves *curves); * \return A pointer to location where the texture will be * stored, which will be filled by #DRW_shgroup_curves_create_sub. */ -struct GPUTexture **DRW_curves_texture_for_evaluated_attribute(struct Curves *curves, +struct GPUVertBuf **DRW_curves_texture_for_evaluated_attribute(struct Curves *curves, const char *name, bool *r_is_point_domain); @@ -147,12 +148,11 @@ void DRW_curves_batch_cache_create_requested(struct Object *ob); int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud); +struct GPUVertBuf **DRW_pointcloud_evaluated_attribute(struct PointCloud *pointcloud, + const char *name); struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob); -struct GPUBatch *DRW_pointcloud_batch_cache_get_surface(struct Object *ob); -struct GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(struct Object *ob); -struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob, - struct GPUMaterial **gpumat_array, - uint gpumat_array_len); + +void DRW_pointcloud_batch_cache_create_requested(struct Object *ob); /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 85dd9ca8695..c36b90ec32e 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -88,13 +88,11 @@ static void curves_discard_attributes(CurvesEvalCache &curves_cache) { for (const int i : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]); - DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]); } for (const int i : IndexRange(MAX_HAIR_SUBDIV)) { for (const int j : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]); - DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]); } drw_attributes_clear(&curves_cache.final[i].attr_used); @@ -107,17 +105,12 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache) GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_point_buf); GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_length_buf); GPU_VERTBUF_DISCARD_SAFE(curves_cache.data_edit_points); - DRW_TEXTURE_FREE_SAFE(curves_cache.point_tex); - DRW_TEXTURE_FREE_SAFE(curves_cache.length_tex); GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_buf); GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_seg_buf); - DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex); - DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex); for (const int i : IndexRange(MAX_HAIR_SUBDIV)) { GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf); - DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex); for (const int j : IndexRange(MAX_THICKRES)) { GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]); } @@ -286,21 +279,6 @@ static void curves_batch_cache_ensure_procedural_pos(const Curves &curves, cache.strands_len}; curves_batch_cache_fill_segments_proc_pos(curves, posTime_data, hairLength_data); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache.proc_point_buf); - cache.point_tex = GPU_texture_create_from_vertbuf("hair_point", cache.proc_point_buf); - } - - if (gpu_material && cache.proc_length_buf != nullptr && cache.length_tex) { - ListBase gpu_attrs = GPU_material_attributes(gpu_material); - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { - if (attr->type == CD_HAIRLENGTH) { - GPU_vertbuf_use(cache.proc_length_buf); - cache.length_tex = GPU_texture_create_from_vertbuf("hair_length", cache.proc_length_buf); - break; - } - } } } @@ -363,12 +341,6 @@ static void curves_batch_cache_ensure_procedural_final_attr(CurvesEvalCache &cac /* Those are points! not line segments. */ GPU_vertbuf_data_alloc(final_cache.attributes_buf[index], final_cache.strands_res * cache.strands_len); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(final_cache.attributes_buf[index]); - - final_cache.attributes_tex[index] = GPU_texture_create_from_vertbuf( - name, final_cache.attributes_buf[index]); } static void curves_batch_ensure_attribute(const Curves &curves, @@ -379,7 +351,6 @@ static void curves_batch_ensure_attribute(const Curves &curves, { using namespace blender; GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]); - DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]); char sampler_name[32]; drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name); @@ -414,13 +385,9 @@ static void curves_batch_ensure_attribute(const Curves &curves, attribute.materialize(vbo_span); - GPU_vertbuf_use(attr_vbo); - cache.proc_attributes_tex[index] = GPU_texture_create_from_vertbuf(sampler_name, attr_vbo); - /* Existing final data may have been for a different attribute (with a different name or domain), * free the data. */ GPU_VERTBUF_DISCARD_SAFE(cache.final[subdiv].attributes_buf[index]); - DRW_TEXTURE_FREE_SAFE(cache.final[subdiv].attributes_tex[index]); /* Ensure final data for points. */ if (request.domain == ATTR_DOMAIN_POINT) { @@ -466,19 +433,11 @@ static void curves_batch_cache_ensure_procedural_strand_data(Curves &curves, GPU_vertbuf_attr_get_raw_data(cache.proc_strand_seg_buf, seg_id, &seg_step); curves_batch_cache_fill_strands_data(curves, data_step, seg_step); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache.proc_strand_buf); - cache.strand_tex = GPU_texture_create_from_vertbuf("curves_strand", cache.proc_strand_buf); - - GPU_vertbuf_use(cache.proc_strand_seg_buf); - cache.strand_seg_tex = GPU_texture_create_from_vertbuf("curves_strand_seg", - cache.proc_strand_seg_buf); } static void curves_batch_cache_ensure_procedural_final_points(CurvesEvalCache &cache, int subdiv) { - /* Same format as point_tex. */ + /* Same format as proc_point_buf. */ GPUVertFormat format = {0}; GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -489,12 +448,6 @@ static void curves_batch_cache_ensure_procedural_final_points(CurvesEvalCache &c /* Those are points! not line segments. */ GPU_vertbuf_data_alloc(cache.final[subdiv].proc_buf, cache.final[subdiv].strands_res * cache.strands_len); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache.final[subdiv].proc_buf); - - cache.final[subdiv].proc_tex = GPU_texture_create_from_vertbuf("hair_proc", - cache.final[subdiv].proc_buf); } static void curves_batch_cache_fill_segments_indices(const Curves &curves, @@ -583,7 +536,6 @@ static bool curves_ensure_attributes(const Curves &curves, /* Some new attributes have been added, free all and start over. */ for (const int i : IndexRange(GPU_MAX_ATTR)) { GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]); - DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]); } drw_attributes_merge(&final_cache.attr_used, &attrs_needed, cache.render_mutex); } @@ -631,7 +583,7 @@ bool curves_ensure_procedural_data(Curves *curves, } /* Refreshed if active layer or custom data changes. */ - if ((*r_hair_cache)->strand_tex == nullptr) { + if ((*r_hair_cache)->proc_strand_buf == nullptr) { curves_batch_cache_ensure_procedural_strand_data(*curves, cache.curves_cache); } @@ -689,7 +641,7 @@ static void request_attribute(Curves &curves, const char *name) drw_attributes_merge(&final_cache.attr_used, &attributes, cache.render_mutex); } -GPUTexture **DRW_curves_texture_for_evaluated_attribute(Curves *curves, +GPUVertBuf **DRW_curves_texture_for_evaluated_attribute(Curves *curves, const char *name, bool *r_is_point_domain) { @@ -715,10 +667,10 @@ GPUTexture **DRW_curves_texture_for_evaluated_attribute(Curves *curves, switch (final_cache.attr_used.requests[request_i].domain) { case ATTR_DOMAIN_POINT: *r_is_point_domain = true; - return &final_cache.attributes_tex[request_i]; + return &final_cache.attributes_buf[request_i]; case ATTR_DOMAIN_CURVE: *r_is_point_domain = false; - return &cache.curves_cache.proc_attributes_tex[request_i]; + return &cache.curves_cache.proc_attributes_buf[request_i]; default: BLI_assert_unreachable(); return nullptr; diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.cc index 7a43c7ee2e6..3d6d2631186 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.cc @@ -23,12 +23,14 @@ #include "DEG_depsgraph_query.h" #include "BLI_hash.h" +#include "BLI_math_vec_types.hh" #include "BLI_polyfill_2d.h" #include "draw_cache.h" #include "draw_cache_impl.h" #include "../engines/gpencil/gpencil_defines.h" +#include "../engines/gpencil/gpencil_shader_shared.h" #define BEZIER_HANDLE (1 << 3) #define COLOR_SHIFT 5 @@ -41,11 +43,13 @@ typedef struct GpencilBatchCache { /** Instancing Data */ GPUVertBuf *vbo; GPUVertBuf *vbo_col; - /** Fill Topology */ + /** Indices in material order, then stroke order with fill first. + * Strokes can be individually rendered using `gps->runtime.stroke_start` and + * `gps->runtime.fill_start`. */ GPUIndexBuf *ibo; - /** Instancing Batches */ - GPUBatch *stroke_batch; - GPUBatch *fill_batch; + /** Batches */ + GPUBatch *geom_batch; + /** Stroke lines only */ GPUBatch *lines_batch; /** Edit Mode */ @@ -97,7 +101,8 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) GpencilBatchCache *cache = gpd->runtime.gpencil_cache; if (!cache) { - cache = gpd->runtime.gpencil_cache = MEM_callocN(sizeof(*cache), __func__); + cache = gpd->runtime.gpencil_cache = (GpencilBatchCache *)MEM_callocN(sizeof(*cache), + __func__); } else { memset(cache, 0, sizeof(*cache)); @@ -116,8 +121,7 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache) } GPU_BATCH_DISCARD_SAFE(cache->lines_batch); - GPU_BATCH_DISCARD_SAFE(cache->fill_batch); - GPU_BATCH_DISCARD_SAFE(cache->stroke_batch); + GPU_BATCH_DISCARD_SAFE(cache->geom_batch); GPU_VERTBUF_DISCARD_SAFE(cache->vbo); GPU_VERTBUF_DISCARD_SAFE(cache->vbo_col); GPU_INDEXBUF_DISCARD_SAFE(cache->ibo); @@ -172,9 +176,10 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd) /* MUST match the format below. */ typedef struct gpStrokeVert { - int32_t mat, stroke_id, point_id, packed_asp_hard_rot; /** Position and thickness packed in the same attribute. */ float pos[3], thickness; + /** Material Index, Stroke Index, Point Index, Packed aspect + hardness + rotation. */ + int32_t mat, stroke_id, point_id, packed_asp_hard_rot; /** UV and strength packed in the same attribute. */ float uv_fill[2], u_stroke, strength; } gpStrokeVert; @@ -183,12 +188,9 @@ static GPUVertFormat *gpencil_stroke_format(void) { static GPUVertFormat format = {0}; if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT); GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT); GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - /* IMPORTANT: This means having only 4 attributes - * to fit into GPU module limit of 16 attributes. */ - GPU_vertformat_multiload_enable(&format, 4); } return &format; } @@ -238,9 +240,6 @@ static GPUVertFormat *gpencil_color_format(void) if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "col", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); GPU_vertformat_attr_add(&format, "fcol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - /* IMPORTANT: This means having only 4 attributes - * to fit into GPU module limit of 16 attributes. */ - GPU_vertformat_multiload_enable(&format, 4); } return &format; } @@ -295,7 +294,8 @@ BLI_INLINE int32_t pack_rotation_aspect_hardness(float rot, float asp, float har return packed; } -static void gpencil_buffer_add_point(gpStrokeVert *verts, +static void gpencil_buffer_add_point(GPUIndexBufBuilder *ibo, + gpStrokeVert *verts, gpColorVert *cols, const bGPDstroke *gps, const bGPDspoint *pt, @@ -319,7 +319,7 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts, vert->strength = (round_cap0) ? pt->strength : -pt->strength; vert->u_stroke = pt->uv_fac; - vert->stroke_id = gps->runtime.stroke_start; + vert->stroke_id = gps->runtime.vertex_start; vert->point_id = v; vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f); /* Tag endpoint material to -1 so they get discarded by vertex shader. */ @@ -329,27 +329,36 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts, vert->packed_asp_hard_rot = pack_rotation_aspect_hardness( pt->uv_rot, aspect_ratio, gps->hardeness); + + if (!is_endpoint) { + /* Issue a Quad per point. */ + /* The attribute loading uses a different shader and will undo this bit packing. */ + int v_mat = (v << GP_VERTEX_ID_SHIFT) | GP_IS_STROKE_VERTEX_BIT; + GPU_indexbuf_add_tri_verts(ibo, v_mat + 0, v_mat + 1, v_mat + 2); + GPU_indexbuf_add_tri_verts(ibo, v_mat + 2, v_mat + 1, v_mat + 3); + } } -static void gpencil_buffer_add_stroke(gpStrokeVert *verts, +static void gpencil_buffer_add_stroke(GPUIndexBufBuilder *ibo, + gpStrokeVert *verts, gpColorVert *cols, const bGPDstroke *gps) { const bGPDspoint *pts = gps->points; int pts_len = gps->totpoints; bool is_cyclic = gpencil_stroke_is_cyclic(gps); - int v = gps->runtime.stroke_start; + int v = gps->runtime.vertex_start; /* First point for adjacency (not drawn). */ int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1); - gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true); for (int i = 0; i < pts_len; i++) { - gpencil_buffer_add_point(verts, cols, gps, &pts[i], v++, false); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[i], v++, false); } /* Draw line to first point to complete the loop for cyclic strokes. */ if (is_cyclic) { - gpencil_buffer_add_point(verts, cols, gps, &pts[0], v, false); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[0], v, false); /* UV factor needs to be adjusted for the last point to not be equal to the UV factor of the * first point. It should be the factor of the last point plus the distance from the last point * to the first. @@ -360,16 +369,20 @@ static void gpencil_buffer_add_stroke(gpStrokeVert *verts, } /* Last adjacency point (not drawn). */ adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2); - gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true); + gpencil_buffer_add_point(ibo, verts, cols, gps, &pts[adj_idx], v++, true); } static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps) { int tri_len = gps->tot_triangles; - int v = gps->runtime.stroke_start; + int v = gps->runtime.vertex_start + 1; for (int i = 0; i < tri_len; i++) { uint *tri = gps->triangles[i].verts; - GPU_indexbuf_add_tri_verts(ibo, v + tri[0], v + tri[1], v + tri[2]); + /* The attribute loading uses a different shader and will undo this bit packing. */ + GPU_indexbuf_add_tri_verts(ibo, + (v + tri[0]) << GP_VERTEX_ID_SHIFT, + (v + tri[1]) << GP_VERTEX_ID_SHIFT, + (v + tri[2]) << GP_VERTEX_ID_SHIFT); } } @@ -379,10 +392,10 @@ static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl), void *thunk) { gpIterData *iter = (gpIterData *)thunk; - gpencil_buffer_add_stroke(iter->verts, iter->cols, gps); if (gps->tot_triangles > 0) { gpencil_buffer_add_fill(&iter->ibo, gps); } + gpencil_buffer_add_stroke(&iter->ibo, iter->verts, iter->cols, gps); } static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), @@ -391,12 +404,15 @@ static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), void *thunk) { gpIterData *iter = (gpIterData *)thunk; - - /* Store first index offset */ - gps->runtime.stroke_start = iter->vert_len; + int stroke_vert_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); + gps->runtime.vertex_start = iter->vert_len; + /* Add additional padding at the start and end. */ + iter->vert_len += 1 + stroke_vert_len + 1; + /* Store first index offset. */ gps->runtime.fill_start = iter->tri_len; - iter->vert_len += gps->totpoints + 2 + gpencil_stroke_is_cyclic(gps); iter->tri_len += gps->tot_triangles; + gps->runtime.stroke_start = iter->tri_len; + iter->tri_len += stroke_vert_len * 2; } static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra) @@ -406,7 +422,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr if (cache->vbo == NULL) { /* Should be discarded together. */ BLI_assert(cache->vbo == NULL && cache->ibo == NULL); - BLI_assert(cache->fill_batch == NULL && cache->stroke_batch == NULL); + BLI_assert(cache->geom_batch == NULL); /* TODO/PERF: Could be changed to only do it if needed. * For now it's simpler to assume we always need it * since multiple viewport could or could not need it. @@ -415,29 +431,29 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr bool do_onion = true; /* First count how many vertices and triangles are needed for the whole object. */ - gpIterData iter = { - .gpd = gpd, - .verts = NULL, - .ibo = {0}, - .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */ - .tri_len = 0, - .curve_len = 0, - }; + gpIterData iter = {}; + iter.gpd = gpd; + iter.verts = NULL; + iter.ibo = {0}; + iter.vert_len = 0; + iter.tri_len = 0; + iter.curve_len = 0; BKE_gpencil_visible_stroke_advanced_iter( NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra); + GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; /* Create VBOs. */ GPUVertFormat *format = gpencil_stroke_format(); GPUVertFormat *format_col = gpencil_color_format(); - cache->vbo = GPU_vertbuf_create_with_format(format); - cache->vbo_col = GPU_vertbuf_create_with_format(format_col); + cache->vbo = GPU_vertbuf_create_with_format_ex(format, vbo_flag); + cache->vbo_col = GPU_vertbuf_create_with_format_ex(format_col, vbo_flag); /* Add extra space at the end of the buffer because of quad load. */ GPU_vertbuf_data_alloc(cache->vbo, iter.vert_len + 2); GPU_vertbuf_data_alloc(cache->vbo_col, iter.vert_len + 2); iter.verts = (gpStrokeVert *)GPU_vertbuf_get_data(cache->vbo); iter.cols = (gpColorVert *)GPU_vertbuf_get_data(cache->vbo_col); /* Create IBO. */ - GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len); + GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, 0xFFFFFFFFu); /* Fill buffers with data. */ BKE_gpencil_visible_stroke_advanced_iter( @@ -452,33 +468,39 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr /* Finish the IBO. */ cache->ibo = GPU_indexbuf_build(&iter.ibo); - /* Create the batches */ - cache->fill_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo); - GPU_batch_vertbuf_add(cache->fill_batch, cache->vbo_col); - cache->stroke_batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL); - GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo, 0); - GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo_col, 0); + cache->geom_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo); + /* Allow creation of buffer texture. */ + GPU_vertbuf_use(cache->vbo); + GPU_vertbuf_use(cache->vbo_col); gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; cache->is_dirty = false; } } -GPUBatch *DRW_cache_gpencil_strokes_get(Object *ob, int cfra) +GPUBatch *DRW_cache_gpencil_get(Object *ob, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); + gpencil_batches_ensure(ob, cache, cfra); + + return cache->geom_batch; +} + +GPUVertBuf *DRW_cache_gpencil_position_buffer_get(Object *ob, int cfra) { GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); gpencil_batches_ensure(ob, cache, cfra); - return cache->stroke_batch; + return cache->vbo; } -GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra) +GPUVertBuf *DRW_cache_gpencil_color_buffer_get(Object *ob, int cfra) { GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); gpencil_batches_ensure(ob, cache, cfra); - return cache->fill_batch; + return cache->vbo_col; } static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), @@ -489,7 +511,7 @@ static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), gpIterData *iter = (gpIterData *)thunk; int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); - int start = gps->runtime.stroke_start + 1; + int start = gps->runtime.vertex_start + 1; int end = start + pts_len; for (int i = start; i < end; i++) { GPU_indexbuf_add_generic_vert(&iter->ibo, i); @@ -508,10 +530,9 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) if (cache->lines_batch == NULL) { GPUVertBuf *vbo = cache->vbo; - gpIterData iter = { - .gpd = ob->data, - .ibo = {0}, - }; + gpIterData iter = {}; + iter.gpd = (bGPdata *)ob->data; + iter.ibo = {0}; uint vert_len = GPU_vertbuf_get_vertex_len(vbo); GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vert_len, vert_len); @@ -540,7 +561,7 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob) Brush *brush = gpd->runtime.sbuffer_brush; /* Convert the sbuffer to a bGPDstroke. */ if (gpd->runtime.sbuffer_gps == NULL) { - bGPDstroke *gps = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer"); + bGPDstroke *gps = (bGPDstroke *)MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer"); gps->totpoints = gpd->runtime.sbuffer_used; gps->mat_nr = max_ii(0, gpd->runtime.matid - 1); gps->flag = gpd->runtime.sbuffer_sflag; @@ -553,7 +574,9 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob) gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2); gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND; - gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */ + gps->runtime.vertex_start = 0; + gps->runtime.fill_start = 0; + gps->runtime.stroke_start = 0; copy_v4_v4(gps->vert_color_fill, gpd->runtime.vert_color_fill); /* Caps. */ gps->caps[0] = gps->caps[1] = (short)brush->gpencil_settings->caps_type; @@ -563,17 +586,17 @@ bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob) return gpd->runtime.sbuffer_gps; } -static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill) +static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_fill) { - tGPspoint *tpoints = gpd->runtime.sbuffer; + tGPspoint *tpoints = (tGPspoint *)gpd->runtime.sbuffer; bGPDstroke *gps = gpd->runtime.sbuffer_gps; int vert_len = gpd->runtime.sbuffer_used; /* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */ BLI_assert(gps != NULL); - if (do_stroke && (gpd->runtime.sbuffer_stroke_batch == NULL)) { - gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__); + if (gpd->runtime.sbuffer_batch == NULL) { + gps->points = (bGPDspoint *)MEM_mallocN(vert_len * sizeof(*gps->points), __func__); const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; @@ -596,36 +619,25 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_ /* Calc uv data along the stroke. */ BKE_gpencil_stroke_uv_update(gps); + int tri_len = gps->tot_triangles + (gps->totpoints + gpencil_stroke_is_cyclic(gps)) * 2; + /* Create IBO. */ + GPUIndexBufBuilder ibo_builder; + GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, tri_len, 0xFFFFFFFFu); /* Create VBO. */ + GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; GPUVertFormat *format = gpencil_stroke_format(); GPUVertFormat *format_color = gpencil_color_format(); - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(format); - GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(format_color); - /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */ + GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(format, vbo_flag); + GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format_ex(format_color, vbo_flag); + /* Add extra space at the start and end the buffer because of quad load and cyclic. */ GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2); GPU_vertbuf_data_alloc(vbo_col, 1 + vert_len + 1 + 2); gpStrokeVert *verts = (gpStrokeVert *)GPU_vertbuf_get_data(vbo); gpColorVert *cols = (gpColorVert *)GPU_vertbuf_get_data(vbo_col); - /* Fill buffers with data. */ - gpencil_buffer_add_stroke(verts, cols, gps); - - GPUBatch *batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL); - GPU_batch_instbuf_add_ex(batch, vbo, true); - GPU_batch_instbuf_add_ex(batch, vbo_col, true); - - gpd->runtime.sbuffer_stroke_batch = batch; - - MEM_freeN(gps->points); - } - - if (do_fill && (gpd->runtime.sbuffer_fill_batch == NULL)) { - /* Create IBO. */ - GPUIndexBufBuilder ibo_builder; - GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len); - - if (gps->tot_triangles > 0) { - float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__); + /* Create fill indices. */ + if (do_fill && gps->tot_triangles > 0) { + float(*tpoints2d)[2] = (float(*)[2])MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__); /* Triangulate in 2D. */ for (int i = 0; i < vert_len; i++) { copy_v2_v2(tpoints2d[i], tpoints[i].m_xy); @@ -633,51 +645,72 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_ /* Compute directly inside the IBO data buffer. */ /* OPTI: This is a bottleneck if the stroke is very long. */ BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data); - /* Add stroke start offset. */ + /* Add stroke start offset and shift. */ for (int i = 0; i < gps->tot_triangles * 3; i++) { - ibo_builder.data[i] += gps->runtime.stroke_start; + ibo_builder.data[i] = (ibo_builder.data[i] + 1) << GP_VERTEX_ID_SHIFT; } /* HACK since we didn't use the builder API to avoid another malloc and copy, * we need to set the number of indices manually. */ ibo_builder.index_len = gps->tot_triangles * 3; + ibo_builder.index_min = 0; + /* For this case, do not allow index compaction to avoid yet another preprocessing step. */ + ibo_builder.index_max = 0xFFFFFFFFu - 1u; + + gps->runtime.stroke_start = gps->tot_triangles; MEM_freeN(tpoints2d); } - GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder); - GPUVertBuf *vbo = gpd->runtime.sbuffer_stroke_batch->inst[0]; - GPUVertBuf *vbo_col = gpd->runtime.sbuffer_stroke_batch->inst[1]; + /* Fill buffers with data. */ + gpencil_buffer_add_stroke(&ibo_builder, verts, cols, gps); - GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_INDEX); - GPU_batch_vertbuf_add(batch, vbo_col); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, + gpencil_dummy_buffer_get(), + GPU_indexbuf_build(&ibo_builder), + GPU_BATCH_OWNS_INDEX); - gpd->runtime.sbuffer_fill_batch = batch; + gpd->runtime.sbuffer_position_buf = vbo; + gpd->runtime.sbuffer_color_buf = vbo_col; + gpd->runtime.sbuffer_batch = batch; + + MEM_freeN(gps->points); } } -GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(Object *ob) +GPUBatch *DRW_cache_gpencil_sbuffer_get(Object *ob, bool show_fill) { bGPdata *gpd = (bGPdata *)ob->data; - gpencil_sbuffer_stroke_ensure(gpd, true, false); + /* Fill batch also need stroke batch to be created (vbo is shared). */ + gpencil_sbuffer_stroke_ensure(gpd, show_fill); - return gpd->runtime.sbuffer_stroke_batch; + return gpd->runtime.sbuffer_batch; } -GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob) +GPUVertBuf *DRW_cache_gpencil_sbuffer_position_buffer_get(Object *ob, bool show_fill) { bGPdata *gpd = (bGPdata *)ob->data; /* Fill batch also need stroke batch to be created (vbo is shared). */ - gpencil_sbuffer_stroke_ensure(gpd, true, true); + gpencil_sbuffer_stroke_ensure(gpd, show_fill); - return gpd->runtime.sbuffer_fill_batch; + return gpd->runtime.sbuffer_position_buf; +} + +GPUVertBuf *DRW_cache_gpencil_sbuffer_color_buffer_get(Object *ob, bool show_fill) +{ + bGPdata *gpd = (bGPdata *)ob->data; + /* Fill batch also need stroke batch to be created (vbo is shared). */ + gpencil_sbuffer_stroke_ensure(gpd, show_fill); + + return gpd->runtime.sbuffer_color_buf; } void DRW_cache_gpencil_sbuffer_clear(Object *ob) { bGPdata *gpd = (bGPdata *)ob->data; MEM_SAFE_FREE(gpd->runtime.sbuffer_gps); - GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_fill_batch); - GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_stroke_batch); + GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_batch); + GPU_VERTBUF_DISCARD_SAFE(gpd->runtime.sbuffer_position_buf); + GPU_VERTBUF_DISCARD_SAFE(gpd->runtime.sbuffer_color_buf); } /** \} */ @@ -728,7 +761,7 @@ static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl, { gpEditIterData *iter = (gpEditIterData *)thunk; const int v_len = gps->totpoints; - const int v = gps->runtime.stroke_start + 1; + const int v = gps->runtime.vertex_start + 1; MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : NULL; gpEditVert *vert_ptr = iter->verts + v; @@ -743,9 +776,12 @@ static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl, vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex); vert_ptr++; } - /* Draw line to first point to complete the loop for cyclic strokes. */ - vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len); - vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex); + + if (gpencil_stroke_is_cyclic(gps)) { + /* Draw line to first point to complete the loop for cyclic strokes. */ + vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len); + vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex); + } } static void gpencil_edit_curve_stroke_count_cb(bGPDlayer *gpl, @@ -876,14 +912,13 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in /* Curve Handles and Points for Editing. */ if (cache->edit_curve_vbo == NULL) { - gpIterData iterdata = { - .gpd = gpd, - .verts = NULL, - .ibo = {0}, - .vert_len = 0, - .tri_len = 0, - .curve_len = 0, - }; + gpIterData iterdata = {}; + iterdata.gpd = gpd; + iterdata.verts = NULL; + iterdata.ibo = {0}; + iterdata.vert_len = 0; + iterdata.tri_len = 0; + iterdata.curve_len = 0; /* Create VBO. */ GPUVertFormat *format = gpencil_edit_curve_format(); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index 5ce658abfe4..031de3e4ef2 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -1889,7 +1889,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, false, true, scene, @@ -1906,7 +1906,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, false, false, scene, @@ -1922,7 +1922,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, true, false, do_cage, @@ -1943,7 +1943,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, is_editmode, is_paint_mode, is_mode_active, - ob->obmat, + ob->object_to_world, true, false, scene, diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index 9c1784b1de2..8facea4333f 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -173,13 +173,9 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) /* TODO: more granular update tagging. */ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_length_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex); - DRW_TEXTURE_FREE_SAFE(hair_cache->length_tex); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_seg_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex); - DRW_TEXTURE_FREE_SAFE(hair_cache->strand_seg_tex); for (int i = 0; i < MAX_MTFACE; i++) { GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]); @@ -192,7 +188,6 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) for (int i = 0; i < MAX_HAIR_SUBDIV; i++) { GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex); for (int j = 0; j < MAX_THICKRES; j++) { GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]); } @@ -810,7 +805,7 @@ static int particle_batch_cache_fill_strands_data(ParticleSystem *psys, static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, int subdiv) { - /* Same format as point_tex. */ + /* Same format as proc_point_buf. */ GPUVertFormat format = {0}; GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -823,12 +818,6 @@ static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCach /* Those are points! not line segments. */ GPU_vertbuf_data_alloc(cache->final[subdiv].proc_buf, cache->final[subdiv].strands_res * cache->strands_len); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->final[subdiv].proc_buf); - - cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf("part_proc", - cache->final[subdiv].proc_buf); } static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit, @@ -1034,14 +1023,6 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit MEM_freeN(parent_mcol); } - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_strand_buf); - cache->strand_tex = GPU_texture_create_from_vertbuf("part_strand", cache->proc_strand_buf); - - GPU_vertbuf_use(cache->proc_strand_seg_buf); - cache->strand_seg_tex = GPU_texture_create_from_vertbuf("part_strand_seg", - cache->proc_strand_seg_buf); - for (int i = 0; i < cache->num_uv_layers; i++) { GPU_vertbuf_use(cache->proc_uv_buf[i]); cache->uv_tex[i] = GPU_texture_create_from_vertbuf("part_uv", cache->proc_uv_buf[i]); @@ -1107,7 +1088,7 @@ static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *cache, - GPUMaterial *gpu_material) + GPUMaterial *UNUSED(gpu_material)) { if (cache->proc_point_buf == NULL) { /* initialize vertex format */ @@ -1149,22 +1130,6 @@ static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, psys->childcache, child_count, &pos_step, &length_step); } } - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_point_buf); - cache->point_tex = GPU_texture_create_from_vertbuf("part_point", cache->proc_point_buf); - } - - /* Checking hair length separately, only allocating gpu memory when needed. */ - if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex == NULL) { - ListBase gpu_attrs = GPU_material_attributes(gpu_material); - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { - if (attr->type == CD_HAIRLENGTH) { - GPU_vertbuf_use(cache->proc_length_buf); - cache->length_tex = GPU_texture_create_from_vertbuf("hair_length", cache->proc_length_buf); - break; - } - } } } @@ -1722,7 +1687,7 @@ bool particles_ensure_procedural_data(Object *object, /* Refreshed on combing and simulation. */ if ((*r_hair_cache)->proc_point_buf == NULL || - (gpu_material && (*r_hair_cache)->length_tex == NULL)) { + (gpu_material && (*r_hair_cache)->proc_length_buf == NULL)) { ensure_seg_pt_count(source.edit, source.psys, &cache->hair); particle_batch_cache_ensure_procedural_pos( source.edit, source.psys, &cache->hair, gpu_material); @@ -1730,7 +1695,7 @@ bool particles_ensure_procedural_data(Object *object, } /* Refreshed if active layer or custom data changes. */ - if ((*r_hair_cache)->strand_tex == NULL) { + if ((*r_hair_cache)->proc_strand_buf == NULL) { particle_batch_cache_ensure_procedural_strand_data( source.edit, source.psys, source.md, &cache->hair); } diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc index 98531637e57..d64fc581942 100644 --- a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc +++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc @@ -23,30 +23,64 @@ #include "BKE_pointcloud.h" #include "GPU_batch.h" +#include "GPU_material.h" -#include "draw_cache_impl.h" /* own include */ +#include "draw_attributes.h" +#include "draw_cache_impl.h" +#include "draw_cache_inline.h" +#include "draw_pointcloud_private.hh" /* own include */ -/* ---------------------------------------------------------------------- */ -/* PointCloud GPUBatch Cache */ +using namespace blender; -struct PointCloudBatchCache { - GPUVertBuf *pos; /* Position and radius. */ - GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */ - GPUVertBuf *attr_viewer; - GPUIndexBuf *geom_indices; +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name GPUBatch cache management + * \{ */ + +struct PointCloudBatchCache { + /* Dot primitive types. */ GPUBatch *dots; + /* Triangle primitive types. */ GPUBatch *surface; GPUBatch **surface_per_mat; - GPUBatch *surface_viewer_attribute; + /* Triangles indices to draw the points. */ + GPUIndexBuf *geom_indices; + + /* Position and radius. */ + GPUVertBuf *pos_rad; + /* Active attribute in 3D view. */ + GPUVertBuf *attr_viewer; + /* Requested attributes */ + GPUVertBuf *attributes_buf[GPU_MAX_ATTR]; + + /** Attributes currently being drawn or about to be drawn. */ + DRW_Attributes attr_used; + /** + * Attributes that were used at some point. This is used for garbage collection, to remove + * attributes that are not used in shaders anymore due to user edits. + */ + DRW_Attributes attr_used_over_time; + + /** + * The last time in seconds that the `attr_used` and `attr_used_over_time` were exactly the same. + * If the delta between this time and the current scene time is greater than the timeout set in + * user preferences (`U.vbotimeout`) then garbage collection is performed. + */ + int last_attr_matching_time; /* settings to determine if cache is invalid */ bool is_dirty; int mat_len; -}; -/* GPUBatch cache management. */ + /** + * The draw cache extraction is currently not multi-threaded for multiple objects, but if it was, + * some locking would be necessary because multiple objects can use the same object data with + * different materials, etc. This is a placeholder to make multi-threading easier in the future. + */ + std::mutex render_mutex; +}; static PointCloudBatchCache *pointcloud_batch_cache_get(PointCloud &pointcloud) { @@ -71,7 +105,7 @@ static void pointcloud_batch_cache_init(PointCloud &pointcloud) PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); if (!cache) { - cache = MEM_cnew<PointCloudBatchCache>(__func__); + cache = MEM_new<PointCloudBatchCache>(__func__); pointcloud.batch_cache = cache; } else { @@ -100,6 +134,15 @@ void DRW_pointcloud_batch_cache_dirty_tag(PointCloud *pointcloud, int mode) } } +static void pointcloud_discard_attributes(PointCloudBatchCache &cache) +{ + for (const int j : IndexRange(GPU_MAX_ATTR)) { + GPU_VERTBUF_DISCARD_SAFE(cache.attributes_buf[j]); + } + + drw_attributes_clear(&cache.attr_used); +} + static void pointcloud_batch_cache_clear(PointCloud &pointcloud) { PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); @@ -109,8 +152,7 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud) GPU_BATCH_DISCARD_SAFE(cache->dots); GPU_BATCH_DISCARD_SAFE(cache->surface); - GPU_VERTBUF_DISCARD_SAFE(cache->pos); - GPU_VERTBUF_DISCARD_SAFE(cache->geom); + GPU_VERTBUF_DISCARD_SAFE(cache->pos_rad); GPU_VERTBUF_DISCARD_SAFE(cache->attr_viewer); GPU_INDEXBUF_DISCARD_SAFE(cache->geom_indices); @@ -119,8 +161,9 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud) GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); } } - GPU_BATCH_DISCARD_SAFE(cache->surface_viewer_attribute); MEM_SAFE_FREE(cache->surface_per_mat); + + pointcloud_discard_attributes(*cache); } void DRW_pointcloud_batch_cache_validate(PointCloud *pointcloud) @@ -137,61 +180,35 @@ void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud) MEM_SAFE_FREE(pointcloud->batch_cache); } -static void pointcloud_batch_cache_ensure_pos(const PointCloud &pointcloud, - PointCloudBatchCache &cache) +void DRW_pointcloud_batch_cache_free_old(PointCloud *pointcloud, int ctime) { - using namespace blender; - if (cache.pos != nullptr) { + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + if (!cache) { return; } - const bke::AttributeAccessor attributes = pointcloud.attributes(); - const VArraySpan<float3> positions = attributes.lookup<float3>("position", ATTR_DOMAIN_POINT); - const VArray<float> radii = attributes.lookup<float>("radius", ATTR_DOMAIN_POINT); - /* From the opengl wiki: - * Note that size does not have to exactly match the size used by the vertex shader. If the - * vertex shader has fewer components than the attribute provides, then the extras are ignored. - * If the vertex shader has more components than the array provides, the extras are given - * values from the vector (0, 0, 0, 1) for the missing XYZW components. */ - if (radii) { - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - } - cache.pos = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.pos, positions.size()); - const VArraySpan<float> radii_span(radii); - MutableSpan<float4> vbo_data{static_cast<float4 *>(GPU_vertbuf_get_data(cache.pos)), - pointcloud.totpoint}; - threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) { - for (const int i : range) { - vbo_data[i].x = positions[i].x; - vbo_data[i].y = positions[i].y; - vbo_data[i].z = positions[i].z; - /* TODO(fclem): remove multiplication. Here only for keeping the size correct for now. */ - vbo_data[i].w = radii_span[i] * 100.0f; - } - }); + bool do_discard = false; + + if (drw_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) { + cache->last_attr_matching_time = ctime; } - else { - static GPUVertFormat format = {0}; - static uint pos; - if (format.attr_len == 0) { - pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - } - cache.pos = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.pos, positions.size()); - GPU_vertbuf_attr_fill(cache.pos, pos, positions.data()); + + if (ctime - cache->last_attr_matching_time > U.vbotimeout) { + do_discard = true; + } + + drw_attributes_clear(&cache->attr_used_over_time); + + if (do_discard) { + pointcloud_discard_attributes(*cache); } } -static const float half_octahedron_normals[5][3] = { - {0.0f, 0.0f, 1.0f}, - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}, - {-1.0f, 0.0f, 0.0f}, - {0.0f, -1.0f, 0.0f}, -}; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name PointCloud extraction + * \{ */ static const uint half_octahedron_tris[4][3] = { {0, 1, 2}, @@ -200,130 +217,236 @@ static const uint half_octahedron_tris[4][3] = { {0, 4, 1}, }; -static void pointcloud_batch_cache_ensure_geom(PointCloudBatchCache &cache) +static void pointcloud_extract_indices(const PointCloud &pointcloud, PointCloudBatchCache &cache) { - if (cache.geom != nullptr) { - return; + /** \note: Avoid modulo by non-power-of-two in shader. */ + uint32_t vertid_max = pointcloud.totpoint * 32; + uint32_t index_len = pointcloud.totpoint * ARRAY_SIZE(half_octahedron_tris); + + GPUIndexBufBuilder builder; + GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, index_len, vertid_max); + + for (int p = 0; p < pointcloud.totpoint; p++) { + for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) { + GPU_indexbuf_add_tri_verts(&builder, + half_octahedron_tris[i][0] + p * 32, + half_octahedron_tris[i][1] + p * 32, + half_octahedron_tris[i][2] + p * 32); + } } + GPU_indexbuf_build_in_place(&builder, cache.geom_indices); +} + +static void pointcloud_extract_position_and_radius(const PointCloud &pointcloud, + PointCloudBatchCache &cache) +{ + using namespace blender; + + const bke::AttributeAccessor attributes = pointcloud.attributes(); + const VArraySpan<float3> positions = attributes.lookup<float3>("position", ATTR_DOMAIN_POINT); + const VArray<float> radii = attributes.lookup<float>("radius", ATTR_DOMAIN_POINT); static GPUVertFormat format = {0}; - static uint pos; if (format.attr_len == 0) { - pos = GPU_vertformat_attr_add(&format, "pos_inst", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - GPU_vertformat_alias_add(&format, "nor"); + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } - cache.geom = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.geom, ARRAY_SIZE(half_octahedron_normals)); - - GPU_vertbuf_attr_fill(cache.geom, pos, half_octahedron_normals); - - GPUIndexBufBuilder builder; - GPU_indexbuf_init(&builder, - GPU_PRIM_TRIS, - ARRAY_SIZE(half_octahedron_tris), - ARRAY_SIZE(half_octahedron_normals)); + GPUUsageType usage_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; + GPU_vertbuf_init_with_format_ex(cache.pos_rad, &format, usage_flag); - for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) { - GPU_indexbuf_add_tri_verts(&builder, UNPACK3(half_octahedron_tris[i])); + GPU_vertbuf_data_alloc(cache.pos_rad, positions.size()); + MutableSpan<float4> vbo_data{static_cast<float4 *>(GPU_vertbuf_get_data(cache.pos_rad)), + pointcloud.totpoint}; + if (radii) { + const VArraySpan<float> radii_span(radii); + threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + vbo_data[i].x = positions[i].x; + vbo_data[i].y = positions[i].y; + vbo_data[i].z = positions[i].z; + /* TODO(fclem): remove multiplication. Here only for keeping the size correct for now. */ + vbo_data[i].w = radii_span[i] * 100.0f; + } + }); + } + else { + threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + vbo_data[i].x = positions[i].x; + vbo_data[i].y = positions[i].y; + vbo_data[i].z = positions[i].z; + vbo_data[i].w = 1.0f; + } + }); } - - cache.geom_indices = GPU_indexbuf_build(&builder); } -static void pointcloud_batch_cache_ensure_attribute_overlay(const PointCloud &pointcloud, - PointCloudBatchCache &cache) +static void pointcloud_extract_attribute(const PointCloud &pointcloud, + PointCloudBatchCache &cache, + const DRW_AttributeRequest &request, + int index) { using namespace blender; - if (cache.attr_viewer != nullptr) { - return; - } + + GPUVertBuf *&attr_buf = cache.attributes_buf[index]; const bke::AttributeAccessor attributes = pointcloud.attributes(); - const VArray<ColorGeometry4f> colors = attributes.lookup_or_default<ColorGeometry4f>( - ".viewer", ATTR_DOMAIN_POINT, {1.0f, 0.0f, 1.0f, 1.0f}); + + /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done + * by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following + * the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a + * similar texture state swizzle to map the attribute correctly as for volume attributes, so we + * can control the conversion ourselves. */ + VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>( + request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f}); static GPUVertFormat format = {0}; if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "attr", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); } - cache.attr_viewer = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache.attr_viewer, pointcloud.totpoint); + GPUUsageType usage_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY; + GPU_vertbuf_init_with_format_ex(attr_buf, &format, usage_flag); + GPU_vertbuf_data_alloc(attr_buf, pointcloud.totpoint); + MutableSpan<ColorGeometry4f> vbo_data{ - static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(cache.attr_viewer)), - pointcloud.totpoint}; - colors.materialize(vbo_data); + static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(attr_buf)), pointcloud.totpoint}; + attribute.materialize(vbo_data); } -GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) -{ - PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); - PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); +/** \} */ - if (cache->dots == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - cache->dots = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, nullptr); - } +/* -------------------------------------------------------------------- */ +/** \name Private API + * \{ */ - return cache->dots; +GPUVertBuf *pointcloud_position_and_radius_get(PointCloud *pointcloud) +{ + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + DRW_vbo_request(nullptr, &cache->pos_rad); + return cache->pos_rad; } -GPUBatch *DRW_pointcloud_batch_cache_get_surface(Object *ob) +GPUBatch **pointcloud_surface_shaded_get(PointCloud *pointcloud, + GPUMaterial **gpu_materials, + int mat_len) { - PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); - PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + DRW_Attributes attrs_needed; + drw_attributes_clear(&attrs_needed); + + for (GPUMaterial *gpu_material : Span<GPUMaterial *>(gpu_materials, mat_len)) { + ListBase gpu_attrs = GPU_material_attributes(gpu_material); + LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { + const char *name = gpu_attr->name; + + int layer_index; + eCustomDataType type; + eAttrDomain domain = ATTR_DOMAIN_POINT; + if (!drw_custom_data_match_attribute(&pointcloud->pdata, name, &layer_index, &type)) { + continue; + } - if (cache->surface == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - pointcloud_batch_cache_ensure_geom(*cache); + drw_attributes_add_request(&attrs_needed, name, type, layer_index, domain); + } + } - cache->surface = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); - GPU_batch_instbuf_add_ex(cache->surface, cache->pos, false); + if (!drw_attributes_overlap(&cache->attr_used, &attrs_needed)) { + /* Some new attributes have been added, free all and start over. */ + for (const int i : IndexRange(GPU_MAX_ATTR)) { + GPU_VERTBUF_DISCARD_SAFE(cache->attributes_buf[i]); + } + drw_attributes_merge(&cache->attr_used, &attrs_needed, cache->render_mutex); } + drw_attributes_merge(&cache->attr_used_over_time, &attrs_needed, cache->render_mutex); + + DRW_batch_request(&cache->surface_per_mat[0]); + return cache->surface_per_mat; +} - return cache->surface; +GPUBatch *pointcloud_surface_get(PointCloud *pointcloud) +{ + PointCloudBatchCache *cache = pointcloud_batch_cache_get(*pointcloud); + return DRW_batch_request(&cache->surface); } -GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(Object *ob) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name API + * \{ */ + +GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) { PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + return DRW_batch_request(&cache->dots); +} - if (cache->surface_viewer_attribute == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - pointcloud_batch_cache_ensure_geom(*cache); - pointcloud_batch_cache_ensure_attribute_overlay(pointcloud, *cache); +GPUVertBuf **DRW_pointcloud_evaluated_attribute(PointCloud *pointcloud, const char *name) +{ + PointCloudBatchCache &cache = *pointcloud_batch_cache_get(*pointcloud); + + int layer_index; + eCustomDataType type; + eAttrDomain domain = ATTR_DOMAIN_POINT; + if (drw_custom_data_match_attribute(&pointcloud->pdata, name, &layer_index, &type)) { + DRW_Attributes attributes{}; + drw_attributes_add_request(&attributes, name, type, layer_index, domain); + drw_attributes_merge(&cache.attr_used, &attributes, cache.render_mutex); + } - cache->surface_viewer_attribute = GPU_batch_create( - GPU_PRIM_TRIS, cache->geom, cache->geom_indices); - GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->attr_viewer, false); - GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->pos, false); + int request_i = -1; + for (const int i : IndexRange(cache.attr_used.num_requests)) { + if (STREQ(cache.attr_used.requests[i].attribute_name, name)) { + request_i = i; + break; + } + } + if (request_i == -1) { + return nullptr; } + return &cache.attributes_buf[request_i]; +} - return cache->surface_viewer_attribute; +int DRW_pointcloud_material_count_get(PointCloud *pointcloud) +{ + return max_ii(1, pointcloud->totcol); } -GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob, - struct GPUMaterial ** /*gpumat_array*/, - uint gpumat_array_len) +void DRW_pointcloud_batch_cache_create_requested(Object *ob) { - PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); - PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); - BLI_assert(cache->mat_len == gpumat_array_len); - UNUSED_VARS(gpumat_array_len); + PointCloud *pointcloud = static_cast<PointCloud *>(ob->data); + PointCloudBatchCache &cache = *pointcloud_batch_cache_get(*pointcloud); - if (cache->surface_per_mat[0] == nullptr) { - pointcloud_batch_cache_ensure_pos(pointcloud, *cache); - pointcloud_batch_cache_ensure_geom(*cache); + if (DRW_batch_requested(cache.dots, GPU_PRIM_POINTS)) { + DRW_vbo_request(cache.dots, &cache.pos_rad); + } - cache->surface_per_mat[0] = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); - GPU_batch_instbuf_add_ex(cache->surface_per_mat[0], cache->pos, false); + if (DRW_batch_requested(cache.surface, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache.surface, &cache.geom_indices); + DRW_vbo_request(cache.surface, &cache.pos_rad); + } + for (int i = 0; i < cache.mat_len; i++) { + if (DRW_batch_requested(cache.surface_per_mat[i], GPU_PRIM_TRIS)) { + /* TODO(fclem): Per material ranges. */ + DRW_ibo_request(cache.surface_per_mat[i], &cache.geom_indices); + } } + for (int j = 0; j < cache.attr_used.num_requests; j++) { + DRW_vbo_request(nullptr, &cache.attributes_buf[j]); - return cache->surface_per_mat; -} + if (DRW_vbo_requested(cache.attributes_buf[j])) { + pointcloud_extract_attribute(*pointcloud, cache, cache.attr_used.requests[j], j); + } + } -int DRW_pointcloud_material_count_get(PointCloud *pointcloud) -{ - return max_ii(1, pointcloud->totcol); + if (DRW_ibo_requested(cache.geom_indices)) { + pointcloud_extract_indices(*pointcloud, cache); + } + + if (DRW_vbo_requested(cache.pos_rad)) { + pointcloud_extract_position_and_radius(*pointcloud, cache); + } } + +/** \} */ diff --git a/source/blender/draw/intern/draw_command.cc b/source/blender/draw/intern/draw_command.cc index 882eda9b31d..10dd63e05dc 100644 --- a/source/blender/draw/intern/draw_command.cc +++ b/source/blender/draw/intern/draw_command.cc @@ -30,6 +30,11 @@ void ShaderBind::execute(RecordingState &state) const } } +void FramebufferBind::execute() const +{ + GPU_framebuffer_bind(framebuffer); +} + void ResourceBind::execute() const { if (slot == -1) { @@ -229,6 +234,11 @@ std::string ShaderBind::serialize() const return std::string(".shader_bind(") + GPU_shader_get_name(shader) + ")"; } +std::string FramebufferBind::serialize() const +{ + return std::string(".framebuffer_bind(") + GPU_framebuffer_get_name(framebuffer) + ")"; +} + std::string ResourceBind::serialize() const { switch (type) { diff --git a/source/blender/draw/intern/draw_command.hh b/source/blender/draw/intern/draw_command.hh index 5307a242e39..ab180cc60b1 100644 --- a/source/blender/draw/intern/draw_command.hh +++ b/source/blender/draw/intern/draw_command.hh @@ -88,6 +88,7 @@ enum class Type : uint8_t { DispatchIndirect, Draw, DrawIndirect, + FramebufferBind, PushConstant, ResourceBind, ShaderBind, @@ -118,6 +119,13 @@ struct ShaderBind { std::string serialize() const; }; +struct FramebufferBind { + GPUFrameBuffer *framebuffer; + + void execute() const; + std::string serialize() const; +}; + struct ResourceBind { eGPUSamplerState sampler; int slot; @@ -473,10 +481,8 @@ class DrawMultiBuf { uint vertex_first, ResourceHandle handle) { - /* Unsupported for now. Use PassSimple. */ - BLI_assert(vertex_first == 0 || vertex_first == -1); - BLI_assert(vertex_len == -1); - UNUSED_VARS_NDEBUG(vertex_len, vertex_first); + /* Custom draw-calls cannot be batched and will produce one group per draw. */ + const bool custom_group = (vertex_first != 0 || vertex_first != -1 || vertex_len != -1); instance_len = instance_len != -1 ? instance_len : 1; @@ -493,8 +499,14 @@ class DrawMultiBuf { bool inverted = handle.has_inverted_handedness(); - if (group_id == uint(-1)) { + DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++); + draw.resource_handle = handle.raw; + draw.instance_len = instance_len; + draw.group_id = group_id; + + if (group_id == uint(-1) || custom_group) { uint new_group_id = group_count_++; + draw.group_id = new_group_id; DrawGroup &group = group_buf_.get_or_resize(new_group_id); group.next = cmd.group_first; @@ -503,11 +515,16 @@ class DrawMultiBuf { group.gpu_batch = batch; group.front_proto_len = 0; group.back_proto_len = 0; + group.vertex_len = vertex_len; + group.vertex_first = vertex_first; + /* Custom group are not to be registered in the group_ids_. */ + if (!custom_group) { + group_id = new_group_id; + } /* For serialization only. */ (inverted ? group.back_proto_len : group.front_proto_len)++; /* Append to list. */ cmd.group_first = new_group_id; - group_id = new_group_id; } else { DrawGroup &group = group_buf_[group_id]; @@ -516,11 +533,6 @@ class DrawMultiBuf { /* For serialization only. */ (inverted ? group.back_proto_len : group.front_proto_len)++; } - - DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++); - draw.group_id = group_id; - draw.resource_handle = handle.raw; - draw.instance_len = instance_len; } void bind(RecordingState &state, diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index b5e9b3ee8bd..07d245e7dfe 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -88,6 +88,14 @@ void DRW_curves_ubos_pool_free(struct CurvesUniformBufPool *pool); void DRW_curves_update(void); void DRW_curves_free(void); +/* draw_pointcloud.cc */ + +struct DRWShadingGroup *DRW_shgroup_pointcloud_create_sub(struct Object *object, + struct DRWShadingGroup *shgrp_parent, + struct GPUMaterial *gpu_material); +void DRW_pointcloud_init(void); +void DRW_pointcloud_free(void); + /* draw_volume.cc */ /** diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc index a61769e7a63..ee9ed4666e0 100644 --- a/source/blender/draw/intern/draw_curves.cc +++ b/source/blender/draw/intern/draw_curves.cc @@ -129,25 +129,25 @@ void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool) static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp, CurvesEvalCache *cache, - GPUTexture *tex, + GPUVertBuf *point_buf, const int subdiv) { - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", point_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandBuffer", cache->proc_strand_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandSegBuffer", cache->proc_strand_seg_buf); DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); } static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int subdiv, const int strands_len, - GPUVertBuf *buffer, - GPUTexture *tex) + GPUVertBuf *output_buf, + GPUVertBuf *input_buf) { GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM); DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass); - drw_curves_cache_shgrp_attach_resources(shgrp, cache, tex, subdiv); - DRW_shgroup_vertex_buffer(shgrp, "posTime", buffer); + drw_curves_cache_shgrp_attach_resources(shgrp, cache, input_buf, subdiv); + DRW_shgroup_vertex_buffer(shgrp, "posTime", output_buf); const int max_strands_per_call = GPU_max_work_group_count(0); int strands_start = 0; @@ -169,7 +169,7 @@ static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int su } drw_curves_cache_update_compute( - cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->point_tex); + cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->proc_point_buf); const DRW_Attributes &attrs = cache->final[subdiv].attr_used; for (int i = 0; i < attrs.num_requests; i++) { @@ -182,13 +182,13 @@ static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int su subdiv, strands_len, cache->final[subdiv].attributes_buf[i], - cache->proc_attributes_tex[i]); + cache->proc_attributes_buf[i]); } } static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, - GPUVertBuf *vbo, - GPUTexture *tex, + GPUVertBuf *output_buf, + GPUVertBuf *input_buf, const int subdiv, const int final_points_len) { @@ -196,14 +196,14 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, DRWShadingGroup *tf_shgrp = nullptr; if (GPU_transform_feedback_support()) { - tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, vbo); + tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, output_buf); } else { tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__); pr_call->next = g_tf_calls; - pr_call->vbo = vbo; + pr_call->vbo = output_buf; pr_call->shgrp = tf_shgrp; pr_call->vert_len = final_points_len; g_tf_calls = pr_call; @@ -213,7 +213,7 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, } BLI_assert(tf_shgrp != nullptr); - drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, tex, subdiv); + drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, input_buf, subdiv); DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len); } @@ -225,7 +225,7 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, c } drw_curves_cache_update_transform_feedback( - cache, cache->final[subdiv].proc_buf, cache->point_tex, subdiv, final_points_len); + cache, cache->final[subdiv].proc_buf, cache->proc_point_buf, subdiv, final_points_len); const DRW_Attributes &attrs = cache->final[subdiv].attr_used; for (int i = 0; i < attrs.num_requests; i++) { @@ -236,7 +236,7 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, c drw_curves_cache_update_transform_feedback(cache, cache->final[subdiv].attributes_buf[i], - cache->proc_attributes_tex[i], + cache->proc_attributes_buf[i], subdiv, final_points_len); } @@ -346,9 +346,9 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, 1.0f); } - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex); - if (curves_cache->length_tex) { - DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_buf); + if (curves_cache->proc_length_buf) { + DRW_shgroup_buffer_texture(shgrp, "hairLen", curves_cache->proc_length_buf); } const DRW_Attributes &attrs = curves_cache->final[subdiv].attr_used; @@ -359,18 +359,18 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name); if (request.domain == ATTR_DOMAIN_CURVE) { - if (!curves_cache->proc_attributes_tex[i]) { + if (!curves_cache->proc_attributes_buf[i]) { continue; } - DRW_shgroup_uniform_texture(shgrp, sampler_name, curves_cache->proc_attributes_tex[i]); + DRW_shgroup_buffer_texture(shgrp, sampler_name, curves_cache->proc_attributes_buf[i]); } else { - if (!curves_cache->final[subdiv].attributes_tex[i]) { + if (!curves_cache->final[subdiv].attributes_buf[i]) { continue; } - DRW_shgroup_uniform_texture( - shgrp, sampler_name, curves_cache->final[subdiv].attributes_tex[i]); + DRW_shgroup_buffer_texture( + shgrp, sampler_name, curves_cache->final[subdiv].attributes_buf[i]); } /* Some attributes may not be used in the shader anymore and were not garbage collected yet, so @@ -390,10 +390,15 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape); - DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->obmat); + DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->object_to_world); DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); + if (gpu_material) { + /* \note: This needs to happen before the drawcall to allow correct attribute extraction. + * (see T101896) */ + DRW_shgroup_add_material_resources(shgrp, gpu_material); + } /* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass * culling test. */ GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1]; diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h index a74878ec674..715706fd7a6 100644 --- a/source/blender/draw/intern/draw_curves_private.h +++ b/source/blender/draw/intern/draw_curves_private.h @@ -34,7 +34,6 @@ typedef enum CurvesEvalShader { typedef struct CurvesEvalFinalCache { /* Output of the subdivision stage: vertex buffer sized to subdiv level. */ GPUVertBuf *proc_buf; - GPUTexture *proc_tex; /** Just contains a huge index buffer used to draw the final curves. */ GPUBatch *proc_hairs[MAX_THICKRES]; @@ -61,35 +60,29 @@ typedef struct CurvesEvalFinalCache { /* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes * on point domain. */ GPUVertBuf *attributes_buf[GPU_MAX_ATTR]; - GPUTexture *attributes_tex[GPU_MAX_ATTR]; } CurvesEvalFinalCache; /* Curves procedural display: Evaluation is done on the GPU. */ typedef struct CurvesEvalCache { /* Input control point positions combined with parameter data. */ GPUVertBuf *proc_point_buf; - GPUTexture *point_tex; /* Editmode data (such as selection flags) used by overlay_edit_curve_point.glsl */ GPUVertBuf *data_edit_points; /** Info of control points strands (segment count and base index) */ GPUVertBuf *proc_strand_buf; - GPUTexture *strand_tex; /* Curve length data. */ GPUVertBuf *proc_length_buf; - GPUTexture *length_tex; GPUVertBuf *proc_strand_seg_buf; - GPUTexture *strand_seg_tex; CurvesEvalFinalCache final[MAX_HAIR_SUBDIV]; /* For point attributes, which need subdivision, these buffers contain the input data. * For curve domain attributes, which do not need subdivision, these are the final data. */ GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR]; - GPUTexture *proc_attributes_tex[GPU_MAX_ATTR]; int strands_len; int elems_len; diff --git a/source/blender/draw/intern/draw_hair.cc b/source/blender/draw/intern/draw_hair.cc index 4e44967e5e9..c5261f26f76 100644 --- a/source/blender/draw/intern/draw_hair.cc +++ b/source/blender/draw/intern/draw_hair.cc @@ -105,9 +105,9 @@ static void drw_hair_particle_cache_shgrp_attach_resources(DRWShadingGroup *shgr ParticleHairCache *cache, const int subdiv) { - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex); - DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", cache->proc_point_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandBuffer", cache->proc_strand_buf); + DRW_shgroup_buffer_texture(shgrp, "hairStrandSegBuffer", cache->proc_strand_seg_buf); DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); } @@ -216,12 +216,12 @@ void DRW_hair_duplimat_get(Object *object, if (collection != nullptr) { sub_v3_v3(dupli_mat[3], collection->instance_offset); } - mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, dupli_parent->object_to_world, dupli_mat); } else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + copy_m4_m4(dupli_mat, dupli_object->ob->object_to_world); invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat); + mul_m4_m4m4(dupli_mat, object->object_to_world, dupli_mat); } } else { @@ -280,9 +280,9 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, float hair_rad_tip = part->rad_tip * part->rad_scale * 0.5f; bool hair_close_tip = (part->shape_flag & PART_SHAPE_CLOSE_TIP) != 0; - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex); - if (hair_cache->length_tex) { - DRW_shgroup_uniform_texture(shgrp, "l", hair_cache->length_tex); + DRW_shgroup_buffer_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_buf); + if (hair_cache->proc_length_buf) { + DRW_shgroup_buffer_texture(shgrp, "l", hair_cache->proc_length_buf); } DRW_shgroup_uniform_block(shgrp, "drw_curves", *g_dummy_curves_info); @@ -293,6 +293,11 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); + if (gpu_material) { + /* \note: This needs to happen before the drawcall to allow correct attribute extraction. + * (see T101896) */ + DRW_shgroup_add_material_resources(shgrp, gpu_material); + } /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass * culling test. */ GPUBatch *geom = hair_cache->final[subdiv].proc_hairs[thickness_res - 1]; diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h index c7e9e1e22de..a3019ab5aa5 100644 --- a/source/blender/draw/intern/draw_hair_private.h +++ b/source/blender/draw/intern/draw_hair_private.h @@ -29,7 +29,6 @@ struct ParticleSystem; typedef struct ParticleHairFinalCache { /* Output of the subdivision stage: vertex buff sized to subdiv level. */ GPUVertBuf *proc_buf; - GPUTexture *proc_tex; /* Just contains a huge index buffer used to draw the final hair. */ GPUBatch *proc_hairs[MAX_THICKRES]; @@ -44,18 +43,14 @@ typedef struct ParticleHairCache { /* Hair Procedural display: Interpolation is done on the GPU. */ GPUVertBuf *proc_point_buf; /* Input control points */ - GPUTexture *point_tex; /** Infos of control points strands (segment count and base index) */ GPUVertBuf *proc_strand_buf; - GPUTexture *strand_tex; /* Hair Length */ GPUVertBuf *proc_length_buf; - GPUTexture *length_tex; GPUVertBuf *proc_strand_seg_buf; - GPUTexture *strand_seg_tex; GPUVertBuf *proc_uv_buf[MAX_MTFACE]; GPUTexture *uv_tex[MAX_MTFACE]; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index da77845feb4..4fcfec833eb 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1690,6 +1690,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DRW_globals_update(); drw_debug_init(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -1959,20 +1960,6 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph DST.buffer_finish_called = false; } -/* Callback function for RE_engine_update_render_passes to ensure all - * render passes are registered. */ -static void draw_render_result_ensure_pass_cb(void *user_data, - struct Scene *UNUSED(scene), - struct ViewLayer *view_layer, - const char *name, - int channels, - const char *chanid, - eNodeSocketDatatype UNUSED(type)) -{ - RenderEngine *engine = user_data; - RE_engine_add_pass(engine, name, channels, chanid, view_layer->name); -} - void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) { Scene *scene = DEG_get_evaluated_scene(depsgraph); @@ -2023,10 +2010,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* set default viewport */ GPU_viewport(0, 0, size[0], size[1]); - /* Update the render passes. This needs to be done before acquiring the render result. */ - RE_engine_update_render_passes( - engine, scene, view_layer, draw_render_result_ensure_pass_cb, engine); - /* Init render result. */ RenderResult *render_result = RE_engine_begin_result(engine, 0, @@ -2071,6 +2054,7 @@ void DRW_render_object_iter( void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph)) { const DRWContextState *draw_ctx = DRW_context_state_get(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2131,6 +2115,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, drw_manager_init(&DST, NULL, NULL); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2166,6 +2151,7 @@ void DRW_cache_restart(void) DST.buffer_finish_called = false; + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2491,6 +2477,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, /* Init engines */ drw_engines_init(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2672,6 +2659,7 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph, /* Init engines */ drw_engines_init(); + DRW_pointcloud_init(); DRW_curves_init(DST.vmempool); DRW_volume_init(DST.vmempool); DRW_smoke_init(DST.vmempool); @@ -2813,7 +2801,7 @@ void DRW_draw_depth_object( GPU_matrix_projection_set(rv3d->winmat); GPU_matrix_set(rv3d->viewmat); - GPU_matrix_mul(object->obmat); + GPU_matrix_mul(object->object_to_world); /* Setup frame-buffer. */ GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport); @@ -2833,11 +2821,11 @@ void DRW_draw_depth_object( const bool use_clipping_planes = RV3D_CLIPPING_ENABLED(v3d, rv3d); if (use_clipping_planes) { GPU_clip_distances(6); - ED_view3d_clipping_local(rv3d, object->obmat); + ED_view3d_clipping_local(rv3d, object->object_to_world); for (int i = 0; i < 6; i++) { copy_v4_v4(planes.world[i], rv3d->clip_local[i]); } - copy_m4_m4(planes.ModelMatrix, object->obmat); + copy_m4_m4(planes.ModelMatrix, object->object_to_world); } drw_batch_cache_validate(object); @@ -3086,6 +3074,7 @@ void DRW_engines_free(void) GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer_depth_only); DRW_shaders_free(); + DRW_pointcloud_free(); DRW_curves_free(); DRW_volume_free(); DRW_shape_cache_free(); diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc index 981206e56fe..4aa27e2288c 100644 --- a/source/blender/draw/intern/draw_manager_data.cc +++ b/source/blender/draw/intern/draw_manager_data.cc @@ -589,7 +589,7 @@ void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup, const char *name, GPUVertBuf *vertex_buffer) { - int location = GPU_shader_get_ssbo(shgroup->shader, name); + int location = GPU_shader_get_texture_binding(shgroup->shader, name); if (location == -1) { return; } @@ -606,7 +606,7 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUVertBuf **vertex_buffer) { - int location = GPU_shader_get_ssbo(shgroup->shader, name); + int location = GPU_shader_get_texture_binding(shgroup->shader, name); if (location == -1) { return; } @@ -724,8 +724,8 @@ static void drw_call_culling_init(DRWCullingState *cull, Object *ob) float corner[3]; /* Get BoundSphere center and radius from the BoundBox. */ mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]); - mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]); - mul_m4_v3(ob->obmat, cull->bsphere.center); + mul_v3_m4v3(corner, ob->object_to_world, bbox->vec[0]); + mul_m4_v3(ob->object_to_world, cull->bsphere.center); cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner); /* Bypass test for very large objects (see T67319). */ @@ -1017,7 +1017,7 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : obmat, ob); drw_command_draw(shgroup, geom, handle); /* Culling data. */ @@ -1042,7 +1042,7 @@ void DRW_shgroup_call_range( if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_range(shgroup, geom, handle, v_sta, v_num); } @@ -1053,7 +1053,7 @@ void DRW_shgroup_call_instance_range( if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_num); } @@ -1099,7 +1099,7 @@ static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_procedural(shgroup, geom, handle, vert_count); } @@ -1149,7 +1149,7 @@ void DRW_shgroup_call_procedural_indirect(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_indirect(shgroup, geom, handle, indirect_buf); } @@ -1159,7 +1159,7 @@ void DRW_shgroup_call_instances(DRWShadingGroup *shgroup, Object *ob, GPUBatch * if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); drw_command_draw_instance(shgroup, geom, handle, count, false); } @@ -1173,7 +1173,7 @@ void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup, if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->object_to_world : nullptr, ob); GPUBatch *batch = DRW_temp_batch_instance_request( DST.vmempool->idatalist, nullptr, inst_attributes, geom); drw_command_draw_instance(shgroup, batch, handle, 0, true); @@ -1283,7 +1283,7 @@ static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4]) * 4x4 matrix is done by multiplying with the transpose inverse. * The inverse cancels out here since we transform by inverse(obmat). */ float tmat[4][4]; - transpose_m4_m4(tmat, ob->obmat); + transpose_m4_m4(tmat, ob->object_to_world); for (int i = 0; i < 6; i++) { mul_m4_v4(tmat, planes[i]); } @@ -1361,7 +1361,7 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) if (SCULPT_DEBUG_BUFFERS) { int debug_node_nr = 0; - DRW_debug_modelmat(scd->ob->obmat); + DRW_debug_modelmat(scd->ob->object_to_world); BKE_pbvh_draw_debug_cb( pbvh, (void (*)(PBVHNode * n, void *d, const float min[3], const float max[3], PBVHNodeFlags f)) diff --git a/source/blender/draw/intern/draw_manager_text.cc b/source/blender/draw/intern/draw_manager_text.cc index 100ef528bc8..239f6fcca73 100644 --- a/source/blender/draw/intern/draw_manager_text.cc +++ b/source/blender/draw/intern/draw_manager_text.cc @@ -305,11 +305,11 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) { mid_v3_v3v3(vmid, v1_clip, v2_clip); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); + mul_mat3_m4_v3(ob->object_to_world, v1); + mul_mat3_m4_v3(ob->object_to_world, v2); } if (unit->system) { @@ -373,7 +373,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, float angle; mid_v3_v3v3(vmid, v1_clip, v2_clip); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); if (use_coords) { copy_v3_v3(no_a, poly_normals[BM_elem_index_get(l_a->f)]); @@ -443,16 +443,16 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, n += 3; if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - mul_mat3_m4_v3(ob->obmat, v3); + mul_mat3_m4_v3(ob->object_to_world, v1); + mul_mat3_m4_v3(ob->object_to_world, v2); + mul_mat3_m4_v3(ob->object_to_world, v3); } area += area_tri_v3(v1, v2, v3); } mul_v3_fl(vmid, 1.0f / float(n)); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); if (unit->system) { numstr_len = BKE_unit_value_as_string( @@ -522,9 +522,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, copy_v3_v3(v2_local, v2); if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - mul_mat3_m4_v3(ob->obmat, v3); + mul_mat3_m4_v3(ob->object_to_world, v1); + mul_mat3_m4_v3(ob->object_to_world, v2); + mul_mat3_m4_v3(ob->object_to_world, v3); } float angle = angle_v3v3v3(v1, v2, v3); @@ -535,7 +535,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, (is_rad) ? angle : RAD2DEGF(angle), (is_rad) ? "r" : "°"); interp_v3_v3v3(fvec, vmid, v2_local, 0.8f); - mul_m4_v3(ob->obmat, fvec); + mul_m4_v3(ob->object_to_world, fvec); DRW_text_cache_add(dt, fvec, numstr, numstr_len, 0, 0, txt_flag, col); } } @@ -566,7 +566,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, copy_v3_v3(v1, v->co); } - mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->object_to_world, v1); numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col); @@ -595,7 +595,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) { mid_v3_v3v3(vmid, v1_clip, v2_clip); - mul_m4_v3(ob->obmat, vmid); + mul_m4_v3(ob->object_to_world, vmid); numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); DRW_text_cache_add( @@ -629,7 +629,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, BM_face_calc_center_median(f, v1); } - mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->object_to_world, v1); numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col); diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh index 24dfdd1b97b..892dfdddfcf 100644 --- a/source/blender/draw/intern/draw_pass.hh +++ b/source/blender/draw/intern/draw_pass.hh @@ -14,8 +14,7 @@ * #Pass. Use many #PassSub along with a main #Pass to reduce the overhead and allow groupings of * commands. \note The draw call order inside a batch of multiple draw with the exact same state is * not guaranteed and is not even deterministic. Use a #PassSimple or #PassSortable if ordering is - * needed. \note As of now, it is also quite limited in the type of draw command it can record - * (no custom vertex count, no custom first vertex). + * needed. Custom vertex count and custom first vertex will effectively disable batching. * * `PassSimple`: * Does not have the overhead of #PassMain but does not have the culling and batching optimization. @@ -192,6 +191,12 @@ class PassBase { void shader_set(GPUShader *shader); /** + * Bind a framebuffer. This is equivalent to a deferred GPU_framebuffer_bind() call. + * \note Changes the global GPU state (outside of DRW). + */ + void framebuffer_set(GPUFrameBuffer *framebuffer); + + /** * Bind a material shader along with its associated resources. Any following bind() or * push_constant() call will use its interface. * IMPORTANT: Assumes material is compiled and can be used (no compilation error). @@ -743,6 +748,11 @@ template<class T> inline void PassBase<T>::shader_set(GPUShader *shader) create_command(Type::ShaderBind).shader_bind = {shader}; } +template<class T> inline void PassBase<T>::framebuffer_set(GPUFrameBuffer *framebuffer) +{ + create_command(Type::FramebufferBind).framebuffer_bind = {framebuffer}; +} + template<class T> inline void PassBase<T>::material_set(Manager &manager, GPUMaterial *material) { GPUPass *gpupass = GPU_material_get_pass(material); diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc index 38fb6d55245..b25bb42a8a5 100644 --- a/source/blender/draw/intern/draw_pbvh.cc +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -951,6 +951,14 @@ struct PBVHBatches { void create_index_faces(PBVH_GPU_Args *args) { + int *mat_index = static_cast<int *>( + CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index")); + + if (mat_index && args->totprim) { + int poly_index = args->mlooptri[args->prim_indices[0]].poly; + material_index = mat_index[poly_index]; + } + /* Calculate number of edges*/ int edge_count = 0; for (int i = 0; i < args->totprim; i++) { @@ -959,6 +967,7 @@ struct PBVHBatches { if (args->hide_poly && args->hide_poly[lt->poly]) { continue; } + int r_edges[3]; BKE_mesh_looptri_get_real_edges(args->me, lt, r_edges); @@ -1030,6 +1039,14 @@ struct PBVHBatches { void create_index_grids(PBVH_GPU_Args *args) { + int *mat_index = static_cast<int *>( + CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index")); + + if (mat_index && args->totprim) { + int poly_index = BKE_subdiv_ccg_grid_to_face_index(args->subdiv_ccg, args->grid_indices[0]); + material_index = mat_index[poly_index]; + } + needs_tri_index = true; int gridsize = args->ccg_key.grid_size; int totgrid = args->totprim; diff --git a/source/blender/draw/intern/draw_pointcloud.cc b/source/blender/draw/intern/draw_pointcloud.cc new file mode 100644 index 00000000000..582dc690cee --- /dev/null +++ b/source/blender/draw/intern/draw_pointcloud.cc @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2017 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Contains procedural GPU hair drawing methods. + */ + +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" + +#include "DNA_customdata_types.h" +#include "DNA_pointcloud_types.h" + +#include "BKE_curves.hh" +#include "BKE_geometry_set.hh" + +#include "GPU_batch.h" +#include "GPU_capabilities.h" +#include "GPU_compute.h" +#include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_texture.h" +#include "GPU_vertex_buffer.h" + +#include "DRW_gpu_wrapper.hh" +#include "DRW_render.h" + +#include "draw_attributes.h" +#include "draw_cache_impl.h" +#include "draw_common.h" +#include "draw_manager.h" +#include "draw_pointcloud_private.hh" + +static GPUVertBuf *g_dummy_vbo = nullptr; + +void DRW_pointcloud_init() +{ + if (g_dummy_vbo == nullptr) { + /* initialize vertex format */ + GPUVertFormat format = {0}; + uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + g_dummy_vbo = GPU_vertbuf_create_with_format_ex( + &format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); + + const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_vertbuf_data_alloc(g_dummy_vbo, 1); + GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert); + } +} + +DRWShadingGroup *DRW_shgroup_pointcloud_create_sub(Object *object, + DRWShadingGroup *shgrp_parent, + GPUMaterial *gpu_material) +{ + PointCloud &pointcloud = *static_cast<PointCloud *>(object->data); + + DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); + + /* Fix issue with certain driver not drawing anything if there is no texture bound to + * "ac", "au", "u" or "c". */ + DRW_shgroup_buffer_texture(shgrp, "u", g_dummy_vbo); + DRW_shgroup_buffer_texture(shgrp, "au", g_dummy_vbo); + DRW_shgroup_buffer_texture(shgrp, "c", g_dummy_vbo); + DRW_shgroup_buffer_texture(shgrp, "ac", g_dummy_vbo); + + GPUVertBuf *pos_rad_buf = pointcloud_position_and_radius_get(&pointcloud); + DRW_shgroup_buffer_texture(shgrp, "ptcloud_pos_rad_tx", pos_rad_buf); + + if (gpu_material != nullptr) { + + // const DRW_Attributes &attrs = cache->attr_used; + // for (int i = 0; i < attrs.num_requests; i++) { + // const DRW_AttributeRequest &request = attrs.requests[i]; + + // char sampler_name[32]; + // /* \note reusing curve attribute function. */ + // drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name); + + // GPUTexture *attribute_buf = DRW_pointcloud_evaluated_attribute(&pointcloud); + // if (!cache->attributes_buf[i]) { + // continue; + // } + // DRW_shgroup_buffer_texture_ref(shgrp, sampler_name, attribute_buf); + // } + + /* Only single material supported for now. */ + GPUBatch **geom = pointcloud_surface_shaded_get(&pointcloud, &gpu_material, 1); + DRW_shgroup_call(shgrp, geom[0], object); + } + else { + GPUBatch *geom = pointcloud_surface_get(&pointcloud); + DRW_shgroup_call(shgrp, geom, object); + } + return shgrp; +} + +void DRW_pointcloud_free() +{ + GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo); +} diff --git a/source/blender/draw/intern/draw_pointcloud_private.hh b/source/blender/draw/intern/draw_pointcloud_private.hh new file mode 100644 index 00000000000..9422d7fbc99 --- /dev/null +++ b/source/blender/draw/intern/draw_pointcloud_private.hh @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + */ + +#pragma once + +struct PointCloud; +struct GPUBatch; +struct GPUVertBuf; +struct GPUMaterial; + +GPUVertBuf *pointcloud_position_and_radius_get(PointCloud *pointcloud); +GPUBatch **pointcloud_surface_shaded_get(PointCloud *pointcloud, + GPUMaterial **gpu_materials, + int mat_len); +GPUBatch *pointcloud_surface_get(PointCloud *pointcloud); diff --git a/source/blender/draw/intern/draw_resource.hh b/source/blender/draw/intern/draw_resource.hh index 2df38e32ed2..b116d7fe183 100644 --- a/source/blender/draw/intern/draw_resource.hh +++ b/source/blender/draw/intern/draw_resource.hh @@ -31,7 +31,7 @@ inline void ObjectMatrices::sync(const Object &object) { - model = object.obmat; + model = object.object_to_world; model_inverse = object.imat; } diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc index 2b4b0e3c089..5c1ce7c3111 100644 --- a/source/blender/draw/intern/draw_volume.cc +++ b/source/blender/draw/intern/draw_volume.cc @@ -127,7 +127,7 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob, grp = DRW_shgroup_create_sub(grp); - volume_infos.density_scale = BKE_volume_density_scale(volume, ob->obmat); + volume_infos.density_scale = BKE_volume_density_scale(volume, ob->object_to_world); volume_infos.color_mul = float4(1.0f); volume_infos.temperature_mul = 1.0f; volume_infos.temperature_bias = 0.0f; diff --git a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl index 123c493b572..def841b07aa 100644 --- a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl +++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl @@ -90,10 +90,15 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos) #ifdef GPU_VERTEX_SHADER -/* Trick to detect if a drawcall is stroke or fill. - * This does mean that we need to draw an empty stroke segment before starting - * to draw the real stroke segments. */ -# define GPENCIL_IS_STROKE_VERTEX (gl_InstanceID != 0) +int gpencil_stroke_point_id() +{ + return (gl_VertexID & ~GP_IS_STROKE_VERTEX_BIT) >> GP_VERTEX_ID_SHIFT; +} + +bool gpencil_is_stroke_vertex() +{ + return flag_test(gl_VertexID, GP_IS_STROKE_VERTEX_BIT); +} /** * Returns value of gl_Position. @@ -120,20 +125,7 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos) * WARNING: Max attribute count is actually 14 because OSX OpenGL implementation * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */ -vec4 gpencil_vertex(ivec4 ma, - ivec4 ma1, - ivec4 ma2, - ivec4 ma3, - vec4 pos, - vec4 pos1, - vec4 pos2, - vec4 pos3, - vec4 uv1, - vec4 uv2, - vec4 col1, - vec4 col2, - vec4 fcol1, - vec4 viewport_size, +vec4 gpencil_vertex(vec4 viewport_size, gpMaterialFlag material_flags, vec2 alignment_rot, /* World Position. */ @@ -155,6 +147,24 @@ vec4 gpencil_vertex(ivec4 ma, /* Stroke hardness. */ out float out_hardness) { + int stroke_point_id = (gl_VertexID & ~GP_IS_STROKE_VERTEX_BIT) >> GP_VERTEX_ID_SHIFT; + + /* Attribute Loading. */ + vec4 pos = texelFetch(gp_pos_tx, (stroke_point_id - 1) * 3 + 0); + vec4 pos1 = texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 0); + vec4 pos2 = texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 0); + vec4 pos3 = texelFetch(gp_pos_tx, (stroke_point_id + 2) * 3 + 0); + ivec4 ma = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id - 1) * 3 + 1)); + ivec4 ma1 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 1)); + ivec4 ma2 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 1)); + ivec4 ma3 = floatBitsToInt(texelFetch(gp_pos_tx, (stroke_point_id + 2) * 3 + 1)); + vec4 uv1 = texelFetch(gp_pos_tx, (stroke_point_id + 0) * 3 + 2); + vec4 uv2 = texelFetch(gp_pos_tx, (stroke_point_id + 1) * 3 + 2); + + vec4 col1 = texelFetch(gp_col_tx, (stroke_point_id + 0) * 2 + 0); + vec4 col2 = texelFetch(gp_col_tx, (stroke_point_id + 1) * 2 + 0); + vec4 fcol1 = texelFetch(gp_col_tx, (stroke_point_id + 0) * 2 + 1); + # define thickness1 pos1.w # define thickness2 pos2.w # define strength1 uv1.w @@ -167,7 +177,7 @@ vec4 gpencil_vertex(ivec4 ma, vec4 out_ndc; - if (GPENCIL_IS_STROKE_VERTEX) { + if (gpencil_is_stroke_vertex()) { bool is_dot = flag_test(material_flags, GP_STROKE_ALIGNMENT); bool is_squares = !flag_test(material_flags, GP_STROKE_DOTS); @@ -177,13 +187,6 @@ vec4 gpencil_vertex(ivec4 ma, is_squares = false; } - /* Endpoints, we discard the vertices. */ - if (ma1.x == -1 || (!is_dot && ma2.x == -1)) { - /* We set the vertex at the camera origin to generate 0 fragments. */ - out_ndc = vec4(0.0, 0.0, -3e36, 0.0); - return out_ndc; - } - /* Avoid using a vertex attribute for quad positioning. */ float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */ float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */ @@ -336,8 +339,7 @@ vec4 gpencil_vertex(ivec4 ma, out_N = safe_normalize(N); /* Decode fill opacity. */ - out_color = vec4(fcol1.rgb, floor(fcol1.a / 10.0)); - out_color.a /= 10000.0; + out_color = vec4(fcol1.rgb, floor(fcol1.a / 10.0) / 10000.0); /* We still offset the fills a little to avoid overlaps */ out_ndc.z += 0.000002; @@ -355,20 +357,7 @@ vec4 gpencil_vertex(ivec4 ma, return out_ndc; } -vec4 gpencil_vertex(ivec4 ma, - ivec4 ma1, - ivec4 ma2, - ivec4 ma3, - vec4 pos, - vec4 pos1, - vec4 pos2, - vec4 pos3, - vec4 uv1, - vec4 uv2, - vec4 col1, - vec4 col2, - vec4 fcol1, - vec4 viewport_size, +vec4 gpencil_vertex(vec4 viewport_size, out vec3 out_P, out vec3 out_N, out vec4 out_color, @@ -379,20 +368,7 @@ vec4 gpencil_vertex(ivec4 ma, out vec2 out_thickness, out float out_hardness) { - return gpencil_vertex(ma, - ma1, - ma2, - ma3, - pos, - pos1, - pos2, - pos3, - uv1, - uv2, - col1, - col2, - fcol1, - viewport_size, + return gpencil_vertex(viewport_size, 0u, vec2(1.0, 0.0), out_P, diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl index dd725ad327f..8725e036435 100644 --- a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl +++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl @@ -2,16 +2,10 @@ /* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */ #pragma BLENDER_REQUIRE(common_view_lib.glsl) -#ifndef DRW_SHADER_SHARED_H - -in vec4 pos; /* Position and radius. */ - -/* ---- Instanced attribs ---- */ - -in vec3 pos_inst; -in vec3 nor; - -#endif +int pointcloud_get_point_id() +{ + return gl_VertexID / 32; +} mat3 pointcloud_get_facing_matrix(vec3 p) { @@ -25,8 +19,10 @@ mat3 pointcloud_get_facing_matrix(vec3 p) /* Returns world center position and radius. */ void pointcloud_get_pos_and_radius(out vec3 outpos, out float outradius) { - outpos = point_object_to_world(pos.xyz); - outradius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0)); + int id = pointcloud_get_point_id(); + vec4 pos_rad = texelFetch(ptcloud_pos_rad_tx, id); + outpos = point_object_to_world(pos_rad.xyz); + outradius = dot(abs(mat3(ModelMatrix) * pos_rad.www), vec3(1.0 / 3.0)); } /* Return world position and normal. */ @@ -38,15 +34,67 @@ void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor) mat3 facing_mat = pointcloud_get_facing_matrix(p); + /** \note: Avoid modulo by non-power-of-two in shader. See Index buffer setup. */ + int vert_id = gl_VertexID % 32; + vec3 pos_inst = vec3(0.0); + + switch (vert_id) { + case 0: + pos_inst.z = 1.0; + break; + case 1: + pos_inst.x = 1.0; + break; + case 2: + pos_inst.y = 1.0; + break; + case 3: + pos_inst.x = -1.0; + break; + case 4: + pos_inst.y = -1.0; + break; + } + /* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */ radius *= 0.01; - outpos = p + (facing_mat * pos_inst) * radius; - outnor = facing_mat * nor; + outnor = facing_mat * pos_inst; + outpos = p + outnor * radius; } -vec3 pointcloud_get_pos(void) +vec3 pointcloud_get_pos() { vec3 outpos, outnor; pointcloud_get_pos_and_nor(outpos, outnor); return outpos; } + +float pointcloud_get_customdata_float(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).r; +} + +vec2 pointcloud_get_customdata_vec2(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).rg; +} + +vec3 pointcloud_get_customdata_vec3(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).rgb; +} + +vec4 pointcloud_get_customdata_vec4(const samplerBuffer cd_buf) +{ + int id = pointcloud_get_point_id(); + return texelFetch(cd_buf, id).rgba; +} + +vec2 pointcloud_get_barycentric(void) +{ + /* TODO: To be implemented. */ + return vec2(0.0); +} diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index 7b500f66a68..23892a39062 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -112,9 +112,7 @@ GPU_SHADER_CREATE_INFO(draw_hair) .additional_info("draw_modelmat", "draw_resource_id"); GPU_SHADER_CREATE_INFO(draw_pointcloud) - .vertex_in(0, Type::VEC4, "pos") - .vertex_in(1, Type::VEC3, "pos_inst") - .vertex_in(2, Type::VEC3, "nor") + .sampler(0, ImageType::FLOAT_BUFFER, "ptcloud_pos_rad_tx", Frequency::BATCH) .additional_info("draw_modelmat_instanced_attr", "draw_resource_id_uniform"); GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform"); @@ -122,26 +120,15 @@ GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resou GPU_SHADER_CREATE_INFO(draw_gpencil) .typedef_source("gpencil_shader_shared.h") .define("DRW_GPENCIL_INFO") - .vertex_in(0, Type::IVEC4, "ma") - .vertex_in(1, Type::IVEC4, "ma1") - .vertex_in(2, Type::IVEC4, "ma2") - .vertex_in(3, Type::IVEC4, "ma3") - .vertex_in(4, Type::VEC4, "pos") - .vertex_in(5, Type::VEC4, "pos1") - .vertex_in(6, Type::VEC4, "pos2") - .vertex_in(7, Type::VEC4, "pos3") - .vertex_in(8, Type::VEC4, "uv1") - .vertex_in(9, Type::VEC4, "uv2") - .vertex_in(10, Type::VEC4, "col1") - .vertex_in(11, Type::VEC4, "col2") - .vertex_in(12, Type::VEC4, "fcol1") + .sampler(0, ImageType::FLOAT_BUFFER, "gp_pos_tx") + .sampler(1, ImageType::FLOAT_BUFFER, "gp_col_tx") /* Per Object */ .push_constant(Type::FLOAT, "gpThicknessScale") /* TODO(fclem): Replace with object info. */ .push_constant(Type::FLOAT, "gpThicknessWorldScale") /* TODO(fclem): Same as above. */ .define("gpThicknessIsScreenSpace", "(gpThicknessWorldScale < 0.0)") /* Per Layer */ .push_constant(Type::FLOAT, "gpThicknessOffset") - .additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_object_infos"); + .additional_info("draw_modelmat", "draw_object_infos"); /** \} */ diff --git a/source/blender/draw/tests/draw_pass_test.cc b/source/blender/draw/tests/draw_pass_test.cc index 394ca8bd3cf..95ab8fa2ef1 100644 --- a/source/blender/draw/tests/draw_pass_test.cc +++ b/source/blender/draw/tests/draw_pass_test.cc @@ -181,12 +181,19 @@ static void test_draw_pass_multi_draw() pass.draw_procedural(GPU_PRIM_LINES, 1, -1, -1, {5}); pass.draw_procedural(GPU_PRIM_POINTS, 6, -1, -1, {5}); pass.draw_procedural(GPU_PRIM_TRIS, 3, -1, -1, {6}); + /* Custom calls should use their own group and never be batched. */ + pass.draw_procedural(GPU_PRIM_TRIS, 2, 2, 2, {7}); + pass.draw_procedural(GPU_PRIM_TRIS, 2, 2, 2, {8}); std::string result = pass.serialize(); std::stringstream expected; expected << ".test.multi_draw" << std::endl; expected << " .shader_bind(gpu_shader_3D_image_color)" << std::endl; expected << " .draw_multi(3)" << std::endl; + expected << " .group(id=4, len=2)" << std::endl; + expected << " .proto(instance_len=2, resource_id=8, front_face)" << std::endl; + expected << " .group(id=3, len=2)" << std::endl; + expected << " .proto(instance_len=2, resource_id=7, front_face)" << std::endl; expected << " .group(id=2, len=1)" << std::endl; expected << " .proto(instance_len=1, resource_id=5, front_face)" << std::endl; expected << " .group(id=1, len=15)" << std::endl; diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index 23c1d68b4d6..4a83bb4c800 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -161,11 +161,11 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) } /* Result must be in world-space. */ - mul_m4_v3(ob_eval->obmat, mpv->co); + mul_m4_v3(ob_eval->object_to_world, mpv->co); } else { /* World-space object location. */ - copy_v3_v3(mpv->co, ob_eval->obmat[3]); + copy_v3_v3(mpv->co, ob_eval->object_to_world[3]); } float mframe = (float)(cframe); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index c9957b38853..96a9604a6f5 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1044,12 +1044,12 @@ static float *visualkey_get_values( Object *ob = ptr->data; /* Loc code is specific... */ if (strstr(identifier, "location")) { - copy_v3_v3(buffer, ob->obmat[3]); + copy_v3_v3(buffer, ob->object_to_world[3]); *r_count = 3; return buffer; } - copy_m4_m4(tmat, ob->obmat); + copy_m4_m4(tmat, ob->object_to_world); rotmode = ob->rotmode; } else if (ptr->type == &RNA_PoseBone) { diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 17484b2b0b7..fbdb375b8a6 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -181,13 +181,13 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) const View3DCursor *curs = &scene->cursor; copy_v3_v3(newbone->tail, curs->location); - sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]); + sub_v3_v3v3(newbone->tail, newbone->tail, obedit->object_to_world[3]); if (a == 1) { newbone->tail[0] = -newbone->tail[0]; } - copy_m3_m4(mat, obedit->obmat); + copy_m3_m4(mat, obedit->object_to_world); invert_m3_m3(imat, mat); mul_m3_v3(imat, newbone->tail); @@ -1569,7 +1569,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) copy_v3_v3(curs, CTX_data_scene(C)->cursor.location); /* Get inverse point for head and orientation for tail */ - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_v3(obedit->imat, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) { @@ -1579,7 +1579,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) unit_m3(obmat); } - copy_m3_m4(viewmat, obedit->obmat); + copy_m3_m4(viewmat, obedit->object_to_world); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 9e828ebd501..810279f1b6c 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -113,7 +113,7 @@ void ED_armature_origin_set( /* Find the center-point. */ if (centermode == 2) { copy_v3_v3(cent, cursor); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, cent); } else { @@ -154,7 +154,7 @@ void ED_armature_origin_set( /* Adjust object location for new center-point. */ if (centermode && (is_editmode == false)) { - mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */ + mul_mat3_m4_v3(ob->object_to_world, cent); /* omit translation part */ add_v3_v3(ob->loc, cent); } } @@ -282,14 +282,14 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) axis_flip = true; } - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3(imat); if (type == CALC_ROLL_CURSOR) { /* Cursor */ float cursor_local[3]; const View3DCursor *cursor = &scene->cursor; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_v3_v3(cursor_local, cursor->location); mul_m4_v3(ob->imat, cursor_local); @@ -730,7 +730,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) ebp = points.first; /* Get points - cursor (tail) */ - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_v3_m4v3(curs, obedit->imat, scene->cursor.location); /* Create a bone */ @@ -767,7 +767,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) float dist_sq_a, dist_sq_b; /* get cursor location */ - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_v3_m4v3(curs, obedit->imat, scene->cursor.location); /* get distances */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 9f1883ccac0..fccf2964868 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -289,7 +289,7 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op) /* Inverse transform for all selected armatures in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ - invert_m4_m4_safe_ortho(oimat, ob_active->obmat); + invert_m4_m4_safe_ortho(oimat, ob_active->object_to_world); /* Get edit-bones of active armature to add edit-bones to */ ED_armature_to_edit(arm); @@ -321,7 +321,7 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op) // BASACT->flag &= ~OB_MODE_POSE; /* Find the difference matrix */ - mul_m4_m4m4(mat, oimat, ob_iter->obmat); + mul_m4_m4m4(mat, oimat, ob_iter->object_to_world); /* Copy bones and posechannels from the object to the edit armature */ for (pchan = opose->chanbase.first; pchan; pchan = pchann) { diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 6b8f790d30f..3ee0510ca7f 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -1601,8 +1601,8 @@ static const EnumPropertyItem prop_similar_types[] = { static float bone_length_squared_worldspace_get(Object *ob, EditBone *ebone) { float v1[3], v2[3]; - mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head); - mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail); + mul_v3_mat3_m4v3(v1, ob->object_to_world, ebone->head); + mul_v3_mat3_m4v3(v2, ob->object_to_world, ebone->tail); return len_squared_v3v3(v1, v2); } @@ -1650,8 +1650,8 @@ static void bone_direction_worldspace_get(Object *ob, EditBone *ebone, float *r_ copy_v3_v3(v1, ebone->head); copy_v3_v3(v2, ebone->tail); - mul_m4_v3(ob->obmat, v1); - mul_m4_v3(ob->obmat, v2); + mul_m4_v3(ob->object_to_world, v1); + mul_m4_v3(ob->object_to_world, v2); sub_v3_v3v3(r_dir, v1, v2); normalize_v3(r_dir); diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 6155aac621d..3c9c8cf05b3 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -365,8 +365,8 @@ static void add_verts_to_dgroups(ReportList *reports, copy_v3_v3(tip[j], bone->arm_tail); } - mul_m4_v3(par->obmat, root[j]); - mul_m4_v3(par->obmat, tip[j]); + mul_m4_v3(par->object_to_world, root[j]); + mul_m4_v3(par->object_to_world, tip[j]); /* set selected */ if (wpmode) { @@ -414,7 +414,7 @@ static void add_verts_to_dgroups(ReportList *reports, if (!vertsfilled) { copy_v3_v3(verts[i], mesh_verts[i].co); } - mul_m4_v3(ob->obmat, verts[i]); + mul_m4_v3(ob->object_to_world, verts[i]); } /* compute the weights based on gathered vertices and bones */ @@ -438,7 +438,7 @@ static void add_verts_to_dgroups(ReportList *reports, root, tip, selected, - mat4_to_scale(par->obmat)); + mat4_to_scale(par->object_to_world)); } /* only generated in some cases but can call anyway */ diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 09174aa5e47..0465606e694 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -703,11 +703,11 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) newBone->inherit_scale_mode = eBone->inherit_scale_mode; if (eBone == arm->act_edbone) { - /* don't change active selection, this messes up separate which uses - * editmode toggle and can separate active bone which is de-selected originally */ + /* Don't change active selection, this messes up separate which uses + * edit-mode toggle and can separate active bone which is de-selected originally. */ - /* important, editbones can be active with only 1 point selected */ - /* newBone->flag |= BONE_SELECTED; */ + /* important, edit-bones can be active with only 1 point selected */ + /* `newBone->flag |= BONE_SELECTED;` */ arm->act_bone = newBone; } newBone->roll = 0.0f; diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 567977e51c4..dfb9e8a79fa 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -1788,11 +1788,11 @@ void ED_mesh_deform_bind_callback(Object *object, mmd_orig->bindcagecos = (float *)mdb.cagecos; mmd_orig->verts_num = mdb.verts_num; mmd_orig->cage_verts_num = mdb.cage_verts_num; - copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->obmat); + copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->object_to_world); /* transform bindcagecos to world space */ for (a = 0; a < mdb.cage_verts_num; a++) { - mul_m4_v3(mmd_orig->object->obmat, mmd_orig->bindcagecos + a * 3); + mul_m4_v3(mmd_orig->object->object_to_world, mmd_orig->bindcagecos + a * 3); } /* free */ diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 9ed963f0c66..51071815823 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -77,10 +77,10 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec /* apply current transform from parent (not yet destroyed), * then calculate new parent inverse matrix */ - BKE_object_apply_mat4(ob, ob->obmat, false, false); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } } } @@ -361,7 +361,7 @@ static void applyarmature_reset_constraints(bPose *pose, const bool use_selected } } -/* set the current pose as the restpose */ +/* Set the current pose as the rest-pose. */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -404,10 +404,10 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) } } - /* Get editbones of active armature to alter */ + /* Get edit-bones of active armature to alter. */ ED_armature_to_edit(arm); - /* get pose of active object and move it out of posemode */ + /* Get pose of active object and move it out of pose-mode. */ pose = ob->pose; if (use_selected) { @@ -429,11 +429,11 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) } } - /* convert editbones back to bones, and then free the edit-data */ + /* Convert edit-bones back to bones, and then free the edit-data. */ ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); - /* flush positions of posebones */ + /* Flush positions of pose-bones. */ BKE_pose_where_is(depsgraph, scene, ob); /* fix parenting of objects which are bone-parented */ diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h index b54f81004f2..3d2aaa3bda1 100644 --- a/source/blender/editors/asset/ED_asset_list.h +++ b/source/blender/editors/asset/ED_asset_list.h @@ -23,6 +23,7 @@ struct wmNotifier; */ void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference, const struct bContext *C); +bool ED_assetlist_is_loaded(const struct AssetLibraryReference *library_reference); void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference, const struct bContext *C); void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C); diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index b641c9d6ffc..fc71882d88f 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -355,7 +355,7 @@ void AssetListStorage::fetch_library(const AssetLibraryReference &library_refere void AssetListStorage::destruct() { - global_storage().~AssetListMap(); + global_storage().clear(); } AssetList *AssetListStorage::lookup_list(const AssetLibraryReference &library_ref) @@ -427,6 +427,18 @@ void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, AssetListStorage::fetch_library(*library_reference, *C); } +bool ED_assetlist_is_loaded(const AssetLibraryReference *library_reference) +{ + AssetList *list = AssetListStorage::lookup_list(*library_reference); + if (!list) { + return false; + } + if (list->needsRefetch()) { + return false; + } + return true; +} + void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, const bContext *C) { diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 61e92f0a1c3..2b6cce25bb7 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4999,7 +4999,7 @@ bool ed_editnurb_spin( invert_m3_m3(persinv, persmat); /* imat and center and size */ - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); invert_m3_m3(imat, bmat); axis_angle_to_mat3(cmat, axis, M_PI_4); @@ -5095,7 +5095,7 @@ static int spin_exec(bContext *C, wmOperator *op) continue; } - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_v3(obedit->imat, cent); if (!ed_editnurb_spin(viewmat, v3d, obedit, axis, cent)) { @@ -5574,7 +5574,7 @@ static int add_vertex_exec(bContext *C, wmOperator *op) RNA_float_get_array(op->ptr, "location", location); - invert_m4_m4(imat, obedit->obmat); + invert_m4_m4(imat, obedit->object_to_world); mul_m4_v3(imat, location); if (ed_editcurve_addvert(cu, editnurb, v3d, location)) { @@ -5614,10 +5614,10 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_curve_nurb_vert_selected_find(cu, vc.v3d, &nu, &bezt, &bp); if (bezt) { - mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]); + mul_v3_m4v3(location, vc.obedit->object_to_world, bezt->vec[1]); } else if (bp) { - mul_v3_m4v3(location, vc.obedit->obmat, bp->vec); + mul_v3_m4v3(location, vc.obedit->object_to_world, bp->vec); } else { copy_v3_v3(location, vc.scene->cursor.location); @@ -5662,8 +5662,8 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* get the plane */ float plane[4]; /* only normalize to avoid precision errors */ - normalize_v3_v3(plane, vc.obedit->obmat[2]); - plane[3] = -dot_v3v3(plane, vc.obedit->obmat[3]); + normalize_v3_v3(plane, vc.obedit->object_to_world[2]); + plane[3] = -dot_v3v3(plane, vc.obedit->object_to_world[3]); if (fabsf(dot_v3v3(view_dir, plane)) < eps) { /* can't project on an aligned plane. */ @@ -6924,7 +6924,7 @@ int ED_curve_join_objects_exec(bContext *C, wmOperator *op) /* Inverse transform for all selected curves in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ - invert_m4_m4_safe_ortho(imat, ob_active->obmat); + invert_m4_m4_safe_ortho(imat, ob_active->object_to_world); Curve *cu_active = ob_active->data; @@ -6936,7 +6936,7 @@ int ED_curve_join_objects_exec(bContext *C, wmOperator *op) if (cu->nurb.first) { /* watch it: switch order here really goes wrong */ - mul_m4_m4m4(cmat, imat, ob_iter->obmat); + mul_m4_m4m4(cmat, imat, ob_iter->object_to_world); /* Compensate for different bevel depth. */ bool do_radius = false; diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 7632f1b1e64..1e91e2f48fc 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -148,7 +148,7 @@ static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) - stroke_elem_radius_from_pressure(cdd, selem->pressure); madd_v3_v3fl(selem->location_local, selem->normal_local, adjust); - mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local); + mul_v3_m4v3(selem->location_world, cdd->vc.obedit->object_to_world, selem->location_local); } selem->pressure = pressure; } @@ -249,7 +249,7 @@ static bool stroke_elem_project_fallback(const struct CurveDrawData *cdd, if (!is_zero_v3(r_normal_world)) { copy_v3_v3(r_normal_local, r_normal_world); - mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local); + mul_transposed_mat3_m4_v3(cdd->vc.obedit->object_to_world, r_normal_local); normalize_v3(r_normal_local); } else { @@ -367,7 +367,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), /* scale to edit-mode space */ GPU_matrix_push(); - GPU_matrix_mul(obedit->obmat); + GPU_matrix_mul(obedit->object_to_world); BLI_mempool_iternew(cdd->stroke_elem_pool, &iter); for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) { @@ -445,7 +445,7 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event) struct CurveDrawData *cdd = op->customdata; Object *obedit = cdd->vc.obedit; - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool); @@ -758,7 +758,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op) int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool); const bool is_3d = (cu->flag & CU_3D) != 0; - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); if (BLI_mempool_len(cdd->stroke_elem_pool) == 0) { curve_draw_stroke_from_operator(op); @@ -1073,8 +1073,8 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (CU_IS_2D(cu)) { /* 2D overrides other options */ - plane_co = obedit->obmat[3]; - plane_no = obedit->obmat[2]; + plane_co = obedit->object_to_world[3]; + plane_no = obedit->object_to_world[2]; cdd->project.use_plane = true; } else { diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c index f71173f951e..b57ce6fc7cf 100644 --- a/source/blender/editors/curve/editcurve_pen.c +++ b/source/blender/editors/curve/editcurve_pen.c @@ -152,8 +152,8 @@ static void update_location_for_2d_curve(const ViewContext *vc, float location[3 /* Get the plane. */ float plane[4]; /* Only normalize to avoid precision errors. */ - normalize_v3_v3(plane, vc->obedit->obmat[2]); - plane[3] = -dot_v3v3(plane, vc->obedit->obmat[3]); + normalize_v3_v3(plane, vc->obedit->object_to_world[2]); + plane[3] = -dot_v3v3(plane, vc->obedit->object_to_world[3]); if (fabsf(dot_v3v3(view_dir, plane)) < eps) { /* Can't project on an aligned plane. */ @@ -173,7 +173,7 @@ static void update_location_for_2d_curve(const ViewContext *vc, float location[3 } float imat[4][4]; - invert_m4_m4(imat, vc->obedit->obmat); + invert_m4_m4(imat, vc->obedit->object_to_world); mul_m4_v3(imat, location); if (CU_IS_2D(cu)) { @@ -186,7 +186,7 @@ static void screenspace_to_worldspace(const ViewContext *vc, const float depth[3], float r_pos_3d[3]) { - mul_v3_m4v3(r_pos_3d, vc->obedit->obmat, depth); + mul_v3_m4v3(r_pos_3d, vc->obedit->object_to_world, depth); ED_view3d_win_to_3d(vc->v3d, vc->region, r_pos_3d, pos_2d, r_pos_3d); update_location_for_2d_curve(vc, r_pos_3d); } @@ -1082,7 +1082,7 @@ static void extrude_points_from_selected_vertices(const ViewContext *vc, float location[3]; if (sel_exists) { - mul_v3_m4v3(location, vc->obedit->obmat, center); + mul_v3_m4v3(location, vc->obedit->object_to_world, center); } else { copy_v3_v3(location, vc->scene->cursor.location); diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index 9c0c580f699..da742dd0c61 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -1517,7 +1517,7 @@ static void nurb_bezt_direction_worldspace_get(Object *ob, { float rsmat[3][3]; BKE_nurb_bezt_calc_normal(nu, bezt, r_dir); - copy_m3_m4(rsmat, ob->obmat); + copy_m3_m4(rsmat, ob->object_to_world); mul_m3_v3(rsmat, r_dir); normalize_v3(r_dir); } @@ -1526,7 +1526,7 @@ static void nurb_bpoint_direction_worldspace_get(Object *ob, Nurb *nu, BPoint *b { float rsmat[3][3]; BKE_nurb_bpoint_calc_normal(nu, bp, r_dir); - copy_m3_m4(rsmat, ob->obmat); + copy_m3_m4(rsmat, ob->object_to_world); mul_m3_v3(rsmat, r_dir); normalize_v3(r_dir); } diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index 38b2b2071b8..1d2b1264477 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -435,7 +435,7 @@ static bke::CurvesGeometry particles_to_curves(Object &object, ParticleSystem &p bke::CurvesGeometry curves(points_num, curves_num); curves.offsets_for_write().copy_from(curve_offsets); - const float4x4 object_to_world_mat = object.obmat; + const float4x4 object_to_world_mat = object.object_to_world; const float4x4 world_to_object_mat = object_to_world_mat.inverted(); MutableSpan<float3> positions = curves.positions_for_write(); @@ -497,7 +497,7 @@ static int curves_convert_from_particle_system_exec(bContext *C, wmOperator * /* Object *ob_new = BKE_object_add(&bmain, &scene, &view_layer, OB_CURVES, psys_eval->name); Curves *curves_id = static_cast<Curves *>(ob_new->data); - BKE_object_apply_mat4(ob_new, ob_from_orig->obmat, true, false); + BKE_object_apply_mat4(ob_new, ob_from_orig->object_to_world, true, false); bke::CurvesGeometry::wrap(curves_id->geometry) = particles_to_curves(*ob_from_eval, *psys_eval); DEG_relations_tag_update(&bmain); diff --git a/source/blender/editors/gizmo_library/gizmo_library_presets.c b/source/blender/editors/gizmo_library/gizmo_library_presets.c index 1ac4ce0bcdf..465c72dd44f 100644 --- a/source/blender/editors/gizmo_library/gizmo_library_presets.c +++ b/source/blender/editors/gizmo_library/gizmo_library_presets.c @@ -114,7 +114,7 @@ void ED_gizmo_draw_preset_facemap( } GPU_matrix_push(); - GPU_matrix_mul(ob->obmat); + GPU_matrix_mul(ob->object_to_world); ED_draw_object_facemap(depsgraph, ob, color, facemap); GPU_matrix_pop(); diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 677bf1bb392..2fd58a9cee0 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -13,9 +13,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_math_geom.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index 5f5a4b41b27..2b7e09b7f05 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -329,8 +329,8 @@ static void gpencil_add_verts_to_dgroups( copy_v3_v3(tip[j], bone->arm_tail); } - mul_m4_v3(ob_arm->obmat, root[j]); - mul_m4_v3(ob_arm->obmat, tip[j]); + mul_m4_v3(ob_arm->object_to_world, root[j]); + mul_m4_v3(ob_arm->object_to_world, tip[j]); selected[j] = 1; @@ -364,7 +364,7 @@ static void gpencil_add_verts_to_dgroups( /* transform stroke points to global space */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { copy_v3_v3(verts[i], &pt->x); - mul_m4_v3(ob->obmat, verts[i]); + mul_m4_v3(ob->object_to_world, verts[i]); } /* loop groups and assign weight */ diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.cc b/source/blender/editors/gpencil/gpencil_bake_animation.cc index 1535fd614fe..4ef2cf9ffd6 100644 --- a/source/blender/editors/gpencil/gpencil_bake_animation.cc +++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc @@ -222,7 +222,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; ob_gpencil = ED_gpencil_add_object(C, scene->cursor.location, local_view_bits); float invmat[4][4]; - invert_m4_m4(invmat, ob_gpencil->obmat); + invert_m4_m4(invmat, ob_gpencil->object_to_world); bGPdata *gpd_dst = (bGPdata *)ob_gpencil->data; gpd_dst->draw_mode = GP_DRAWMODE_2D; @@ -323,7 +323,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op bGPDspoint *pt = &gps->points[j]; pt->runtime.idx_orig = 0; pt->runtime.pt_orig = nullptr; - mul_m4_v3(ob_eval->obmat, &pt->x); + mul_m4_v3(ob_eval->object_to_world, &pt->x); mul_m4_v3(invmat, &pt->x); } diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c6d7eb294fb..0417694d7bd 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -2914,8 +2914,8 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) float offset_global[3]; float offset_local[3]; - sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]); - copy_m3_m4(bmat, ob_active->obmat); + sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->object_to_world[3]); + copy_m3_m4(bmat, ob_active->object_to_world); /* Inverse transform for all selected curves in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 6181b9810e3..f9b40a4c79b 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3848,7 +3848,12 @@ static int gpencil_stroke_start_set_exec(bContext *C, wmOperator *op) for (int i = 0; i < gps->totpoints; i++) { pt = &gps->points[i]; if (pt->flag & GP_SPOINT_SELECT) { - BKE_gpencil_stroke_start_set(gps, i); + if (i == gps->totpoints - 1) { + BKE_gpencil_stroke_flip(gps); + } + else { + BKE_gpencil_stroke_start_set(gps, i); + } BKE_gpencil_stroke_geometry_update(gpd, gps); changed = true; break; @@ -4157,7 +4162,7 @@ static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Object *cam_ob = scene->camera; if (cam_ob != NULL) { - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); } break; } @@ -4224,7 +4229,7 @@ static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op) /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Stroke. */ diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index b94b413edc2..5c88e719b8c 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -317,7 +317,7 @@ static void add_endpoint_radius_help(tGPDfill *tgpf, /* Rotate to object rotation. */ sub_v3_v3(&pt->x, endpoint); - mul_mat3_m4_v3(tgpf->ob->obmat, &pt->x); + mul_mat3_m4_v3(tgpf->ob->object_to_world, &pt->x); add_v3_v3(&pt->x, endpoint); } } diff --git a/source/blender/editors/gpencil/gpencil_mesh.cc b/source/blender/editors/gpencil/gpencil_mesh.cc index d847fbe2aea..2b01fce5bf8 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.cc +++ b/source/blender/editors/gpencil/gpencil_mesh.cc @@ -299,7 +299,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) angle, thickness, offset, - ob_eval->obmat, + ob_eval->object_to_world, frame_offset, use_seams, use_faces, diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index a82288e3377..d2ed1720bf8 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -936,7 +936,7 @@ static bGPDstroke *gpencil_stroke_to_outline(tGPsdata *p, bGPDstroke *gps) /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(p->ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(p->ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Stroke. */ diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 9b934876ebb..515bdeb6188 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -671,7 +671,7 @@ static bool gpencil_brush_pinch_apply(tGP_BrushEditData *gso, /* 1) Make this point relative to the cursor/midpoint (dvec) */ float fpt[3]; - mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + mul_v3_m4v3(fpt, gso->object->object_to_world, &pt->x); sub_v3_v3v3(vec, fpt, gso->dvec); /* 2) Shrink the distance by pulling the point towards the midpoint @@ -743,7 +743,7 @@ static bool gpencil_brush_twist_apply(tGP_BrushEditData *gso, /* Rotate point */ float fpt[3]; - mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + mul_v3_m4v3(fpt, gso->object->object_to_world, &pt->x); sub_v3_v3v3(vec, fpt, gso->dvec); /* make relative to center * (center is stored in dvec) */ mul_m3_v3(rmat, vec); @@ -1037,7 +1037,7 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso) */ for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) { /* Rotate around center new position */ - mul_mat3_m4_v3(gso->object->obmat, &pt->x); /* only rotation component */ + mul_mat3_m4_v3(gso->object->object_to_world, &pt->x); /* only rotation component */ /* assume that the delta can just be applied, and then everything works */ add_v3_v3(&pt->x, delta); @@ -1172,7 +1172,7 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) gso->object = ob; if (ob) { float matrix[4][4]; - copy_m4_m4(matrix, ob->obmat); + copy_m4_m4(matrix, ob->object_to_world); zero_axis_bias_m4(matrix); invert_m4_m4(gso->inv_mat, matrix); gso->vrgroup = gso->gpd->vertex_group_active_index - 1; @@ -1202,6 +1202,9 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) gso->automasking_strokes = BLI_ghash_ptr_new(__func__); } else { + if (gso->automasking_strokes != NULL) { + BLI_ghash_free(gso->automasking_strokes, NULL, NULL); + } gso->automasking_strokes = NULL; } /* save mask */ @@ -1292,6 +1295,10 @@ static void gpencil_sculpt_brush_exit(bContext *C, wmOperator *op) } default: + if (gso->stroke_customdata != NULL) { + BLI_ghash_free(gso->stroke_customdata, NULL, NULL); + gso->stroke_customdata = NULL; + } break; } @@ -2075,6 +2082,20 @@ static void gpencil_sculpt_brush_apply_event(bContext *C, wmOperator *op, const if (gso->brush == NULL) { gso->brush = gso->brush_prev; } + Brush *brush = gso->brush; + if (brush->gpencil_settings->sculpt_mode_flag & + (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER | + GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) { + if (gso->automasking_strokes == NULL) { + gso->automasking_strokes = BLI_ghash_ptr_new(__func__); + } + } + else { + if (gso->automasking_strokes != NULL) { + BLI_ghash_free(gso->automasking_strokes, NULL, NULL); + } + gso->automasking_strokes = NULL; + } } else { if (gso->brush_prev != NULL) { diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index cc13f667e48..7d814b43196 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -900,7 +900,7 @@ void ED_gpencil_drawing_reference_get(const Scene *scene, } else { /* use object location */ - copy_v3_v3(r_vec, ob->obmat[3]); + copy_v3_v3(r_vec, ob->object_to_world[3]); /* Apply layer offset. */ bGPdata *gpd = ob->data; bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); @@ -984,7 +984,7 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene, /* if object, apply object rotation */ if (ob && (ob->type == OB_GPENCIL)) { float mat[4][4]; - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); /* move origin to cursor */ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { @@ -1206,7 +1206,7 @@ void ED_gpencil_project_point_to_plane(const Scene *scene, /* if object, apply object rotation */ if (ob && (ob->type == OB_GPENCIL)) { float mat[4][4]; - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { if (gpl != NULL) { add_v3_v3(mat[3], gpl->location); @@ -1233,7 +1233,7 @@ void ED_gpencil_project_point_to_plane(const Scene *scene, /* move origin to object */ if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { - copy_v3_v3(mat[3], ob->obmat[3]); + copy_v3_v3(mat[3], ob->object_to_world[3]); } mul_mat3_m4_v3(mat, plane_normal); @@ -1365,16 +1365,16 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata if (gpl->parent != NULL) { /* calculate new matrix */ if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) { - invert_m4_m4(cur_mat, gpl->parent->obmat); - copy_v3_v3(gpl_loc, obact->obmat[3]); + invert_m4_m4(cur_mat, gpl->parent->object_to_world); + copy_v3_v3(gpl_loc, obact->object_to_world[3]); } else if (gpl->partype == PARBONE) { bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr); if (pchan) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat); + mul_m4_m4m4(tmp_mat, gpl->parent->object_to_world, pchan->pose_mat); invert_m4_m4(cur_mat, tmp_mat); - copy_v3_v3(gpl_loc, obact->obmat[3]); + copy_v3_v3(gpl_loc, obact->object_to_world[3]); } } diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index 51cb08cf592..0144ffa07c7 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -138,7 +138,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) opdata->array_loc = NULL; opdata->array_rot = NULL; opdata->array_scale = NULL; - opdata->ob_scale = mat4_to_scale(opdata->ob->obmat); + opdata->ob_scale = mat4_to_scale(opdata->ob->object_to_world); opdata->vinit_rotation[0] = 1.0f; opdata->vinit_rotation[1] = 0.0f; @@ -158,7 +158,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op) float r_center[3]; gpencil_stroke_center(gps, r_center); /* Add object location. */ - add_v3_v3(r_center, opdata->ob->obmat[3]); + add_v3_v3(r_center, opdata->ob->object_to_world[3]); add_v3_v3(center, r_center); i++; } diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index c8ffbb9acb1..b97cd6a9099 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -345,12 +345,14 @@ typedef enum { ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */ } eUVPackIsland_MarginMethod; +/** See also #UnwrapOptions. */ struct UVPackIsland_Params { uint rotate : 1; uint only_selected_uvs : 1; uint only_selected_faces : 1; uint use_seams : 1; uint correct_aspect : 1; + bool ignore_pinned; /* Ignore islands which have any pinned UVs. */ eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */ float margin; /* Additional space to add around each island. */ }; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 2a1941f0d9e..1098266331f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -784,6 +784,9 @@ void UI_block_set_search_only(uiBlock *block, bool search_only); * Can be called with C==NULL. */ void UI_block_free(const struct bContext *C, uiBlock *block); + +void UI_block_listen(const uiBlock *block, const struct wmRegionListenerParams *listener_params); + /** * Can be called with C==NULL. */ @@ -1683,6 +1686,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name); * Adds a hint to the button which draws right aligned, grayed out and never clipped. */ void UI_but_hint_drawstr_set(uiBut *but, const char *string); +void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number); void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]); @@ -2524,6 +2528,7 @@ void uiTemplateNodeView(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); +void uiTemplateNodeAssetMenuItems(uiLayout *layout, struct bContext *C, const char *catalog_path); void uiTemplateTextureUser(uiLayout *layout, struct bContext *C); /** * Button to quickly show texture in Properties Editor texture tab. @@ -2788,7 +2793,8 @@ typedef struct uiPropertySplitWrapper { uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout); void uiItemL(uiLayout *layout, const char *name, int icon); /* label */ -void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert); +struct uiBut *uiItemL_ex( + uiLayout *layout, const char *name, int icon, bool highlight, bool redalert); /** * Helper to add a label and creates a property split layout if needed. */ @@ -3195,9 +3201,6 @@ void UI_interface_tag_script_reload(void); /* Support click-drag motion which presses the button and closes a popover (like a menu). */ #define USE_UI_POPOVER_ONCE -void UI_block_views_listen(const uiBlock *block, - const struct wmRegionListenerParams *listener_params); - bool UI_view_item_is_active(const uiViewItemHandle *item_handle); bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle); /** diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index 6c756984203..fc03b0218c0 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -35,6 +35,7 @@ struct ContextPathItem { std::string name; /* #BIFIconID */ int icon; + int icon_indicator_number; }; void context_path_add_generic(Vector<ContextPathItem> &path, diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index a1a98a4b08c..9669e242dac 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -27,6 +27,12 @@ typedef struct IconFile { int index; } IconFile; +typedef struct IconTextOverlay { + char text[5]; +} IconTextOverlay; + +#define UI_NO_ICON_OVERLAY_TEXT NULL + #define ICON_DEFAULT_HEIGHT 16 #define ICON_DEFAULT_WIDTH 16 @@ -105,7 +111,8 @@ void UI_icon_draw_ex(float x, float alpha, float desaturate, const uchar mono_color[4], - bool mono_border); + bool mono_border, + const struct IconTextOverlay *text_overlay); void UI_icons_free(void); void UI_icons_free_drawinfo(void *drawinfo); @@ -124,6 +131,9 @@ int UI_icon_from_library(const struct ID *id); int UI_icon_from_object_mode(int mode); int UI_icon_color_from_collection(const struct Collection *collection); +void UI_icon_text_overlay_init_from_count(struct IconTextOverlay *text_overlay, + const int icon_indicator_number); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_depth.c b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c index 3fb5a74944b..c6d950112b9 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_depth.c +++ b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c @@ -162,7 +162,7 @@ static void depthdropper_depth_sample_pt(bContext *C, View3D *v3d = area->spacedata.first; RegionView3D *rv3d = region->regiondata; /* weak, we could pass in some reference point */ - const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; + const float *view_co = v3d->camera ? v3d->camera->object_to_world[3] : rv3d->viewinv[3]; const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin}; copy_v2_v2_int(ddr->name_pos, mval); diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index 422fc34aa50..331d1581db5 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -3474,6 +3474,7 @@ void UI_block_free(const bContext *C, uiBlock *block) BLI_freelistN(&block->saferct); BLI_freelistN(&block->color_pickers.list); + BLI_freelistN(&block->dynamic_listeners); ui_block_free_button_groups(block); ui_block_free_views(block); @@ -3481,6 +3482,20 @@ void UI_block_free(const bContext *C, uiBlock *block) MEM_freeN(block); } +void UI_block_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) +{ + /* Don't need to let invisible blocks (old blocks from previous redraw) listen. */ + if (!block->active) { + return; + } + + LISTBASE_FOREACH (uiBlockDynamicListener *, listener, &block->dynamic_listeners) { + listener->listener_func(listener_params); + } + + ui_block_views_listen(block, listener_params); +} + void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb) { ARegion *region = CTX_wm_region(C); @@ -6452,6 +6467,11 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string) ui_but_add_shortcut(but, string, false); } +void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number) +{ + UI_icon_text_overlay_init_from_count(&but->icon_overlay_text, indicator_number); +} + void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4]) { but->flag |= UI_BUT_NODE_LINK; diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc index e8f552e26a3..74a07d6edc8 100644 --- a/source/blender/editors/interface/interface_context_path.cc +++ b/source/blender/editors/interface/interface_context_path.cc @@ -17,6 +17,8 @@ #include "UI_interface.hh" #include "UI_resources.h" +#include "RNA_prototypes.h" + #include "WM_api.h" namespace blender::ui { @@ -41,7 +43,13 @@ void context_path_add_generic(Vector<ContextPathItem> &path, static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) : icon_override; - path.append({name, int(icon)}); + if (&rna_type == &RNA_NodeTree) { + ID *id = (ID *)ptr; + path.append({name, int(icon), ID_REAL_USERS(id)}); + } + else { + path.append({name, int(icon), 1}); + } } /* -------------------------------------------------------------------- */ @@ -60,7 +68,9 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path) if (i > 0) { uiItemL(sub_row, "", ICON_RIGHTARROW_THIN); } - uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon); + uiBut *but = uiItemL_ex( + sub_row, context_path[i].name.c_str(), context_path[i].icon, false, false); + UI_but_icon_indicator_number_set(but, context_path[i].icon_indicator_number); } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a45721e2c64..a5c786358d6 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3519,7 +3519,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) { - /* label and roundbox can overlap real buttons (backdrops...) */ + /* Label and round-box can overlap real buttons (backdrops...). */ if (ELEM(actbut->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, @@ -3551,7 +3551,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) { - /* label and roundbox can overlap real buttons (backdrops...) */ + /* Label and round-box can overlap real buttons (backdrops...). */ if (ELEM(actbut->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, @@ -3894,7 +3894,7 @@ static void ui_do_but_textedit( } if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) { if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) && - strcmp(ime_data->str_result, "\xE3\x80\x82") == 0) { + STREQ(ime_data->str_result, "\xE3\x80\x82")) { /* Convert Ideographic Full Stop (U+3002) to decimal point when entering numbers. */ ui_textedit_insert_ascii(but, data, '.'); } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index deb3d84ae66..9a4f98ebcd6 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -415,8 +415,15 @@ static void vicon_collection_color_draw( const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex( - x, y, ICON_OUTLINER_COLLECTION, aspect, 1.0f, 0.0f, collection_color->color, true); + UI_icon_draw_ex(x, + y, + ICON_OUTLINER_COLLECTION, + aspect, + 1.0f, + 0.0f, + collection_color->color, + true, + UI_NO_ICON_OVERLAY_TEXT); } # define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \ @@ -444,7 +451,8 @@ static void vicon_strip_color_draw( const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex(x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true); + UI_icon_draw_ex( + x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true, UI_NO_ICON_OVERLAY_TEXT); } # define DEF_ICON_STRIP_COLOR_DRAW(index, color) \ @@ -472,8 +480,15 @@ static void vicon_strip_color_draw_library_data_indirect( { const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; - UI_icon_draw_ex( - x, y, ICON_LIBRARY_DATA_DIRECT, aspect, ICON_INDIRECT_DATA_ALPHA * alpha, 0.0f, NULL, false); + UI_icon_draw_ex(x, + y, + ICON_LIBRARY_DATA_DIRECT, + aspect, + ICON_INDIRECT_DATA_ALPHA * alpha, + 0.0f, + NULL, + false, + UI_NO_ICON_OVERLAY_TEXT); } static void vicon_strip_color_draw_library_data_override_noneditable( @@ -488,7 +503,8 @@ static void vicon_strip_color_draw_library_data_override_noneditable( ICON_INDIRECT_DATA_ALPHA * alpha * 0.75f, 0.0f, NULL, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); } /* Dynamically render icon instead of rendering a plain color to a texture/buffer @@ -1716,9 +1732,47 @@ static void icon_draw_texture(float x, int ih, float alpha, const float rgb[3], - bool with_border) -{ - if (g_icon_draw_cache.enabled) { + bool with_border, + const IconTextOverlay *text_overlay) +{ + const float zoom_factor = w / UI_DPI_ICON_SIZE; + float text_width = 0.0f; + + /* No need to show if too zoomed out, otherwise it just adds noise. */ + const bool show_indicator = (text_overlay && text_overlay->text[0] != '\0') && + (zoom_factor > 0.7f); + + if (show_indicator) { + /* Handle the little numbers on top of the icon. */ + uchar text_color[4]; + UI_GetThemeColor3ubv(TH_TEXT, text_color); + text_color[3] = 255; + + uiFontStyle fstyle_small = *UI_FSTYLE_WIDGET; + fstyle_small.points *= zoom_factor; + fstyle_small.points *= 0.8f; + + rcti text_rect = { + .xmax = x + UI_UNIT_X * zoom_factor, + .xmin = x, + .ymax = y, + .ymin = y, + }; + + UI_fontstyle_draw(&fstyle_small, + &text_rect, + text_overlay->text, + sizeof(text_overlay->text), + text_color, + &(struct uiFontStyleDraw_Params){ + .align = UI_STYLE_TEXT_RIGHT, + }); + text_width = (float)UI_fontstyle_string_width(&fstyle_small, text_overlay->text) / UI_UNIT_X / + zoom_factor; + } + + /* Draw the actual icon. */ + if (!show_indicator && g_icon_draw_cache.enabled) { icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border); return; } @@ -1735,7 +1789,7 @@ static void icon_draw_texture(float x, GPUTexture *texture = with_border ? icongltex.tex[1] : icongltex.tex[0]; - GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON); GPU_shader_bind(shader); const int img_binding = GPU_shader_get_texture_binding(shader, "image"); @@ -1752,6 +1806,7 @@ static void icon_draw_texture(float x, GPU_shader_uniform_vector(shader, rect_tex_loc, 4, 1, (float[4]){x1, y1, x2, y2}); GPU_shader_uniform_vector(shader, rect_geom_loc, 4, 1, (float[4]){x, y, x + w, y + h}); + GPU_shader_uniform_1f(shader, "text_width", text_width); GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false); @@ -1786,7 +1841,8 @@ static void icon_draw_size(float x, int draw_size, const float desaturate, const uchar mono_rgba[4], - const bool mono_border) + const bool mono_border, + const IconTextOverlay *text_overlay) { bTheme *btheme = UI_GetTheme(); const float fdraw_size = (float)draw_size; @@ -1874,7 +1930,8 @@ static void icon_draw_size(float x, di->data.texture.h, alpha, NULL, - false); + false, + text_overlay); } else if (di->type == ICON_TYPE_MONO_TEXTURE) { /* Monochrome icon that uses text or theme color. */ @@ -1908,7 +1965,8 @@ static void icon_draw_size(float x, di->data.texture.h + 2 * border_texel, color[3], color, - with_border); + with_border, + text_overlay); } else if (di->type == ICON_TYPE_BUFFER) { @@ -2425,17 +2483,27 @@ int UI_icon_color_from_collection(const Collection *collection) void UI_icon_draw(float x, float y, int icon_id) { - UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha) { - UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size) { - icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false); + icon_draw_size(x, + y, + icon_id, + aspect, + alpha, + ICON_SIZE_PREVIEW, + size, + false, + NULL, + false, + UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_ex(float x, @@ -2445,7 +2513,8 @@ void UI_icon_draw_ex(float x, float alpha, float desaturate, const uchar mono_color[4], - const bool mono_border) + const bool mono_border, + const IconTextOverlay *text_overlay) { const int draw_size = get_draw_size(ICON_SIZE_ICON); icon_draw_size(x, @@ -2457,7 +2526,19 @@ void UI_icon_draw_ex(float x, draw_size, desaturate, mono_color, - mono_border); + mono_border, + text_overlay); +} + +void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay, + const int icon_indicator_number) +{ + /* The icon indicator is used as an aggregator, no need to show if it is 1. */ + if (icon_indicator_number < 2) { + text_overlay->text[0] = '\0'; + return; + } + BLI_str_format_integer_unit(text_overlay->text, icon_indicator_number); } /* ********** Alert Icons ********** */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6ef7d346418..982ac1753e1 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -23,6 +23,7 @@ struct ARegion; struct AnimationEvalContext; struct CurveMapping; struct CurveProfile; +struct IconTextOverlay; struct ID; struct ImBuf; struct Main; @@ -275,6 +276,9 @@ struct uiBut { uiButPushedStateFunc pushed_state_func; const void *pushed_state_arg; + /** Little indicator (e.g., counter) displayed on top of some icons. */ + struct IconTextOverlay icon_overlay_text; + /* pointer back */ uiBlock *block; }; @@ -473,6 +477,12 @@ typedef enum uiButtonGroupFlag { } uiButtonGroupFlag; ENUM_OPERATORS(uiButtonGroupFlag, UI_BUTTON_GROUP_PANEL_HEADER); +typedef struct uiBlockDynamicListener { + struct uiBlockDynamicListener *next, *prev; + + void (*listener_func)(const struct wmRegionListenerParams *params); +} uiBlockDynamicListener; + struct uiBlock { uiBlock *next, *prev; @@ -495,6 +505,8 @@ struct uiBlock { * state that is persistent over redraws (e.g. collapsed tree-view items). */ ListBase views; + ListBase dynamic_listeners; /* #uiBlockDynamicListener */ + char name[UI_MAX_NAME_STR]; float winmat[4][4]; @@ -1536,6 +1548,8 @@ void ui_interface_tag_script_reload_queries(void); /* interface_view.cc */ void ui_block_free_views(struct uiBlock *block); +void ui_block_views_listen(const uiBlock *block, + const struct wmRegionListenerParams *listener_params); uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block, const uiViewHandle *new_view); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index c906a5b36f1..a456cef7be6 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -3235,7 +3235,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon) return but; } -void uiItemL_ex( +uiBut *uiItemL_ex( uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert) { uiBut *but = uiItemL_(layout, name, icon); @@ -3248,6 +3248,8 @@ void uiItemL_ex( if (redalert) { UI_but_flag_enable(but, UI_BUT_REDALERT); } + + return but; } void uiItemL(uiLayout *layout, const char *name, int icon) @@ -5812,6 +5814,14 @@ void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout) printf("%s: opening menu \"%s\"\n", __func__, mt->idname); } + if (mt->listener) { + /* Forward the menu type listener to the block we're drawing in. */ + uiBlock *block = uiLayoutGetBlock(layout); + uiBlockDynamicListener *listener = MEM_mallocN(sizeof(*listener), "uiBlockDynamicListener"); + listener->listener_func = mt->listener; + BLI_addtail(&block->dynamic_listeners, listener); + } + if (layout->context) { CTX_store_set(C, layout->context); } diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index e089642963d..2d06dd2c465 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -1859,8 +1859,7 @@ static void edittranslation_find_po_file(const char *root, /* First, full lang code. */ BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng); - BLI_path_join(path, maxlen, root, uilng); - BLI_path_append(path, maxlen, tstr); + BLI_path_join(path, maxlen, root, uilng, tstr); if (BLI_is_file(path)) { return; } diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc index 7a69e2f9b2f..24d8281aad8 100644 --- a/source/blender/editors/interface/interface_panel.cc +++ b/source/blender/editors/interface/interface_panel.cc @@ -1112,7 +1112,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style, 0.7f, 0.0f, title_color, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } @@ -1140,7 +1141,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style, 1.0f, 0.0f, title_color, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc index 569f657a544..0d19390d508 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.cc +++ b/source/blender/editors/interface/interface_region_menu_popup.cc @@ -10,6 +10,7 @@ #include <cstdarg> #include <cstdlib> #include <cstring> +#include <functional> #include "MEM_guardedalloc.h" @@ -166,28 +167,80 @@ struct uiPopupMenu { uiBut *but; ARegion *butregion; + /* Menu hash is created from this, to keep a memory of recently opened menus. */ + const char *title; + int mx, my; bool popup, slideout; - uiMenuCreateFunc menu_func; - void *menu_arg; + std::function<void(bContext *C, uiLayout *layout)> menu_func; }; +/** + * \param title: Optional. If set, it will be used to store recently opened menus so they can be + * opened with the mouse over the last chosen entry again. + */ +static void ui_popup_menu_create_block(bContext *C, + uiPopupMenu *pup, + const char *title, + const char *block_name) +{ + const uiStyle *style = UI_style_get_dpi(); + + pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN); + if (!pup->but) { + pup->block->flag |= UI_BLOCK_IS_FLIP | UI_BLOCK_NO_FLIP; + } + if (title && title[0]) { + pup->block->flag |= UI_BLOCK_POPUP_MEMORY; + pup->block->puphash = ui_popup_menu_hash(title); + } + pup->layout = UI_block_layout( + pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); + + /* NOTE: this intentionally differs from the menu & sub-menu default because many operators + * use popups like this to select one of their options - + * where having invoke doesn't make sense. + * When the menu was opened from a button, use invoke still for compatibility. This used to be + * the default and changing now could cause issues. */ + const wmOperatorCallContext opcontext = pup->but ? WM_OP_INVOKE_REGION_WIN : + WM_OP_EXEC_REGION_WIN; + + uiLayoutSetOperatorContext(pup->layout, opcontext); + + if (pup->but) { + if (pup->but->context) { + uiLayoutContextCopy(pup->layout, pup->but->context); + } + } +} + static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup) { uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup); - if (pup->menu_func) { - pup->block->handle = handle; - pup->menu_func(C, pup->layout, pup->menu_arg); - pup->block->handle = nullptr; + int minwidth = 0; + + if (!pup->layout) { + ui_popup_menu_create_block(C, pup, pup->title, __func__); + + if (pup->menu_func) { + pup->block->handle = handle; + pup->menu_func(C, pup->layout); + pup->block->handle = nullptr; + } + + if (uiLayoutGetUnitsX(pup->layout) != 0.0f) { + /* Use the minimum width from the layout if it's set. */ + minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X; + } + + pup->layout = nullptr; } /* Find block minimum width. */ - int minwidth; - if (uiLayoutGetUnitsX(pup->layout) != 0.0f) { - /* Use the minimum width from the layout if it's set. */ - minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X; + if (minwidth) { + /* Skip. */ } else if (pup->but) { /* Minimum width to enforce. */ @@ -236,7 +289,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT); if (pup->popup) { - int offset[2]; + int offset[2] = {0, 0}; uiBut *but_activate = nullptr; UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_NUMSELECT); @@ -244,36 +297,42 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi UI_block_direction_set(block, direction); /* offset the mouse position, possibly based on earlier selection */ - uiBut *bt; - if ((block->flag & UI_BLOCK_POPUP_MEMORY) && (bt = ui_popup_menu_memory_get(block))) { - /* position mouse on last clicked item, at 0.8*width of the - * button, so it doesn't overlap the text too much, also note - * the offset is negative because we are inverse moving the - * block to be under the mouse */ - offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)); - offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y); - - if (ui_but_is_editable(bt)) { - but_activate = bt; - } - } - else { - /* position mouse at 0.8*width of the button and below the tile - * on the first item */ - offset[0] = 0; - LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { - offset[0] = min_ii(offset[0], - -(but_iter->rect.xmin + 0.8f * BLI_rctf_size_x(&but_iter->rect))); + if (!handle->refresh) { + uiBut *bt; + if ((block->flag & UI_BLOCK_POPUP_MEMORY) && (bt = ui_popup_menu_memory_get(block))) { + /* position mouse on last clicked item, at 0.8*width of the + * button, so it doesn't overlap the text too much, also note + * the offset is negative because we are inverse moving the + * block to be under the mouse */ + offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)); + offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y); + + if (ui_but_is_editable(bt)) { + but_activate = bt; + } } + else { + /* position mouse at 0.8*width of the button and below the tile + * on the first item */ + offset[0] = 0; + LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { + offset[0] = min_ii(offset[0], + -(but_iter->rect.xmin + 0.8f * BLI_rctf_size_x(&but_iter->rect))); + } - offset[1] = 2.1 * UI_UNIT_Y; + offset[1] = 2.1 * UI_UNIT_Y; - LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { - if (ui_but_is_editable(but_iter)) { - but_activate = but_iter; - break; + LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) { + if (ui_but_is_editable(but_iter)) { + but_activate = but_iter; + break; + } } } + copy_v2_v2_int(handle->prev_bounds_offset, offset); + } + else { + copy_v2_v2_int(offset, handle->prev_bounds_offset); } /* in rare cases this is needed since moving the popup @@ -312,27 +371,35 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi return pup->block; } -uiPopupBlockHandle *ui_popup_menu_create( - bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg) +static void ui_block_free_func_POPUP(void *arg_pup) +{ + uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup); + MEM_delete(pup); +} + +static uiPopupBlockHandle *ui_popup_menu_create( + bContext *C, + ARegion *butregion, + uiBut *but, + const char *title, + std::function<void(bContext *, uiLayout *)> menu_func) { wmWindow *window = CTX_wm_window(C); - const uiStyle *style = UI_style_get_dpi(); - uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__); - pup->block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS_PULLDOWN); - pup->block->flag |= UI_BLOCK_NUMSELECT; /* Default menus to numeric-selection. */ - pup->layout = UI_block_layout( - pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); - pup->slideout = but ? ui_block_is_menu(but->block) : false; - pup->but = but; - uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN); + uiPopupMenu *pup = MEM_new<uiPopupMenu>(__func__); + pup->title = title; + /* menu is created from a callback */ + pup->menu_func = menu_func; + if (but) { + pup->slideout = ui_block_is_menu(but->block); + pup->but = but; + } if (!but) { /* no button to start from, means we are a popup */ pup->mx = window->eventstate->xy[0]; pup->my = window->eventstate->xy[1]; pup->popup = true; - pup->block->flag |= UI_BLOCK_NO_FLIP; } /* some enums reversing is strange, currently we have no good way to * reverse some enum's but not others, so reverse all so the first menu @@ -346,17 +413,10 @@ uiPopupBlockHandle *ui_popup_menu_create( pup->block->flag |= UI_BLOCK_NO_FLIP; } #endif - if (but->context) { - uiLayoutContextCopy(pup->layout, but->context); - } } - /* menu is created from a callback */ - pup->menu_func = menu_func; - pup->menu_arg = arg; - uiPopupBlockHandle *handle = ui_popup_block_create( - C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr); + C, butregion, but, nullptr, ui_block_func_POPUP, pup, ui_block_free_func_POPUP); if (!but) { handle->popup = true; @@ -365,68 +425,73 @@ uiPopupBlockHandle *ui_popup_menu_create( WM_event_add_mousemove(window); } - MEM_freeN(pup); - return handle; } +uiPopupBlockHandle *ui_popup_menu_create( + bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg) +{ + return ui_popup_menu_create( + C, butregion, but, nullptr, [menu_func, arg](bContext *C, uiLayout *layout) { + menu_func(C, layout, arg); + }); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name Popup Menu API with begin & end * \{ */ +static void create_title_button(uiLayout *layout, const char *title, int icon) +{ + uiBlock *block = uiLayoutGetBlock(layout); + char titlestr[256]; + + if (icon) { + BLI_snprintf(titlestr, sizeof(titlestr), " %s", title); + uiDefIconTextBut(block, + UI_BTYPE_LABEL, + 0, + icon, + titlestr, + 0, + 0, + 200, + UI_UNIT_Y, + nullptr, + 0.0, + 0.0, + 0, + 0, + ""); + } + else { + uiBut *but = uiDefBut( + block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, ""); + but->drawflag = UI_BUT_TEXT_LEFT; + } + + uiItemS(layout); +} + +/* Used to directly create a popup menu that is not refreshed on redraw. */ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, const char *title, const char *block_name, int icon) { - const uiStyle *style = UI_style_get_dpi(); - uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__); + uiPopupMenu *pup = MEM_new<uiPopupMenu>(__func__); - pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN); - pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP; - pup->block->puphash = ui_popup_menu_hash(title); - pup->layout = UI_block_layout( - pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); + pup->title = title; - /* NOTE: this intentionally differs from the menu & sub-menu default because many operators - * use popups like this to select one of their options - - * where having invoke doesn't make sense */ - uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN); + ui_popup_menu_create_block(C, pup, title, block_name); /* create in advance so we can let buttons point to retval already */ pup->block->handle = MEM_cnew<uiPopupBlockHandle>(__func__); - /* create title button */ if (title[0]) { - char titlestr[256]; - - if (icon) { - BLI_snprintf(titlestr, sizeof(titlestr), " %s", title); - uiDefIconTextBut(pup->block, - UI_BTYPE_LABEL, - 0, - icon, - titlestr, - 0, - 0, - 200, - UI_UNIT_Y, - nullptr, - 0.0, - 0.0, - 0, - 0, - ""); - } - else { - uiBut *but = uiDefBut( - pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, ""); - but->drawflag = UI_BUT_TEXT_LEFT; - } - - uiItemS(pup->layout); + create_title_button(pup->layout, title, icon); } return pup; @@ -465,7 +530,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup) UI_popup_handlers_add(C, &window->modalhandlers, menu, 0); WM_event_add_mousemove(window); - MEM_freeN(pup); + MEM_delete(pup); } bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup) @@ -477,7 +542,7 @@ bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup) UI_block_layout_resolve(pup->block, nullptr, nullptr); MEM_freeN(pup->block->handle); UI_block_free(C, pup->block); - MEM_freeN(pup); + MEM_delete(pup); return false; } @@ -541,6 +606,20 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports) } } +static void ui_popup_menu_create_from_menutype(bContext *C, + MenuType *mt, + const char *title, + const int icon) +{ + uiPopupBlockHandle *handle = ui_popup_menu_create( + C, nullptr, nullptr, title, [mt, title, icon](bContext *C, uiLayout *layout) -> void { + create_title_button(layout, title, icon); + ui_item_menutype_func(C, layout, mt); + }); + + handle->can_refresh = true; +} + int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) { MenuType *mt = WM_menutype_find(idname, true); @@ -554,14 +633,21 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) /* cancel but allow event to pass through, just like operators do */ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } + /* For now always recreate menus on redraw that were invoked with this function. Maybe we want to + * make that optional somehow. */ + const bool allow_refresh = true; - uiPopupMenu *pup = UI_popup_menu_begin( - C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - - UI_menutype_draw(C, mt, layout); - - UI_popup_menu_end(C, pup); + const char *title = CTX_IFACE_(mt->translation_context, mt->label); + if (allow_refresh) { + ui_popup_menu_create_from_menutype(C, mt, title, ICON_NONE); + } + else { + /* If no refresh is needed, create the block directly. */ + uiPopupMenu *pup = UI_popup_menu_begin(C, title, ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + UI_menutype_draw(C, mt, layout); + UI_popup_menu_end(C, pup); + } return OPERATOR_INTERFACE; } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 6ba80e2e0d9..1bad9b34a72 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1420,21 +1420,25 @@ static void widget_draw_icon( /* to indicate draggable */ if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) { - UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme, &but->icon_overlay_text); } else if (but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) { - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text); } else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) { if (has_theme) { alpha *= 0.8f; } - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text); } else { const bTheme *btheme = UI_GetTheme(); const float desaturate = 1.0 - btheme->tui.icon_saturation; - UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme); + UI_icon_draw_ex( + xs, ys, icon, aspect, alpha, desaturate, color, has_theme, &but->icon_overlay_text); } } @@ -5426,7 +5430,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, GPU_blend(GPU_BLEND_ALPHA); /* XXX scale weak get from fstyle? */ - UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false); + UI_icon_draw_ex( + xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc index c568a8cab74..71974b4d2f9 100644 --- a/source/blender/editors/interface/views/interface_view.cc +++ b/source/blender/editors/interface/views/interface_view.cc @@ -81,7 +81,7 @@ void ui_block_free_views(uiBlock *block) } } -void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) +void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params) { ARegion *region = listener_params->region; diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 888a8340d51..1c6d1747516 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -383,7 +383,7 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3]) return ok; } - copy_m3_m4(bmat, ob->obmat); + copy_m3_m4(bmat, ob->object_to_world); const Span<MVert> verts = me->verts(); const Span<MPoly> polys = me->polys(); @@ -403,7 +403,7 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3]) const MLoop *ml = &loops[poly.loopstart]; for (int b = 0; b < poly.totloop; b++, ml++) { mul_v3_m3v3(vec, bmat, verts[ml->v].co); - add_v3_v3v3(vec, vec, ob->obmat[3]); + add_v3_v3v3(vec, vec, ob->object_to_world[3]); minmax_v3v3_v3(r_min, r_max, vec); } diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c index f5090c0143d..ad900c997f8 100644 --- a/source/blender/editors/mesh/editmesh_add_gizmo.c +++ b/source/blender/editors/mesh/editmesh_add_gizmo.c @@ -316,7 +316,7 @@ static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op) PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); if (RNA_property_is_set(op->ptr, prop_matrix)) { RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]); - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_m4m4(matrix, obedit->imat, matrix); } else { diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 3284cd70646..85801668510 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -244,7 +244,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { Object *obedit = objects[ob_index]; - float scale = mat4_to_scale(obedit->obmat); + float scale = mat4_to_scale(obedit->object_to_world); opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); BMEditMesh *em = BKE_editmesh_from_object(obedit); if (em->bm->totvertsel > 0) { diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 5c5a12b3e64..aab33678bec 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -314,9 +314,9 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op) copy_v3_v3(plane_co_local, plane_co); copy_v3_v3(plane_no_local, plane_no); - invert_m4_m4(imat, obedit->obmat); + invert_m4_m4(imat, obedit->object_to_world); mul_m4_v3(imat, plane_co_local); - mul_transposed_mat3_m4_v3(obedit->obmat, plane_no_local); + mul_transposed_mat3_m4_v3(obedit->object_to_world, plane_no_local); BMOperator bmop; EDBM_op_init( diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 55e9c32e41b..9df3a521cfa 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -55,8 +55,8 @@ static void edbm_extrude_edge_exclude_mirror( float mtx[4][4]; if (mmd->mirror_ob) { float imtx[4][4]; - invert_m4_m4(imtx, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, imtx, obedit->obmat); + invert_m4_m4(imtx, mmd->mirror_ob->object_to_world); + mul_m4_m4m4(mtx, imtx, obedit->object_to_world); } BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { @@ -293,7 +293,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) Object *obedit = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(obedit); - copy_m3_m4(tmat, obedit->obmat); + copy_m3_m4(tmat, obedit->object_to_world); invert_m3(tmat); mul_v3_m3v3(offset_local, tmat, offset); @@ -736,7 +736,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w } mul_v3_fl(local_center, 1.0f / (float)local_verts_len); - mul_m4_v3(vc.obedit->obmat, local_center); + mul_m4_v3(vc.obedit->object_to_world, local_center); mul_v3_fl(local_center, (float)local_verts_len); add_v3_v3(center, local_center); @@ -761,7 +761,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w continue; } - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); float local_center[3]; @@ -823,7 +823,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w /* center */ copy_v3_v3(ofs, local_center); - mul_m4_v3(vc.obedit->obmat, ofs); /* view space */ + mul_m4_v3(vc.obedit->object_to_world, ofs); /* view space */ ED_view3d_win_to_3d_int(vc.v3d, vc.region, ofs, event->mval, ofs); mul_m4_v3(vc.obedit->imat, ofs); /* back in object space */ diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c index be2d04b14a1..9d0bcfe4e90 100644 --- a/source/blender/editors/mesh/editmesh_extrude_screw.c +++ b/source/blender/editors/mesh/editmesh_extrude_screw.c @@ -102,11 +102,11 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) continue; } - copy_v3_v3(nor, obedit->obmat[2]); + copy_v3_v3(nor, obedit->object_to_world[2]); /* calculate dvec */ - mul_v3_m4v3(v1_co_global, obedit->obmat, v1->co); - mul_v3_m4v3(v2_co_global, obedit->obmat, v2->co); + mul_v3_m4v3(v1_co_global, obedit->object_to_world, v1->co); + mul_v3_m4v3(v2_co_global, obedit->object_to_world, v2->co); sub_v3_v3v3(dvec, v1_co_global, v2_co_global); mul_v3_fl(dvec, 1.0f / steps); @@ -126,7 +126,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) dvec, turns * steps, DEG2RADF(360.0f * turns), - obedit->obmat, + obedit->object_to_world, false)) { continue; } diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 1b9c98db5eb..756d7f73d10 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -77,7 +77,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) d, steps, -angle, - obedit->obmat, + obedit->object_to_world, use_normal_flip, dupli, use_auto_merge)) { diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c index 687f06c8dcf..19e23f4f212 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c @@ -362,7 +362,7 @@ static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgrou } if (totsel) { mul_v3_fl(select_center, 1.0f / totsel); - mul_m4_v3(obedit->obmat, select_center); + mul_m4_v3(obedit->object_to_world, select_center); copy_v3_v3(ggd->data.select_center, select_center); ggd->data.use_select_center = true; } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 068e6215c26..fa4ae7f984c 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -136,7 +136,7 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { Object *obedit = objects[ob_index]; - float scale = mat4_to_scale(obedit->obmat); + float scale = mat4_to_scale(obedit->object_to_world); opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); BMEditMesh *em = BKE_editmesh_from_object(obedit); if (em->bm->totvertsel > 0) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index a147594b25b..369162e80a3 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -586,9 +586,9 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd, float axis[3]; float arc_angle; - const float inverse_average_scale = 1 / - (kcd->curr.ob->obmat[0][0] + kcd->curr.ob->obmat[1][1] + - kcd->curr.ob->obmat[2][2]); + const float inverse_average_scale = 1 / (kcd->curr.ob->object_to_world[0][0] + + kcd->curr.ob->object_to_world[1][1] + + kcd->curr.ob->object_to_world[2][2]); const float px_scale = 3.0f * inverse_average_scale * @@ -1194,7 +1194,7 @@ static void knife_bm_tri_cagecos_get_worldspace(const KnifeTool_OpData *kcd, knife_bm_tri_cagecos_get(kcd, ob_index, tri_index, cos); const Object *ob = kcd->objects[ob_index]; for (int i = 0; i < 3; i++) { - mul_m4_v3(ob->obmat, cos[i]); + mul_m4_v3(ob->object_to_world, cos[i]); } } @@ -1744,7 +1744,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v, Object *ob } float cageco_ws[3]; - mul_v3_m4v3(cageco_ws, ob->obmat, cageco); + mul_v3_m4v3(cageco_ws, ob->object_to_world, cageco); kfv = new_knife_vert(kcd, v->co, cageco_ws); kfv->v = v; @@ -2657,14 +2657,14 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) if (cagecos) { for (int i = 0; i < em->bm->totvert; i++) { copy_v3_v3(ws, cagecos[i]); - mul_m4_v3(ob->obmat, ws); + mul_m4_v3(ob->object_to_world, ws); minmax_v3v3_v3(min, max, ws); } } else { BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { copy_v3_v3(ws, v->co); - mul_m4_v3(ob->obmat, ws); + mul_m4_v3(ob->object_to_world, ws); minmax_v3v3_v3(min, max, ws); } } @@ -5072,7 +5072,7 @@ void EDBM_mesh_knife(ViewContext *vc, BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { float cent[3], cent_ss[2]; BM_face_calc_point_in_face(f, cent); - mul_m4_v3(ob->obmat, cent); + mul_m4_v3(ob->object_to_world, cent); knife_project_v2(kcd, cent, cent_ss); if (edbm_mesh_knife_point_isect(polys, cent_ss)) { BM_elem_flag_enable(f, BM_ELEM_TAG); @@ -5113,7 +5113,7 @@ void EDBM_mesh_knife(ViewContext *vc, if (found) { float cent[3], cent_ss[2]; BM_face_calc_point_in_face(f, cent); - mul_m4_v3(ob->obmat, cent); + mul_m4_v3(ob->object_to_world, cent); knife_project_v2(kcd, cent, cent_ss); if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) && edbm_mesh_knife_point_isect(polys, cent_ss)) { diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 494e0ff4a27..9a91d7836fe 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -88,7 +88,7 @@ typedef struct RingSelOpData { static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) { RingSelOpData *lcd = arg; - EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->obmat); + EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->object_to_world); } static void edgering_select(RingSelOpData *lcd) diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index bf9664fa10d..63e37b18827 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -124,7 +124,7 @@ static int edbm_polybuild_transform_at_cursor_invoke(bContext *C, BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); if (!ele_act) { @@ -192,7 +192,7 @@ static int edbm_polybuild_delete_at_cursor_invoke(bContext *C, BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); if (!ele_act) { @@ -286,7 +286,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); @@ -294,7 +294,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con if (ele_act == NULL || ele_act->head.htype == BM_FACE) { /* Just add vert */ copy_v3_v3(center, vc.scene->cursor.location); - mul_v3_m4v3(center, vc.obedit->obmat, center); + mul_v3_m4v3(center, vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); @@ -309,7 +309,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con BMFace *f_reference = e_act->l ? e_act->l->f : NULL; mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); - mul_m4_v3(vc.obedit->obmat, center); + mul_m4_v3(vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); if (f_reference->len == 3 && RNA_boolean_get(op->ptr, "create_quads")) { @@ -364,7 +364,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con BMFace *f_reference = e_pair[0]->l ? e_pair[0]->l->f : NULL; - mul_v3_m4v3(center, vc.obedit->obmat, v_act->co); + mul_v3_m4v3(center, vc.obedit->object_to_world, v_act->co); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); @@ -386,7 +386,7 @@ static int edbm_polybuild_face_at_cursor_invoke(bContext *C, wmOperator *op, con } else { /* Just add edge */ - mul_m4_v3(vc.obedit->obmat, center); + mul_m4_v3(vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, v_act->co, event->mval, center); mul_m4_v3(vc.obedit->imat, center); @@ -464,7 +464,7 @@ static int edbm_polybuild_split_at_cursor_invoke(bContext *C, BMEditMesh *em = vc.em; BMesh *bm = em->bm; - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + invert_m4_m4(vc.obedit->imat, vc.obedit->object_to_world); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX); @@ -475,7 +475,7 @@ static int edbm_polybuild_split_at_cursor_invoke(bContext *C, if (ele_act->head.htype == BM_EDGE) { BMEdge *e_act = (BMEdge *)ele_act; mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co); - mul_m4_v3(vc.obedit->obmat, center); + mul_m4_v3(vc.obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc.v3d, vc.region, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c index cf73e579700..732f39e4123 100644 --- a/source/blender/editors/mesh/editmesh_preselect_elem.c +++ b/source/blender/editors/mesh/editmesh_preselect_elem.c @@ -243,7 +243,7 @@ static void view3d_preselect_update_preview_triangle_from_vert(struct EditMesh_P } if (e_pair[1] != NULL) { - mul_v3_m4v3(center, vc->obedit->obmat, v_act->co); + mul_v3_m4v3(center, vc->obedit->object_to_world, v_act->co); ED_view3d_win_to_3d_int(vc->v3d, vc->region, center, mval, center); mul_m4_v3(vc->obedit->imat, center); @@ -311,7 +311,7 @@ static void view3d_preselect_update_preview_triangle_from_edge(struct EditMesh_P psel->preview_tris = MEM_mallocN(sizeof(*psel->preview_tris), __func__); psel->preview_lines = MEM_mallocN(sizeof(*psel->preview_lines) * 3, __func__); mid_v3_v3v3(center, eed->v1->co, eed->v2->co); - mul_m4_v3(vc->obedit->obmat, center); + mul_m4_v3(vc->obedit->object_to_world, center); ED_view3d_win_to_3d_int(vc->v3d, vc->region, center, mval, center); mul_m4_v3(vc->obedit->imat, center); diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc index 76d0bab8a52..2ef2772d404 100644 --- a/source/blender/editors/mesh/editmesh_select.cc +++ b/source/blender/editors/mesh/editmesh_select.cc @@ -1060,7 +1060,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, float imat3[3][3]; ED_view3d_viewcontext_init_object(vc, obedit); - copy_m3_m4(imat3, obedit->obmat); + copy_m3_m4(imat3, obedit->object_to_world); invert_m3(imat3); const float(*coords)[3] = nullptr; @@ -1085,7 +1085,8 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, for (uint j = 0; j < 2; j++) { BMVert *v = *((&e->v1) + j); float point[3]; - mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co); + mul_v3_m4v3( + point, obedit->object_to_world, coords ? coords[BM_elem_index_get(v)] : v->co); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_vert) { @@ -1114,7 +1115,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, else { mid_v3_v3v3(point, e->v1->co, e->v2->co); } - mul_m4_v3(obedit->obmat, point); + mul_m4_v3(obedit->object_to_world, point); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_edge) { @@ -1139,7 +1140,8 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) { float point[3]; - mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co); + mul_v3_m4v3( + point, obedit->object_to_world, coords ? coords[BM_elem_index_get(v)] : v->co); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_vert) { @@ -1169,7 +1171,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, else { mid_v3_v3v3(point, e->v1->co, e->v2->co); } - mul_m4_v3(obedit->obmat, point); + mul_m4_v3(obedit->object_to_world, point); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_edge) { @@ -1198,7 +1200,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, else { BM_face_calc_center_median(f, point); } - mul_m4_v3(obedit->obmat, point); + mul_m4_v3(obedit->object_to_world, point); const float dist_sq_test = dist_squared_to_ray_v3_normalized( ray_origin, ray_direction, point); if (dist_sq_test < dist_sq_best_face) { @@ -4947,7 +4949,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) { float vertex_world[3]; - mul_v3_m4v3(vertex_world, obedit->obmat, v_act->co); + mul_v3_m4v3(vertex_world, obedit->object_to_world, v_act->co); value = dot_v3v3(axis_vector, vertex_world); } @@ -4977,7 +4979,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN | BM_ELEM_SELECT)) { float v_iter_world[3]; - mul_v3_m4v3(v_iter_world, obedit_iter->obmat, v->co); + mul_v3_m4v3(v_iter_world, obedit_iter->object_to_world, v->co); const float value_iter = dot_v3v3(axis_vector, v_iter_world); switch (sign) { case SELECT_AXIS_ALIGN: diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 47c76b7709b..9469639718f 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -137,7 +137,7 @@ static void face_to_plane(const Object *ob, BMFace *face, float r_plane[4]) copy_v3_v3(normal, face->no); mul_transposed_mat3_m4_v3(ob->imat, normal); normalize_v3(normal); - mul_v3_m4v3(co, ob->obmat, BM_FACE_FIRST_LOOP(face)->v->co); + mul_v3_m4v3(co, ob->object_to_world, BM_FACE_FIRST_LOOP(face)->v->co); plane_from_point_normal_v3(r_plane, co, normal); } @@ -206,7 +206,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(ob); BMesh *bm = em->bm; Material ***material_array = NULL; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); int custom_data_offset = 0; if (bm->totfacesel == 0) { @@ -214,7 +214,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) } float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); switch (type) { case SIMFACE_MATERIAL: { @@ -335,7 +335,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) int custom_data_offset; float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); bool has_custom_data_layer = false; switch (type) { @@ -559,8 +559,8 @@ static void edge_pos_direction_worldspace_get(Object *ob, BMEdge *edge, float *r copy_v3_v3(v1, edge->v1->co); copy_v3_v3(v2, edge->v2->co); - mul_m4_v3(ob->obmat, v1); - mul_m4_v3(ob->obmat, v2); + mul_m4_v3(ob->object_to_world, v1); + mul_m4_v3(ob->object_to_world, v2); sub_v3_v3v3(r_dir, v1, v2); normalize_v3(r_dir); @@ -586,8 +586,8 @@ static float edge_length_squared_worldspace_get(Object *ob, BMEdge *edge) { float v1[3], v2[3]; - mul_v3_mat3_m4v3(v1, ob->obmat, edge->v1->co); - mul_v3_mat3_m4v3(v2, ob->obmat, edge->v2->co); + mul_v3_mat3_m4v3(v1, ob->object_to_world, edge->v1->co); + mul_v3_mat3_m4v3(v2, ob->object_to_world, edge->v2->co); return len_squared_v3v3(v1, v2); } @@ -705,7 +705,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op) } float ob_m3[3][3], ob_m3_inv[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); invert_m3_m3(ob_m3_inv, ob_m3); BMEdge *edge; /* Mesh edge. */ @@ -812,7 +812,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op) } float ob_m3[3][3], ob_m3_inv[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); invert_m3_m3(ob_m3_inv, ob_m3); BMEdge *edge; /* Mesh edge. */ @@ -1028,7 +1028,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) BLI_bitmap *defbase_selected = NULL; int defbase_len = 0; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); if (bm->totvertsel == 0) { continue; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 9f3ef8af17d..9f5c0d74ced 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3356,7 +3356,7 @@ static bool merge_target(BMEditMesh *em, if (use_cursor) { vco = scene->cursor.location; copy_v3_v3(co, vco); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, co); } else { @@ -6684,7 +6684,7 @@ static void sort_bmelem_flag(bContext *C, int coidx = (action == SRT_VIEW_ZAXIS) ? 2 : 0; /* Apply the view matrix to the object matrix. */ - mul_m4_m4m4(mat, rv3d->viewmat, ob->obmat); + mul_m4_m4m4(mat, rv3d->viewmat, ob->object_to_world); if (totelem[0]) { pb = pblock[0] = MEM_callocN(sizeof(char) * totelem[0], "sort_bmelem vert pblock"); @@ -6753,7 +6753,7 @@ static void sort_bmelem_flag(bContext *C, copy_v3_v3(cur, scene->cursor.location); - invert_m4_m4(mat, ob->obmat); + invert_m4_m4(mat, ob->object_to_world); mul_m4_v3(mat, cur); if (totelem[0]) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 4fc44f01ea0..10acfc96ca8 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1858,7 +1858,7 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, ED_view3d_win_to_segment_clipped(depsgraph, region, v3d, mval_f, origin, end, false); - invert_m4_m4(invmat, obedit->obmat); + invert_m4_m4(invmat, obedit->object_to_world); mul_m4_v3(invmat, origin); copy_v3_v3(co1, e->v1->co); diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 122b8fa7d89..b468360ff9b 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -787,7 +787,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator if (me->edit_mesh) { /* Tag edges as sharp according to smooth threshold if needed, - * to preserve autosmooth shading. */ + * to preserve auto-smooth shading. */ if (me->flag & ME_AUTOSMOOTH) { BM_edges_sharp_from_angle_set(me->edit_mesh->bm, me->smoothresh); } @@ -796,7 +796,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator } else { /* Tag edges as sharp according to smooth threshold if needed, - * to preserve autosmooth shading. */ + * to preserve auto-smooth shading. */ if (me->flag & ME_AUTOSMOOTH) { const Span<MVert> verts = me->verts(); MutableSpan<MEdge> edges = me->edges_for_write(); diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index 4d75ab7f041..147c26e521f 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -132,7 +132,7 @@ static void join_mesh_single(Depsgraph *depsgraph, float cmat[4][4]; /* Watch this: switch matrix multiplication order really goes wrong. */ - mul_m4_m4m4(cmat, imat, ob_src->obmat); + mul_m4_m4m4(cmat, imat, ob_src->object_to_world); /* transform vertex coordinates into new space */ for (a = 0; a < me->totvert; a++, mvert++) { @@ -386,7 +386,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) * NOTE: This doesn't apply recursive parenting. */ if (join_parent) { ob->parent = nullptr; - BKE_object_apply_mat4_ex(ob, ob->obmat, ob->parent, ob->parentinv, false); + BKE_object_apply_mat4_ex(ob, ob->object_to_world, ob->parent, ob->parentinv, false); } /* that way the active object is always selected */ @@ -594,7 +594,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) /* Inverse transform for all selected meshes in this object, * See #object_join_exec for detailed comment on why the safe version is used. */ - invert_m4_m4_safe_ortho(imat, ob->obmat); + invert_m4_m4_safe_ortho(imat, ob->object_to_world); /* Add back active mesh first. * This allows to keep things similar as they were, as much as possible diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 3ce39b695e0..6075e4250eb 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -322,7 +322,7 @@ void ED_object_base_init_transform_on_add(Object *object, const float loc[3], co copy_v3_v3(object->rot, rot); } - BKE_object_to_mat4(object, object->obmat); + BKE_object_to_mat4(object, object->object_to_world); } float ED_object_new_primitive_matrix(bContext *C, @@ -342,14 +342,14 @@ float ED_object_new_primitive_matrix(bContext *C, invert_m3(rmat); /* inverse transform for initial rotation and object */ - copy_m3_m4(mat, obedit->obmat); + copy_m3_m4(mat, obedit->object_to_world); mul_m3_m3m3(cmat, rmat, mat); invert_m3_m3(imat, cmat); copy_m4_m3(r_primmat, imat); /* center */ copy_v3_v3(r_primmat[3], loc); - sub_v3_v3v3(r_primmat[3], r_primmat[3], obedit->obmat[3]); + sub_v3_v3v3(r_primmat[3], r_primmat[3], obedit->object_to_world[3]); invert_m3_m3(imat, mat); mul_m3_v3(imat, r_primmat[3]); @@ -2084,7 +2084,7 @@ static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op) Object *curves_ob = ED_object_add_type( C, OB_CURVES, nullptr, nullptr, nullptr, false, local_view_bits); - BKE_object_apply_mat4(curves_ob, surface_ob->obmat, false, false); + BKE_object_apply_mat4(curves_ob, surface_ob->object_to_world, false, false); /* Set surface object. */ Curves *curves_id = static_cast<Curves *>(curves_ob->data); @@ -2561,8 +2561,8 @@ static void make_object_duplilist_real(bContext *C, id_us_min((ID *)ob_dst->instance_collection); ob_dst->instance_collection = nullptr; - copy_m4_m4(ob_dst->obmat, dob->mat); - BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); + copy_m4_m4(ob_dst->object_to_world, dob->mat); + BKE_object_apply_mat4(ob_dst, ob_dst->object_to_world, false, false); BLI_ghash_insert(dupli_gh, dob, ob_dst); if (parent_gh) { @@ -3017,7 +3017,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; float loc[3], size[3], rot[3][3], eul[3]; float matrix[4][4]; - mat4_to_loc_rot_size(loc, rot, size, ob->obmat); + mat4_to_loc_rot_size(loc, rot, size, ob->object_to_world); mat3_to_eul(eul, rot); Object *ob_gpencil = ED_gpencil_add_object(C, loc, local_view_bits); @@ -3556,11 +3556,62 @@ void OBJECT_OT_convert(wmOperatorType *ot) /** \name Duplicate Object Operator * \{ */ +static void object_add_sync_base_collection( + Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new) +{ + if ((base_src != nullptr) && (base_src->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) { + BKE_collection_object_add_from(bmain, scene, base_src->object, object_new); + } + else { + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, object_new); + } +} + +static void object_add_sync_local_view(Base *base_src, Base *base_new) +{ + base_new->local_view_bits = base_src->local_view_bits; +} + +static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new) +{ + /* 1) duplis should end up in same collection as the original + * 2) Rigid Body sim participants MUST always be part of a collection... + */ + /* XXX: is 2) really a good measure here? */ + if (object_src->rigidbody_object || object_src->rigidbody_constraint) { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, object_src)) { + BKE_collection_object_add(bmain, collection, object_new); + } + } + } +} + /** * - Assumes `id.new` is correct. * - Leaves selection of base/object unaltered. * - Sets #ID.newid pointers. */ +static void object_add_duplicate_internal(Main *bmain, + Object *ob, + const eDupli_ID_Flags dupflag, + const eLibIDDuplicateFlags duplicate_options, + Object **r_ob_new) +{ + if (ob->mode & OB_MODE_POSE) { + return; + } + + Object *obn = static_cast<Object *>( + ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options))); + if (r_ob_new) { + *r_ob_new = obn; + } + DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + return; +} + static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer *view_layer, @@ -3569,49 +3620,25 @@ static Base *object_add_duplicate_internal(Main *bmain, const eLibIDDuplicateFlags duplicate_options, Object **r_ob_new) { - Base *base, *basen = nullptr; - Object *obn; - - if (ob->mode & OB_MODE_POSE) { - /* nothing? */ + Object *object_new = nullptr; + object_add_duplicate_internal(bmain, ob, dupflag, duplicate_options, &object_new); + if (r_ob_new) { + *r_ob_new = object_new; + } + if (object_new == nullptr) { + return nullptr; } - else { - obn = static_cast<Object *>( - ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options))); - if (r_ob_new) { - *r_ob_new = obn; - } - DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - - BKE_view_layer_synced_ensure(scene, view_layer); - base = BKE_view_layer_base_find(view_layer, ob); - if ((base != nullptr) && (base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) { - BKE_collection_object_add_from(bmain, scene, ob, obn); - } - else { - LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); - BKE_collection_object_add(bmain, layer_collection->collection, obn); - } - - BKE_view_layer_synced_ensure(scene, view_layer); - basen = BKE_view_layer_base_find(view_layer, obn); - if (base != nullptr && basen != nullptr) { - basen->local_view_bits = base->local_view_bits; - } - /* 1) duplis should end up in same collection as the original - * 2) Rigid Body sim participants MUST always be part of a collection... - */ - /* XXX: is 2) really a good measure here? */ - if (ob->rigidbody_object || ob->rigidbody_constraint) { - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob)) { - BKE_collection_object_add(bmain, collection, obn); - } - } - } + BKE_view_layer_synced_ensure(scene, view_layer); + Base *base_src = BKE_view_layer_base_find(view_layer, ob); + object_add_sync_base_collection(bmain, scene, view_layer, base_src, object_new); + BKE_view_layer_synced_ensure(scene, view_layer); + Base *base_new = BKE_view_layer_base_find(view_layer, object_new); + if (base_src && base_new) { + object_add_sync_local_view(base_src, base_new); } - return basen; + object_add_sync_rigid_body(bmain, ob, object_new); + return base_new; } Base *ED_object_add_duplicate( @@ -3665,70 +3692,70 @@ static int duplicate_exec(bContext *C, wmOperator *op) * we also want to remap pointers between those... */ BKE_main_id_newptr_and_tag_clear(bmain); - /* Do not do collection re-syncs for each object; will do it once afterwards. - * However this means we can't get to new duplicated Base's immediately, will - * have to process them after the sync. */ - BKE_layer_collection_resync_forbid(); - /* Duplicate the selected objects, remember data needed to process - * after the sync (the base of the original object, and the copy of the - * original object). */ - blender::Vector<std::pair<Base *, Object *>> source_bases_new_objects; - Object *ob_new_active = nullptr; + * after the sync. */ + struct DuplicateObjectLink { + Base *base_src = nullptr; + Object *object_new = nullptr; + + DuplicateObjectLink(Base *base_src) : base_src(base_src) + { + } + }; + blender::Vector<DuplicateObjectLink> object_base_links; CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - Object *ob_new = nullptr; + object_base_links.append(DuplicateObjectLink(base)); + } + CTX_DATA_END; + + bool new_objects_created = false; + for (DuplicateObjectLink &link : object_base_links) { object_add_duplicate_internal(bmain, - scene, - view_layer, - base->object, + link.base_src->object, dupflag, LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID, - &ob_new); - if (ob_new == nullptr) { - continue; - } - source_bases_new_objects.append({base, ob_new}); - - /* note that this is safe to do with this context iterator, - * the list is made in advance */ - ED_object_base_select(base, BA_DESELECT); - - /* new object will become active */ - BKE_view_layer_synced_ensure(scene, view_layer); - if (BKE_view_layer_active_base_get(view_layer) == base) { - ob_new_active = ob_new; + &link.object_new); + if (link.object_new) { + new_objects_created = true; } } - CTX_DATA_END; - BKE_layer_collection_resync_allow(); - if (source_bases_new_objects.is_empty()) { + if (!new_objects_created) { return OPERATOR_CANCELLED; } - /* Sync the collection now, after everything is duplicated. */ - BKE_main_collection_sync(bmain); + /* Sync that could tag the view_layer out of sync. */ + for (DuplicateObjectLink &link : object_base_links) { + /* note that this is safe to do with this context iterator, + * the list is made in advance */ + ED_object_base_select(link.base_src, BA_DESELECT); + if (link.object_new) { + object_add_sync_base_collection(bmain, scene, view_layer, link.base_src, link.object_new); + object_add_sync_rigid_body(bmain, link.base_src->object, link.object_new); + } + } - /* After sync we can get to the new Base data, process it here. */ - for (const auto &item : source_bases_new_objects) { - Object *ob_new = item.second; - Base *base_source = item.first; - BKE_view_layer_synced_ensure(scene, view_layer); - Base *base_new = BKE_view_layer_base_find(view_layer, ob_new); - if (base_new == nullptr) { + /* Sync the view layer. Everything else should not tag the view_layer out of sync. */ + BKE_view_layer_synced_ensure(scene, view_layer); + const Base *active_base = BKE_view_layer_active_base_get(view_layer); + for (DuplicateObjectLink &link : object_base_links) { + if (!link.object_new) { continue; } + + Base *base_new = BKE_view_layer_base_find(view_layer, link.object_new); + BLI_assert(base_new); ED_object_base_select(base_new, BA_SELECT); - if (ob_new == ob_new_active) { + if (active_base == link.base_src) { ED_object_base_activate(C, base_new); } - if (base_new->object->data) { - DEG_id_tag_update(static_cast<ID *>(base_new->object->data), 0); + + if (link.object_new->data) { + DEG_id_tag_update(static_cast<ID *>(link.object_new->data), 0); } - /* #object_add_duplicate_internal will not have done this, since - * before the collection sync it would not have found the new base yet. */ - base_new->local_view_bits = base_source->local_view_bits; + + object_add_sync_local_view(link.base_src, base_new); } /* Note that this will also clear newid pointers and tags. */ @@ -3844,8 +3871,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op) PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); if (RNA_property_is_set(op->ptr, prop_matrix)) { Object *ob_add = basen->object; - RNA_property_float_get_array(op->ptr, prop_matrix, &ob_add->obmat[0][0]); - BKE_object_apply_mat4(ob_add, ob_add->obmat, true, true); + RNA_property_float_get_array(op->ptr, prop_matrix, &ob_add->object_to_world[0][0]); + BKE_object_apply_mat4(ob_add, ob_add->object_to_world, true, true); DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM); } @@ -3942,7 +3969,7 @@ static int object_transform_to_mouse_exec(bContext *C, wmOperator *op) float mat_dst_unit[4][4]; float final_delta[4][4]; - normalize_m4_m4(mat_src_unit, ob->obmat); + normalize_m4_m4(mat_src_unit, ob->object_to_world); normalize_m4_m4(mat_dst_unit, matrix); invert_m4(mat_src_unit); mul_m4_m4m4(final_delta, mat_dst_unit, mat_src_unit); @@ -4097,7 +4124,7 @@ static int object_join_exec(bContext *C, wmOperator *op) * If the zero scale is removed, the data on this axis remains un-scaled * (something that wouldn't work for #invert_m4_m4_safe). */ float imat_test[4][4]; - if (!invert_m4_m4(imat_test, ob->obmat)) { + if (!invert_m4_m4(imat_test, ob->object_to_world)) { BKE_report(op->reports, RPT_WARNING, "Active object final transform has one or more zero scaled axes"); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 781866db6a0..d05badc8fee 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1518,10 +1518,10 @@ static int bake(const BakeAPIRender *bkr, highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false, false); /* Low-poly to high-poly transformation matrix. */ - copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); + copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->object_to_world); invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); - highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); + highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->object_to_world); i++; } @@ -1540,18 +1540,19 @@ static int bake(const BakeAPIRender *bkr, pixel_array_high = MEM_mallocN(sizeof(BakePixel) * targets.pixels_num, "bake pixels high poly"); - if (!RE_bake_pixels_populate_from_objects(me_low_eval, - pixel_array_low, - pixel_array_high, - highpoly, - tot_highpoly, - targets.pixels_num, - ob_cage != NULL, - bkr->cage_extrusion, - bkr->max_ray_distance, - ob_low_eval->obmat, - (ob_cage ? ob_cage->obmat : ob_low_eval->obmat), - me_cage_eval)) { + if (!RE_bake_pixels_populate_from_objects( + me_low_eval, + pixel_array_low, + pixel_array_high, + highpoly, + tot_highpoly, + targets.pixels_num, + ob_cage != NULL, + bkr->cage_extrusion, + bkr->max_ray_distance, + ob_low_eval->object_to_world, + (ob_cage ? ob_cage->object_to_world : ob_low_eval->object_to_world), + me_cage_eval)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cleanup; } @@ -1629,7 +1630,7 @@ static int bake(const BakeAPIRender *bkr, targets.result, me_low_eval, bkr->normal_swizzle, - ob_low_eval->obmat); + ob_low_eval->object_to_world); } else { /* From multi-resolution. */ @@ -1655,7 +1656,7 @@ static int bake(const BakeAPIRender *bkr, targets.result, (me_nores) ? me_nores : me_low_eval, bkr->normal_swizzle, - ob_low_eval->obmat); + ob_low_eval->object_to_world); if (md) { BKE_id_free(NULL, &me_nores->id); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index fa9ded0f989..1386da5dbde 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -2327,14 +2327,14 @@ static bool get_new_constraint_target( /* Since by default, IK targets the tip of the last bone, * use the tip of the active PoseChannel if adding a target for an IK Constraint. */ if (con_type == CONSTRAINT_TYPE_KINEMATIC) { - mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_tail); + mul_v3_m4v3(obt->loc, obact->object_to_world, pchanact->pose_tail); } else { - mul_v3_m4v3(obt->loc, obact->obmat, pchanact->pose_head); + mul_v3_m4v3(obt->loc, obact->object_to_world, pchanact->pose_head); } } else { - copy_v3_v3(obt->loc, obact->obmat[3]); + copy_v3_v3(obt->loc, obact->object_to_world[3]); } /* restore, BKE_object_add sets active */ diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 27659042f50..63093692e43 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -535,7 +535,7 @@ static int add_hook_object(const bContext *C, ob = add_hook_object_new(bmain, scene, view_layer, v3d, obedit); /* transform cent to global coords for loc */ - mul_v3_m4v3(ob->loc, obedit->obmat, cent); + mul_v3_m4v3(ob->loc, obedit->object_to_world, cent); } md = obedit->modifiers.first; @@ -556,13 +556,13 @@ static int add_hook_object(const bContext *C, unit_m4(pose_mat); - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); if (mode == OBJECT_ADDHOOK_NEWOB) { /* pass */ } else { /* may overwrite with pose-bone location, below */ - mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]); + mul_v3_m4v3(cent, obedit->imat, ob->object_to_world[3]); } if (mode == OBJECT_ADDHOOK_SELOB_BONE) { @@ -576,7 +576,7 @@ static int add_hook_object(const bContext *C, pchan_act = BKE_pose_channel_active_if_layer_visible(ob); if (LIKELY(pchan_act)) { invert_m4_m4(pose_mat, pchan_act->pose_mat); - mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]); + mul_v3_m4v3(cent, ob->object_to_world, pchan_act->pose_mat[3]); mul_v3_m4v3(cent, obedit->imat, cent); } } @@ -588,16 +588,16 @@ static int add_hook_object(const bContext *C, copy_v3_v3(hmd->cent, cent); /* matrix calculus */ - /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */ + /* vert x (obmat x hook->imat) x hook->object_to_world x ob->imat */ /* (parentinv ) */ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); BKE_object_transform_copy(object_eval, ob); BKE_object_where_is_calc(depsgraph, scene_eval, object_eval); - invert_m4_m4(object_eval->imat, object_eval->obmat); + invert_m4_m4(object_eval->imat, object_eval->object_to_world); /* apparently this call goes from right to left... */ - mul_m4_series(hmd->parentinv, pose_mat, object_eval->imat, obedit->obmat); + mul_m4_series(hmd->parentinv, pose_mat, object_eval->imat, obedit->object_to_world); DEG_relations_tag_update(bmain); @@ -834,10 +834,10 @@ static int object_hook_recenter_exec(bContext *C, wmOperator *op) } /* recenter functionality */ - copy_m3_m4(bmat, ob->obmat); + copy_m3_m4(bmat, ob->object_to_world); invert_m3_m3(imat, bmat); - sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]); + sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->object_to_world[3]); mul_m3_v3(imat, hmd->cent); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 5da19d76259..10068def991 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -272,7 +272,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) /* inverse parent matrix */ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else { ob->partype = PARVERT1; @@ -280,7 +280,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) /* inverse parent matrix */ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } } } @@ -401,7 +401,7 @@ void ED_object_parent_clear(Object *ob, const int type) /* remove parent, and apply the parented transform * result as object's local transforms */ ob->parent = NULL; - BKE_object_apply_mat4(ob, ob->obmat, true, false); + BKE_object_apply_mat4(ob, ob->object_to_world, true, false); break; } case CLEAR_PARENT_INVERSE: { @@ -584,7 +584,7 @@ bool ED_object_parent_set(ReportList *reports, if (keep_transform) { /* Was removed because of bug T23577, * but this can be handy in some cases too T32616, so make optional. */ - BKE_object_apply_mat4(ob, ob->obmat, false, false); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); } /* Set the parent (except for follow-path constraint option). */ @@ -706,7 +706,7 @@ bool ED_object_parent_set(ReportList *reports, BKE_constraint_target_matrix_get( depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); - sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); + sub_v3_v3v3(vec, ob->object_to_world[3], cmat[3]); copy_v3_v3(ob->loc, vec); } @@ -729,7 +729,7 @@ bool ED_object_parent_set(ReportList *reports, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else if (is_armature_parent && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { if (partype == PAR_ARMATURE) { @@ -747,7 +747,7 @@ bool ED_object_parent_set(ReportList *reports, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else if ((ob->type == OB_GPENCIL) && (par->type == OB_LATTICE)) { /* Add Lattice modifier */ @@ -758,12 +758,12 @@ bool ED_object_parent_set(ReportList *reports, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } else { /* calculate inverse parent matrix */ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); } DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -772,7 +772,7 @@ bool ED_object_parent_set(ReportList *reports, static void parent_set_vert_find(KDTree_3d *tree, Object *child, int vert_par[3], bool is_tri) { - const float *co_find = child->obmat[3]; + const float *co_find = child->object_to_world[3]; if (is_tri) { KDTreeNearest_3d nearest[3]; int tot; @@ -1186,7 +1186,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) } if (type == CLEAR_TRACK_KEEP_TRANSFORM) { - BKE_object_apply_mat4(ob, ob->obmat, true, true); + BKE_object_apply_mat4(ob, ob->object_to_world, true, true); } } CTX_DATA_END; diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index 8358bf632d3..c653610d6fe 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -296,7 +296,7 @@ static void voxel_size_edit_draw(const bContext *C, ARegion * /*ar*/, void *arg) uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_matrix_push(); - GPU_matrix_mul(cd->active_object->obmat); + GPU_matrix_mul(cd->active_object->object_to_world); /* Draw Rect */ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f); @@ -494,7 +494,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev float view_normal[3] = {0.0f, 0.0f, 1.0f}; /* Calculate the view normal. */ - invert_m4_m4(active_object->imat, active_object->obmat); + invert_m4_m4(active_object->imat, active_object->object_to_world); copy_m3_m4(mat, rv3d->viewinv); mul_m3_v3(mat, view_normal); copy_m3_m4(mat, active_object->imat); @@ -535,7 +535,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* Project the selected face in the previous step of the Bounding Box. */ for (int i = 0; i < 4; i++) { float preview_plane_world_space[3]; - mul_v3_m4v3(preview_plane_world_space, active_object->obmat, cd->preview_plane[i]); + mul_v3_m4v3(preview_plane_world_space, active_object->object_to_world, cd->preview_plane[i]); ED_view3d_project_v2(region, preview_plane_world_space, preview_plane_proj[i]); } @@ -582,7 +582,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* Invert object scale. */ float scale[3]; - mat4_to_size(scale, active_object->obmat); + mat4_to_size(scale, active_object->object_to_world); invert_v3(scale); size_to_mat4(scale_mat, scale); @@ -593,7 +593,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* Scale the text to constant viewport size. */ float text_pos_word_space[3]; - mul_v3_m4v3(text_pos_word_space, active_object->obmat, text_pos); + mul_v3_m4v3(text_pos_word_space, active_object->object_to_world, text_pos); const float pixelsize = ED_view3d_pixel_size(rv3d, text_pos_word_space); scale_m4_fl(scale_mat, pixelsize * 0.5f); mul_m4_m4_post(cd->text_mat, scale_mat); diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index 6604e3da4d2..a863e9ac324 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -527,9 +527,9 @@ static void ignore_parent_tx(Main *bmain, Depsgraph *depsgraph, Scene *scene, Ob LISTBASE_FOREACH (Object *, ob_child, &bmain->objects) { if (ob_child->parent == ob) { Object *ob_child_eval = DEG_get_evaluated_object(depsgraph, ob_child); - BKE_object_apply_mat4(ob_child_eval, ob_child_eval->obmat, true, false); + BKE_object_apply_mat4(ob_child_eval, ob_child_eval->object_to_world, true, false); BKE_object_workob_calc_parent(depsgraph, scene, ob_child_eval, &workob); - invert_m4_m4(ob_child->parentinv, workob.obmat); + invert_m4_m4(ob_child->parentinv, workob.object_to_world); /* Copy result of BKE_object_apply_mat4(). */ BKE_object_transform_copy(ob_child, ob_child_eval); /* Make sure evaluated object is in a consistent state with the original one. @@ -660,11 +660,11 @@ static int apply_objects_internal(bContext *C, if (do_multi_user) { obact = CTX_data_active_object(C); - invert_m4_m4(obact_invmat, obact->obmat); + invert_m4_m4(obact_invmat, obact->object_to_world); Object workob; BKE_object_workob_calc_parent(depsgraph, scene, obact, &workob); - copy_m4_m4(obact_parent, workob.obmat); + copy_m4_m4(obact_parent, workob.object_to_world); copy_m4_m4(obact_parentinv, obact->parentinv); if (apply_objects_internal_need_single_user(C)) { @@ -989,7 +989,7 @@ static int apply_objects_internal(bContext *C, float _obmat[4][4], _iobmat[4][4]; float _mat[4][4]; - copy_m4_m4(_obmat, ob->obmat); + copy_m4_m4(_obmat, ob->object_to_world); invert_m4_m4(_iobmat, _obmat); copy_m4_m4(_mat, _obmat); @@ -1075,7 +1075,7 @@ static int visual_transform_apply_exec(bContext *C, wmOperator * /*op*/) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); BKE_object_where_is_calc(depsgraph, scene, ob_eval); - BKE_object_apply_mat4(ob_eval, ob_eval->obmat, true, true); + BKE_object_apply_mat4(ob_eval, ob_eval->object_to_world, true, true); BKE_object_transform_copy(ob, ob_eval); /* update for any children that may get moved */ @@ -1274,7 +1274,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { copy_v3_v3(cent, cursor); - invert_m4_m4(obedit->imat, obedit->obmat); + invert_m4_m4(obedit->imat, obedit->object_to_world); mul_m4_v3(obedit->imat, cent); } else { @@ -1342,7 +1342,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { copy_v3_v3(cent, cursor); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, cent); } @@ -1363,7 +1363,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) INIT_MINMAX(min, max); BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true); mid_v3_v3v3(cent, min, max); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, cent); } @@ -1554,7 +1554,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_GEOMETRY) { zero_v3(gpcenter); BKE_gpencil_centroid_3d(gpd, gpcenter); - add_v3_v3(gpcenter, ob->obmat[3]); + add_v3_v3(gpcenter, ob->object_to_world[3]); } if (centermode == ORIGIN_TO_CURSOR) { copy_v3_v3(gpcenter, cursor); @@ -1566,8 +1566,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) float offset_local[3]; int i; - sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]); - copy_m3_m4(bmat, obact->obmat); + sub_v3_v3v3(offset_global, gpcenter, ob->object_to_world[3]); + copy_m3_m4(bmat, obact->object_to_world); invert_m3_m3(imat, bmat); mul_m3_v3(imat, offset_global); mul_v3_m3v3(offset_local, imat, offset_global); @@ -1699,7 +1699,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) ob_other->flag |= OB_DONE; DEG_id_tag_update(&ob_other->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ + mul_v3_mat3_m4v3(centn, ob_other->object_to_world, cent); /* omit translation part */ add_v3_v3(ob_other->loc, centn); Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other); @@ -1873,9 +1873,9 @@ static void object_transform_axis_target_calc_depth_init(XFormAxisData *xfd, con int center_tot = 0; for (XFormAxisItem &item : xfd->object_data) { const Object *ob = item.ob; - const float *ob_co_a = ob->obmat[3]; + const float *ob_co_a = ob->object_to_world[3]; float ob_co_b[3]; - add_v3_v3v3(ob_co_b, ob->obmat[3], ob->obmat[2]); + add_v3_v3v3(ob_co_b, ob->object_to_world[3], ob->object_to_world[2]); float view_isect[3], ob_isect[3]; if (isect_line_line_v3(view_co_a, view_co_b, ob_co_a, ob_co_b, view_isect, ob_isect)) { add_v3_v3(center, view_isect); @@ -1946,7 +1946,7 @@ static void object_apply_location(Object *ob, const float loc[3]) /* quick but weak */ Object ob_prev = blender::dna::shallow_copy(*ob); float mat[4][4]; - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); copy_v3_v3(mat[3], loc); BKE_object_apply_mat4(ob, mat, true, true); copy_v3_v3(mat[3], ob->loc); @@ -1961,7 +1961,7 @@ static bool object_orient_to_location(Object *ob, const bool z_flip) { float delta[3]; - sub_v3_v3v3(delta, ob->obmat[3], location); + sub_v3_v3v3(delta, ob->object_to_world[3], location); if (normalize_v3(delta) != 0.0f) { if (z_flip) { negate_v3(delta); @@ -2139,7 +2139,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const float xform_rot_offset_inv_first[3][3]; for (const int i : xfd->object_data.index_range()) { XFormAxisItem &item = xfd->object_data[i]; - copy_m3_m4(item.xform_rot_offset, item.ob->obmat); + copy_m3_m4(item.xform_rot_offset, item.ob->object_to_world); normalize_m3(item.xform_rot_offset); if (i == 0) { @@ -2158,8 +2158,8 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const XFormAxisItem &item = xfd->object_data[i]; if (is_translate_init) { float ob_axis[3]; - item.xform_dist = len_v3v3(item.ob->obmat[3], location_world); - normalize_v3_v3(ob_axis, item.ob->obmat[2]); + item.xform_dist = len_v3v3(item.ob->object_to_world[3], location_world); + normalize_v3_v3(ob_axis, item.ob->object_to_world[2]); /* Scale to avoid adding distance when moving between surfaces. */ if (normal_found) { float scale = fabsf(dot_v3v3(ob_axis, normal)); @@ -2173,7 +2173,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const copy_v3_v3(target_normal, normal); } else { - normalize_v3_v3(target_normal, item.ob->obmat[2]); + normalize_v3_v3(target_normal, item.ob->object_to_world[2]); } #ifdef USE_RELATIVE_ROTATION @@ -2190,7 +2190,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const madd_v3_v3fl(loc, target_normal, item.xform_dist); object_apply_location(item.ob, loc); /* so orient behaves as expected */ - copy_v3_v3(item.ob->obmat[3], loc); + copy_v3_v3(item.ob->object_to_world[3], loc); } object_orient_to_location( diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c index 50ba5b8af5f..1387282357f 100644 --- a/source/blender/editors/object/object_utils.c +++ b/source/blender/editors/object/object_utils.c @@ -114,20 +114,20 @@ bool ED_object_calc_active_center(Object *ob, const bool select_only, float r_ce { if (ob->mode & OB_MODE_EDIT) { if (ED_object_calc_active_center_for_editmode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); + mul_m4_v3(ob->object_to_world, r_center); return true; } return false; } if (ob->mode & OB_MODE_POSE) { if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); + mul_m4_v3(ob->object_to_world, r_center); return true; } return false; } if (!select_only || (ob->base_flag & BASE_SELECTED)) { - copy_v3_v3(r_center, ob->obmat[3]); + copy_v3_v3(r_center, ob->object_to_world[3]); return true; } return false; @@ -245,11 +245,11 @@ void ED_object_xform_skip_child_container_item_ensure(struct XFormObjectSkipChil if (!BLI_ghash_ensure_p(xcs->obchild_in_obmode_map, ob, &xf_p)) { struct XFormObjectSkipChild *xf = MEM_mallocN(sizeof(*xf), __func__); copy_m4_m4(xf->parentinv_orig, ob->parentinv); - copy_m4_m4(xf->obmat_orig, ob->obmat); - copy_m4_m4(xf->parent_obmat_orig, ob->parent->obmat); - invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->obmat); + copy_m4_m4(xf->obmat_orig, ob->object_to_world); + copy_m4_m4(xf->parent_obmat_orig, ob->parent->object_to_world); + invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->object_to_world); if (ob_parent_recurse) { - copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->obmat); + copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->object_to_world); } xf->mode = mode; xf->ob_parent_recurse = ob_parent_recurse; @@ -274,14 +274,14 @@ void ED_object_xform_skip_child_container_update_all(struct XFormObjectSkipChild if (xf->mode == XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM) { /* Parent is transformed, this isn't so compensate. */ Object *ob_parent_eval = DEG_get_evaluated_object(depsgraph, ob->parent); - mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->obmat); + mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->object_to_world); invert_m4(dmat); } else if (xf->mode == XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT) { /* Calculate parent matrix (from the root transform). */ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(depsgraph, xf->ob_parent_recurse); float parent_recurse_obmat_inv[4][4]; - invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat); + invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->object_to_world); mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv); invert_m4(dmat); float parent_obmat_calc[4][4]; @@ -296,7 +296,7 @@ void ED_object_xform_skip_child_container_update_all(struct XFormObjectSkipChild /* Transform this - without transform data. */ Object *ob_parent_recurse_eval = DEG_get_evaluated_object(depsgraph, xf->ob_parent_recurse); float parent_recurse_obmat_inv[4][4]; - invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat); + invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->object_to_world); mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv); invert_m4(dmat); float obmat_calc[4][4]; @@ -350,7 +350,7 @@ void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container void **xf_p; if (!BLI_ghash_ensure_p(xds->obdata_in_obmode_map, ob->data, &xf_p)) { struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__); - copy_m4_m4(xf->obmat_orig, ob->obmat); + copy_m4_m4(xf->obmat_orig, ob->object_to_world); xf->ob = ob; /* Result may be NULL, that's OK. */ xf->xod = ED_object_data_xform_create(ob->data); @@ -378,7 +378,7 @@ void ED_object_data_xform_container_update_all(struct XFormObjectData_Container Object *ob_eval = DEG_get_evaluated_object(depsgraph, xf->ob); float imat[4][4], dmat[4][4]; invert_m4_m4(imat, xf->obmat_orig); - mul_m4_m4m4(dmat, imat, ob_eval->obmat); + mul_m4_m4m4(dmat, imat, ob_eval->object_to_world); invert_m4(dmat); ED_object_data_xform_by_mat4(xf->xod, dmat); diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c index a1d53cadd06..d1e6e7000d9 100644 --- a/source/blender/editors/object/object_warp.c +++ b/source/blender/editors/object/object_warp.c @@ -38,7 +38,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4], mul_m4_m4m4(viewmat_roll, mat_offset, viewmat); /* apply the view and the object matrix */ - mul_m4_m4m4(r_mat_view, viewmat_roll, obedit->obmat); + mul_m4_m4m4(r_mat_view, viewmat_roll, obedit->object_to_world); /* get the view-space cursor */ mul_v3_m4v3(r_center_view, viewmat_roll, center); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index e6d0aca7902..6dc3860fdf2 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3930,7 +3930,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(co_root, co); copy_v3_v3(no_root, &edit->emitter_cosnos[point_index * 6 + 3]); - mul_mat3_m4_v3(data->ob->obmat, no_root); /* normal into global-space */ + mul_mat3_m4_v3(data->ob->object_to_world, no_root); /* normal into global-space */ normalize_v3(no_root); if (puff_volume) { @@ -4016,8 +4016,8 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL); if (point_index != -1) { copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]); - mul_mat3_m4_v3(data->ob->obmat, onor); /* Normal into world-space. */ - mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */ + mul_mat3_m4_v3(data->ob->object_to_world, onor); /* Normal into world-space. */ + mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */ normalize_v3(onor); } else { @@ -4412,7 +4412,7 @@ static int brush_add(const bContext *C, PEData *data, short number) short size = pset->brush[PE_BRUSH_ADD].size; RNG *rng; - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); if (psys->flag & PSYS_GLOBAL_HAIR) { return 0; @@ -4797,7 +4797,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.combfac = 1.0f - data.combfac; } - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); ED_view3d_win_to_delta(region, xy_delta, bedit->zfac, vec); data.dvec = vec; @@ -4865,7 +4865,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) } data.invert = (brush->invert ^ flip); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); foreach_mouse_hit_point(&data, brush_puff, selected); } @@ -4895,7 +4895,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.smoothfac = brush->strength; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); foreach_mouse_hit_key(&data, brush_smooth_get, selected); diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 210757173eb..852156f9403 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -726,8 +726,8 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, edit_point = target_edit ? target_edit->points : NULL; - invert_m4_m4(from_ob_imat, ob->obmat); - invert_m4_m4(to_ob_imat, target_ob->obmat); + invert_m4_m4(from_ob_imat, ob->object_to_world); + invert_m4_m4(to_ob_imat, target_ob->object_to_world); invert_m4_m4(from_imat, from_mat); invert_m4_m4(to_imat, to_mat); @@ -843,7 +843,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, float offset[3]; if (to_global) { - copy_m4_m4(imat, target_ob->obmat); + copy_m4_m4(imat, target_ob->object_to_world); } else { /* NOTE: using target_dm here, which is in target_ob object space and has full modifiers. @@ -923,8 +923,8 @@ static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, Particl ob, psys, psys->edit, - ob->obmat, - ob->obmat, + ob->object_to_world, + ob->object_to_world, psys->flag & PSYS_GLOBAL_HAIR, false); if (ok) { @@ -1174,8 +1174,8 @@ static bool copy_particle_systems_to_object(const bContext *C, to_mat = I; break; case PAR_COPY_SPACE_WORLD: - from_mat = ob_from->obmat; - to_mat = ob_to->obmat; + from_mat = ob_from->object_to_world; + to_mat = ob_to->object_to_world; break; default: /* should not happen */ diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index 140199209da..5aae48b1138 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -785,7 +785,7 @@ static Object *object_preview_camera_create(Main *preview_main, float rotmat[3][3]; float dummyscale[3]; - mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->obmat); + mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->object_to_world); /* Camera is Y up, so needs additional rotations to obliquely face the front. */ float drotmat[3][3]; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 39e3c7a2f0a..a62e027ba03 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -147,7 +147,7 @@ void ED_region_do_listen(wmRegionListenerParams *params) } LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { - UI_block_views_listen(block, params); + UI_block_listen(block, params); } LISTBASE_FOREACH (uiList *, list, ®ion->ui_lists) { @@ -187,7 +187,8 @@ static void area_draw_azone_fullscreen( min_ff(alpha, 0.75f), 0.0f, NULL, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); } /** diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc index e276bae6697..8172eb8a5d7 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc @@ -185,7 +185,7 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, /* Shorten ray when the surface object is hit. */ if (surface_object_eval != nullptr) { - const float4x4 surface_to_world_mat = surface_object->obmat; + const float4x4 surface_to_world_mat = surface_object->object_to_world; const float4x4 world_to_surface_mat = surface_to_world_mat.inverted(); Mesh *surface_eval = BKE_object_get_evaluated_mesh(surface_object_eval); @@ -218,7 +218,7 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph, } } - const float4x4 curves_to_world_mat = curves_object.obmat; + const float4x4 curves_to_world_mat = curves_object.object_to_world; const float4x4 world_to_curves_mat = curves_to_world_mat.inverted(); const float3 center_ray_start_cu = world_to_curves_mat * center_ray_start_wo; diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc index 6366da310b6..df7dd871a94 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc @@ -220,8 +220,10 @@ static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEven int return_value = op->type->modal(C, op, event); if (return_value == OPERATOR_FINISHED) { - paint_stroke_free(C, op, op_data->stroke); - MEM_delete(op_data); + if (op->customdata != nullptr) { + paint_stroke_free(C, op, op_data->stroke); + MEM_delete(op_data); + } return OPERATOR_FINISHED; } @@ -236,16 +238,19 @@ static int sculpt_curves_stroke_modal(bContext *C, wmOperator *op, const wmEvent int return_value = paint_stroke_modal(C, op, event, &op_data->stroke); if (ELEM(return_value, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { MEM_delete(op_data); + op->customdata = nullptr; } return return_value; } static void sculpt_curves_stroke_cancel(bContext *C, wmOperator *op) { - SculptCurvesBrushStrokeData *op_data = static_cast<SculptCurvesBrushStrokeData *>( - op->customdata); - paint_stroke_cancel(C, op, op_data->stroke); - MEM_delete(op_data); + if (op->customdata != nullptr) { + SculptCurvesBrushStrokeData *op_data = static_cast<SculptCurvesBrushStrokeData *>( + op->customdata); + paint_stroke_cancel(C, op, op_data->stroke); + MEM_delete(op_data); + } } static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot) @@ -786,7 +791,7 @@ static void select_grow_invoke_per_curve(Curves &curves_id, }); }); - float4x4 curves_to_world_mat = curves_ob.obmat; + float4x4 curves_to_world_mat = curves_ob.object_to_world; float4x4 world_to_curves_mat = curves_to_world_mat.inverted(); float4x4 projection; diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 71ec444098e..b85b878af7d 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1071,7 +1071,7 @@ static void cursor_draw_tiling_preview(const uint gpuattr, for (int dim = 0; dim < 3; dim++) { location[dim] = cur[dim] * step[dim] + orgLoc[dim]; } - cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3); + cursor_draw_point_screen_space(gpuattr, region, location, ob->object_to_world, 3); } } } @@ -1092,7 +1092,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, /* Axis Symmetry. */ flip_v3_v3(location, true_location, (char)i); - cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3); + cursor_draw_point_screen_space(gpuattr, region, location, ob->object_to_world, 3); /* Tiling. */ cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius); @@ -1107,7 +1107,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, mul_m4_v3(symm_rot_mat, location); cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius); - cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3); + cursor_draw_point_screen_space(gpuattr, region, location, ob->object_to_world, 3); } } } @@ -1334,7 +1334,7 @@ static void paint_cursor_update_pixel_radius(PaintCursorContext *pcontext) } copy_v3_v3(pcontext->scene_space_location, pcontext->location); - mul_m4_v3(pcontext->vc.obact->obmat, pcontext->scene_space_location); + mul_m4_v3(pcontext->vc.obact->object_to_world, pcontext->scene_space_location); } else { Sculpt *sd = CTX_data_tool_settings(pcontext->C)->sculpt; @@ -1464,7 +1464,7 @@ static void paint_cursor_drawing_setup_cursor_space(PaintCursorContext *pcontext float cursor_trans[4][4], cursor_rot[4][4]; const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; float quat[4]; - copy_m4_m4(cursor_trans, pcontext->vc.obact->obmat); + copy_m4_m4(cursor_trans, pcontext->vc.obact->object_to_world); translate_m4(cursor_trans, pcontext->location[0], pcontext->location[1], pcontext->location[2]); rotation_between_vecs_to_quat(quat, z_axis, pcontext->normal); quat_to_mat4(cursor_rot, quat); @@ -1508,7 +1508,7 @@ static void paint_cursor_pose_brush_origins_draw(PaintCursorContext *pcontext) cursor_draw_point_screen_space(pcontext->pos, pcontext->region, ss->pose_ik_chain_preview->segments[i].initial_orig, - pcontext->vc.obact->obmat, + pcontext->vc.obact->object_to_world, 3); } } @@ -1526,7 +1526,7 @@ static void paint_cursor_preview_boundary_data_pivot_draw(PaintCursorContext *pc pcontext->pos, pcontext->region, SCULPT_vertex_co_get(pcontext->ss, pcontext->ss->boundary_preview->pivot_vertex), - pcontext->vc.obact->obmat, + pcontext->vc.obact->object_to_world, 3); } @@ -1634,7 +1634,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * pcontext->pos, pcontext->region, SCULPT_vertex_co_get(pcontext->ss, pcontext->ss->expand_cache->initial_active_vertex), - pcontext->vc.obact->obmat, + pcontext->vc.obact->object_to_world, 2); } @@ -1656,7 +1656,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * NULL); GPU_matrix_push(); - GPU_matrix_mul(pcontext->vc.obact->obmat); + GPU_matrix_mul(pcontext->vc.obact->object_to_world); /* Drawing Cursor overlays in 3D object space. */ if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_GRAB && @@ -1747,7 +1747,7 @@ static void paint_cursor_cursor_draw_3d_view_brush_cursor_active(PaintCursorCont NULL, NULL); GPU_matrix_push(); - GPU_matrix_mul(pcontext->vc.obact->obmat); + GPU_matrix_mul(pcontext->vc.obact->object_to_world); /* Draw the special active cursors different tools may have. */ diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index 22d6626ab16..26f76d46f85 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -44,7 +44,7 @@ bool paint_curve_poll(bContext *C) RegionView3D *rv3d = CTX_wm_region_view3d(C); SpaceImage *sima; - if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0))) { + if (rv3d && !(ob && ((ob->mode & (OB_MODE_ALL_PAINT | OB_MODE_SCULPT_CURVES)) != 0))) { return false; } @@ -676,6 +676,9 @@ static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op)) case PAINT_MODE_SCULPT: name = "SCULPT_OT_brush_stroke"; break; + case PAINT_MODE_SCULPT_CURVES: + name = "SCULPT_CURVES_OT_brush_stroke"; + break; default: return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 79316361e53..b7ce4b2973c 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -402,7 +402,8 @@ static ImBuf *brush_painter_imbuf_new( if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); - BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool); + const MTex *mtex = &brush->mtex; + BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); @@ -446,6 +447,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, { Scene *scene = painter->scene; Brush *brush = painter->brush; + const MTex *mtex = &brush->mtex; BrushPainterCache *cache = &tile->cache; const char *display_device = scene->display_settings.display_device; @@ -485,7 +487,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, if (!use_texture_old) { if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); - BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool); + BKE_brush_sample_tex_3d(scene, brush, mtex, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 41d5090b38c..ea33449f0dd 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3684,7 +3684,7 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmet ps->viewDir[1] = 0.0f; ps->viewDir[2] = 1.0f; - copy_m4_m4(ps->obmat, ps->ob->obmat); + copy_m4_m4(ps->obmat, ps->ob->object_to_world); if (symmetry_flag) { int i; @@ -3742,7 +3742,7 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps, const char symmet CameraParams params; /* viewmat & viewinv */ - copy_m4_m4(viewinv, cam_ob_eval->obmat); + copy_m4_m4(viewinv, cam_ob_eval->object_to_world); normalize_m4(viewinv); invert_m4_m4(viewmat, viewinv); @@ -4462,7 +4462,7 @@ static void project_paint_begin(const bContext *C, if (ps->source == PROJ_SRC_VIEW) { /* faster clipping lookups */ - ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); + ED_view3d_clipping_local(ps->rv3d, ps->ob->object_to_world); } ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0); @@ -5370,7 +5370,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v /* Color texture (alpha used as mask). */ if (ps->is_texbrush) { - MTex *mtex = &brush->mtex; + const MTex *mtex = BKE_brush_color_texture_get(brush, OB_MODE_TEXTURE_PAINT); float samplecos[3]; float texrgba[4]; @@ -5386,7 +5386,8 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v /* NOTE: for clone and smear, * we only use the alpha, could be a special function */ - BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool); + BKE_brush_sample_tex_3d( + ps->scene, brush, mtex, samplecos, texrgba, thread_index, pool); copy_v3_v3(texrgb, texrgba); custom_mask *= texrgba[3]; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 571ebd79764..c3e3109ac87 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1009,11 +1009,12 @@ static void sculpt_gesture_trim_shape_origin_normal_get(SculptGestureContext *sg copy_v3_v3(r_normal, sgcontext->world_space_view_normal); break; case SCULPT_GESTURE_TRIM_ORIENTATION_SURFACE: - mul_v3_m4v3(r_origin, sgcontext->vc.obact->obmat, sgcontext->ss->gesture_initial_location); + mul_v3_m4v3( + r_origin, sgcontext->vc.obact->object_to_world, sgcontext->ss->gesture_initial_location); /* Transforming the normal does not take non uniform scaling into account. Sculpt mode is not * expected to work on object with non uniform scaling. */ copy_v3_v3(r_normal, sgcontext->ss->gesture_initial_normal); - mul_mat3_m4_v3(sgcontext->vc.obact->obmat, r_normal); + mul_mat3_m4_v3(sgcontext->vc.obact->object_to_world, r_normal); break; } } @@ -1044,7 +1045,7 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext) * mesh, coordinates are first calculated in world space, then converted to object space to * store them. */ float world_space_vco[3]; - mul_v3_m4v3(world_space_vco, vc->obact->obmat, vco); + mul_v3_m4v3(world_space_vco, vc->obact->object_to_world, vco); const float dist = dist_signed_to_plane_v3(world_space_vco, shape_plane); trim_operation->depth_front = min_ff(dist, trim_operation->depth_front); trim_operation->depth_back = max_ff(dist, trim_operation->depth_back); @@ -1052,8 +1053,9 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext) if (trim_operation->use_cursor_depth) { float world_space_gesture_initial_location[3]; - mul_v3_m4v3( - world_space_gesture_initial_location, vc->obact->obmat, ss->gesture_initial_location); + mul_v3_m4v3(world_space_gesture_initial_location, + vc->obact->object_to_world, + ss->gesture_initial_location); float mid_point_depth; if (trim_operation->orientation == SCULPT_GESTURE_TRIM_ORIENTATION_VIEW) { diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index bc4c6dc4148..a70924b0626 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -564,7 +564,7 @@ static void paint_brush_stroke_add_step( if (SCULPT_stroke_get_location( C, world_space_position, stroke->last_mouse_position, stroke->original)) { copy_v3_v3(stroke->last_world_space_position, world_space_position); - mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, stroke->last_world_space_position); } else { add_v3_v3(stroke->last_world_space_position, stroke->last_scene_spacing_delta); @@ -825,7 +825,7 @@ static int paint_space_stroke(bContext *C, if (use_scene_spacing) { float world_space_position[3]; bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, world_space_position); if (hit && stroke->stroke_over_mesh) { sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position); length = len_v3(d_world_space_position); @@ -1216,8 +1216,8 @@ static void paint_line_strokes_spacing(bContext *C, C, world_space_position_old, old_pos, stroke->original); bool hit_new = SCULPT_stroke_get_location( C, world_space_position_new, new_pos, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, world_space_position_old); - mul_m4_v3(stroke->vc.obact->obmat, world_space_position_new); + mul_m4_v3(stroke->vc.obact->object_to_world, world_space_position_old); + mul_m4_v3(stroke->vc.obact->object_to_world, world_space_position_new); if (hit_old && hit_new && stroke->stroke_over_mesh) { sub_v3_v3v3(d_world_space_position, world_space_position_new, world_space_position_old); length = len_v3(d_world_space_position); @@ -1360,7 +1360,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str if (paint_stroke_use_scene_spacing(br, BKE_paintmode_get_active_from_context(C))) { stroke->stroke_over_mesh = SCULPT_stroke_get_location( C, stroke->last_world_space_position, data + 2 * j, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, stroke->last_world_space_position); } stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position); @@ -1492,7 +1492,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS if (paint_stroke_use_scene_spacing(br, mode)) { stroke->stroke_over_mesh = SCULPT_stroke_get_location( C, stroke->last_world_space_position, sample_average.mouse, stroke->original); - mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position); + mul_m4_v3(stroke->vc.obact->object_to_world, stroke->last_world_space_position); } stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse); BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */ diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index ce4a5151a20..f87ca073c82 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -135,12 +135,12 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo float delta[3], scale, loc[3]; const float xy_delta[2] = {pixel_radius, 0.0f}; - mul_v3_m4v3(loc, ob->obmat, center); + mul_v3_m4v3(loc, ob->object_to_world, center); const float zfac = ED_view3d_calc_zfac(vc->rv3d, loc); ED_view3d_win_to_delta(vc->region, xy_delta, zfac, delta); - scale = fabsf(mat4_to_scale(ob->obmat)); + scale = fabsf(mat4_to_scale(ob->object_to_world)); scale = (scale == 0.0f) ? 1.0f : scale; return len_v3(delta) / scale; @@ -297,7 +297,7 @@ static void imapaint_pick_uv( GPU_matrix_model_view_get(matrix); GPU_matrix_projection_get(proj); view[0] = view[1] = 0; - mul_m4_m4m4(matrix, matrix, ob_eval->obmat); + mul_m4_m4m4(matrix, matrix, ob_eval->object_to_world); mul_m4_m4m4(matrix, proj, matrix); minabsw = 1e10; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index 6e3504332ed..ac5ad62c91f 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -433,9 +433,10 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp, float r_rgba[4]) { const Brush *brush = BKE_paint_brush(&vp->paint); - BLI_assert(brush->mtex.tex != nullptr); - if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { - BKE_brush_sample_tex_3d(vc->scene, brush, co, r_rgba, 0, nullptr); + const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT); + BLI_assert(mtex->tex != nullptr); + if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { + BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co, r_rgba, 0, nullptr); } else { float co_ss[2]; /* screenspace */ @@ -445,7 +446,7 @@ static void paint_and_tex_color_alpha_intern(VPaint *vp, co_ss, (eV3DProjTest)(V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR)) == V3D_PROJ_RET_OK) { const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */ - BKE_brush_sample_tex_3d(vc->scene, brush, co_ss_3d, r_rgba, 0, nullptr); + BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co_ss_3d, r_rgba, 0, nullptr); } else { zero_v4(r_rgba); @@ -1646,7 +1647,7 @@ static void vwpaint_update_cache_invariants( /* cache projection matrix */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, cache->vc->rv3d->viewinv); mul_m3_v3(mat, view_dir); copy_m3_m4(mat, ob->imat); @@ -2517,7 +2518,7 @@ static void wpaint_stroke_update_step(bContext *C, ED_view3d_init_mats_rv3d(ob, vc->rv3d); /* load projection matrix */ - mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); + mul_m4_m4m4(mat, vc->rv3d->persmat, ob->object_to_world); Mesh *mesh = static_cast<Mesh *>(ob->data); @@ -2555,7 +2556,7 @@ static void wpaint_stroke_update_step(bContext *C, /* Calculate pivot for rotation around selection if needed. * also needed for "Frame Selected" on last stroke. */ float loc_world[3]; - mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location); + mul_v3_m4v3(loc_world, ob->object_to_world, ss->cache->true_location); paint_last_stroke_update(scene, loc_world); BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL); @@ -3846,7 +3847,7 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P ED_view3d_init_mats_rv3d(ob, vc->rv3d); /* load projection matrix */ - mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); + mul_m4_m4m4(mat, vc->rv3d->persmat, ob->object_to_world); swap_m4m4(vc->rv3d->persmat, mat); @@ -3869,7 +3870,7 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P /* Calculate pivot for rotation around selection if needed. * also needed for "Frame Selected" on last stroke. */ float loc_world[3]; - mul_v3_m4v3(loc_world, ob->obmat, ss->cache->true_location); + mul_v3_m4v3(loc_world, ob->object_to_world, ss->cache->true_location); paint_last_stroke_update(scene, loc_world); ED_region_tag_redraw(vc->region); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 0f71acd3698..24c6f1b0c3d 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1121,8 +1121,8 @@ void SCULPT_tag_update_overlays(bContext *C) DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); - View3D *v3d = CTX_wm_view3d(C); - if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } } @@ -2458,7 +2458,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, { StrokeCache *cache = ss->cache; const Scene *scene = cache->vc->scene; - const MTex *mtex = &br->mtex; + const MTex *mtex = BKE_brush_mask_texture_get(br, OB_MODE_SCULPT); float avg = 1.0f; float rgba[4]; float point[3]; @@ -2470,7 +2470,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, } else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { /* Get strength by feeding the vertex location directly into a texture. */ - avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool); + avg = BKE_brush_sample_tex_3d(scene, br, mtex, point, rgba, 0, ss->tex_pool); } else { float symm_point[3], point_2d[2]; @@ -2499,19 +2499,19 @@ float SCULPT_brush_strength_factor(SculptSession *ss, x = symm_point[0]; y = symm_point[1]; - x *= br->mtex.size[0]; - y *= br->mtex.size[1]; + x *= mtex->size[0]; + y *= mtex->size[1]; - x += br->mtex.ofs[0]; - y += br->mtex.ofs[1]; + x += mtex->ofs[0]; + y += mtex->ofs[1]; - avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id); + avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id); avg += br->texture_sample_bias; } else { const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f}; - avg = BKE_brush_sample_tex_3d(scene, br, point_3d, rgba, 0, ss->tex_pool); + avg = BKE_brush_sample_tex_3d(scene, br, mtex, point_3d, rgba, 0, ss->tex_pool); } } @@ -2793,7 +2793,7 @@ static void calc_brush_local_mat(const Brush *brush, Object *ob, float local_mat float up[3]; /* Ensure `ob->imat` is up to date. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); /* Initialize last column of matrix. */ mat[0][3] = 0.0f; @@ -2833,7 +2833,7 @@ void SCULPT_tilt_apply_to_normal(float r_normal[3], StrokeCache *cache, const fl return; } const float rot_max = M_PI_2 * tilt_strength * SCULPT_TILT_SENSITIVITY; - mul_v3_mat3_m4v3(r_normal, cache->vc->obact->obmat, r_normal); + mul_v3_mat3_m4v3(r_normal, cache->vc->obact->object_to_world, r_normal); float normal_tilt_y[3]; rotate_v3_v3v3fl(normal_tilt_y, r_normal, cache->vc->rv3d->viewinv[0], cache->y_tilt * rot_max); float normal_tilt_xy[3]; @@ -3284,7 +3284,7 @@ static void sculpt_topology_update(Sculpt *sd, /* Update average stroke position. */ copy_v3_v3(location, ss->cache->true_location); - mul_m4_v3(ob->obmat, location); + mul_m4_v3(ob->object_to_world, location); } static void do_brush_action_task_cb(void *__restrict userdata, @@ -3615,7 +3615,7 @@ static void do_brush_action(Sculpt *sd, /* Update average stroke position. */ copy_v3_v3(location, ss->cache->true_location); - mul_m4_v3(ob->obmat, location); + mul_m4_v3(ob->object_to_world, location); add_v3_v3(ups->average_stroke_accum, location); ups->average_stroke_counter++; @@ -4201,8 +4201,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) /* Store matrix for mirror object clipping. */ if (mmd->mirror_ob) { float imtx_mirror_ob[4][4]; - invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat); - mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat); + invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->object_to_world); + mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->object_to_world); } } } @@ -4354,7 +4354,7 @@ static void sculpt_update_cache_invariants( /* Cache projection matrix. */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, cache->vc->rv3d->viewinv); mul_m3_v3(mat, viewDir); copy_m3_m4(mat, ob->imat); @@ -4373,7 +4373,7 @@ static void sculpt_update_cache_invariants( if (sd->gravity_object) { Object *gravity_object = sd->gravity_object; - copy_v3_v3(cache->true_gravity_direction, gravity_object->obmat[2]); + copy_v3_v3(cache->true_gravity_direction, gravity_object->object_to_world[2]); } else { cache->true_gravity_direction[0] = cache->true_gravity_direction[1] = 0.0f; @@ -4527,27 +4527,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru } /* Compute 3d coordinate at same z from original location + mval. */ - mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location); + mul_v3_m4v3(loc, ob->object_to_world, cache->orig_grab_location); ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location); /* Compute delta to move verts by. */ if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { if (sculpt_needs_delta_from_anchored_origin(brush)) { sub_v3_v3v3(delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_mat3_m4_v3(imat, delta); add_v3_v3(cache->grab_delta, delta); } else if (sculpt_needs_delta_for_tip_orientation(brush)) { if (brush->flag & BRUSH_ANCHORED) { float orig[3]; - mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location); + mul_v3_m4v3(orig, ob->object_to_world, cache->orig_grab_location); sub_v3_v3v3(cache->grab_delta, grab_location, orig); } else { sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); } - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_mat3_m4_v3(imat, cache->grab_delta); } else { @@ -4592,7 +4592,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru /* Handle 'rake' */ cache->is_rake_rotation_valid = false; - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); mul_mat3_m4_v3(imat, grab_location); if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { @@ -4813,12 +4813,12 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd, void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush) { SculptSession *ss = ob->sculpt; - View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); Sculpt *sd = CTX_data_tool_settings(C)->sculpt; bool need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, 0); if (ss->shapekey_active || ss->deform_modifiers_active || - (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) { + (!BKE_sculptsession_use_pbvh_draw(ob, rv3d) && need_pmap)) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); BKE_sculpt_update_object_for_edit( depsgraph, ob, need_pmap, false, SCULPT_tool_is_paint(brush->sculpt_tool)); @@ -4913,7 +4913,7 @@ float SCULPT_raycast_init(ViewContext *vc, ED_view3d_win_to_segment_clipped( vc->depsgraph, vc->region, vc->v3d, mval, ray_start, ray_end, true); - invert_m4_m4(obimat, ob->obmat); + invert_m4_m4(obimat, ob->object_to_world); mul_m4_v3(obimat, ray_start); mul_m4_v3(obimat, ray_end); @@ -5021,7 +5021,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C, float radius; /* Update cursor data in SculptSession. */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, vc.rv3d->viewinv); mul_m3_v3(mat, viewDir); copy_m3_m4(mat, ob->imat); @@ -5249,7 +5249,6 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags) SculptSession *ss = ob->sculpt; ARegion *region = CTX_wm_region(C); MultiresModifierData *mmd = ss->multires.modifier; - View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); if (rv3d) { @@ -5274,7 +5273,7 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags) /* Only current viewport matters, slower update for all viewports will * be done in sculpt_flush_update_done. */ - if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) { + if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) { /* Slow update with full dependency graph update and all that comes with it. * Needed when there are modifiers or full shading in the 3D viewport. */ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); @@ -5316,16 +5315,15 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up /* After we are done drawing the stroke, check if we need to do a more * expensive depsgraph tag to update geometry. */ wmWindowManager *wm = CTX_wm_manager(C); - View3D *current_v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); + RegionView3D *current_rv3d = CTX_wm_region_view3d(C); SculptSession *ss = ob->sculpt; Mesh *mesh = ob->data; /* Always needed for linked duplicates. */ bool need_tag = (ID_REAL_USERS(&mesh->id) > 1); - if (rv3d) { - rv3d->rflag &= ~RV3D_PAINTING; + if (current_rv3d) { + current_rv3d->rflag &= ~RV3D_PAINTING; } LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { @@ -5335,16 +5333,17 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up if (sl->spacetype != SPACE_VIEW3D) { continue; } - View3D *v3d = (View3D *)sl; - if (v3d != current_v3d) { - need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, v3d); - } /* Tag all 3D viewports for redraw now that we are done. Others * viewports did not get a full redraw, and anti-aliasing for the * current viewport was deactivated. */ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = region->regiondata; + if (rv3d != current_rv3d) { + need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, rv3d); + } + ED_region_tag_redraw(region); } } @@ -5378,15 +5377,17 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up BKE_sculpt_attributes_destroy_temporary_stroke(ob); - if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - BKE_pbvh_bmesh_after_stroke(ss->pbvh); - } + if (update_flags & SCULPT_UPDATE_COORDS) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + BKE_pbvh_bmesh_after_stroke(ss->pbvh); + } - /* 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->shapekey_active && !ss->deform_modifiers_active) { - sculpt_update_keyblock(ob); + /* 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->shapekey_active && !ss->deform_modifiers_active) { + sculpt_update_keyblock(ob); + } } if (need_tag) { @@ -5511,7 +5512,8 @@ static void sculpt_stroke_update_step(bContext *C, sculpt_restore_mesh(sd, ob); if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) { - float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat)); + float object_space_constant_detail = 1.0f / (sd->constant_detail * + mat4_to_scale(ob->object_to_world)); BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail); } else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) { @@ -5625,6 +5627,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str } else { BKE_sculpt_attributes_destroy_temporary_stroke(ob); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COLOR); } } else { diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index b6bb4c185f9..cf7e1d027f7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -667,15 +667,15 @@ static void cloth_brush_solve_collision(Object *object, BVHTreeRayHit hit; float obmat_inv[4][4]; - invert_m4_m4(obmat_inv, object->obmat); + invert_m4_m4(obmat_inv, object->object_to_world); for (collider_cache = cloth_sim->collider_list->first; collider_cache; collider_cache = collider_cache->next) { float ray_start[3], ray_normal[3]; float pos_world_space[3], prev_pos_world_space[3]; - mul_v3_m4v3(pos_world_space, object->obmat, cloth_sim->pos[i]); - mul_v3_m4v3(prev_pos_world_space, object->obmat, cloth_sim->last_iteration_pos[i]); + mul_v3_m4v3(pos_world_space, object->object_to_world, cloth_sim->pos[i]); + mul_v3_m4v3(prev_pos_world_space, object->object_to_world, cloth_sim->last_iteration_pos[i]); sub_v3_v3v3(ray_normal, pos_world_space, prev_pos_world_space); copy_v3_v3(ray_start, prev_pos_world_space); hit.index = -1; @@ -1419,7 +1419,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, float sculpt_gravity[3] = {0.0f}; if (sd->gravity_object) { - copy_v3_v3(sculpt_gravity, sd->gravity_object->obmat[2]); + copy_v3_v3(sculpt_gravity, sd->gravity_object->object_to_world[2]); } else { sculpt_gravity[2] = -1.0f; diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index 6dd718d6a0c..0e46fd50f3b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -102,7 +102,8 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *op) size = max_fff(dim[0], dim[1], dim[2]); /* Update topology size. */ - float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat)); + float object_space_constant_detail = 1.0f / + (sd->constant_detail * mat4_to_scale(ob->object_to_world)); BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail); SCULPT_undo_push_begin(ob, op); @@ -223,7 +224,7 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2 if (srd.hit && srd.edge_length > 0.0f) { /* Convert edge length to world space detail resolution. */ - sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat)); + sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->object_to_world)); } } @@ -473,8 +474,8 @@ static void dyntopo_detail_size_parallel_lines_draw(uint pos3d, bool flip, const float angle) { - float object_space_constant_detail = 1.0f / - (cd->detail_size * mat4_to_scale(cd->active_object->obmat)); + float object_space_constant_detail = 1.0f / (cd->detail_size * + mat4_to_scale(cd->active_object->object_to_world)); /* The constant detail represents the maximum edge length allowed before subdividing it. If the * triangle grid preview is created with this value it will represent an ideal mesh density where @@ -592,7 +593,8 @@ static void dyntopo_detail_size_sample_from_surface(Object *ob, if (num_neighbors > 0) { const float avg_edge_len = len_accum / num_neighbors; /* Use 0.7 as the average of min and max dyntopo edge length. */ - const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat)); + const float detail_size = 0.7f / + (avg_edge_len * mat4_to_scale(cd->active_object->object_to_world)); cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f); } } @@ -716,7 +718,7 @@ static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wm float cursor_trans[4][4], cursor_rot[4][4]; const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; float quat[4]; - copy_m4_m4(cursor_trans, active_object->obmat); + copy_m4_m4(cursor_trans, active_object->object_to_world); translate_m4( cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]); diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 655b03bbb36..3133bb2007e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -167,15 +167,16 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss, if (expand_cache->texture_distortion_strength == 0.0f) { return expand_cache->vert_falloff[v_i]; } - - if (!expand_cache->brush->mtex.tex) { + const Brush *brush = expand_cache->brush; + const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT); + if (!mtex->tex) { return expand_cache->vert_falloff[v_i]; } float rgba[4]; const float *vertex_co = SCULPT_vertex_co_get(ss, v); const float avg = BKE_brush_sample_tex_3d( - expand_cache->scene, expand_cache->brush, vertex_co, rgba, 0, ss->tex_pool); + expand_cache->scene, brush, mtex, vertex_co, rgba, 0, ss->tex_pool); const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength * expand_cache->max_vert_falloff; diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index ee1238e0f24..40835172be9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -18,6 +18,7 @@ #include "BLI_math_vector.hh" #include "BLI_span.hh" #include "BLI_task.h" +#include "BLI_task.hh" #include "DNA_brush_types.h" #include "DNA_customdata_types.h" @@ -313,6 +314,7 @@ static EnumPropertyItem prop_sculpt_face_set_create_types[] = { static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) { + using namespace blender; Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); @@ -396,25 +398,16 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (mode == SCULPT_FACE_SET_SELECTION) { - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - BMeshCreateParams create_params{}; - create_params.use_toolflags = true; - bm = BM_mesh_create(&allocsize, &create_params); - - BMeshFromMeshParams convert_params{}; - convert_params.calc_vert_normal = true; - convert_params.calc_face_normal = true; - BM_mesh_bm_from_me(bm, mesh, &convert_params); - - BMIter iter; - BMFace *f; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - ss->face_sets[BM_elem_index_get(f)] = next_face_set; + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArraySpan<bool> select_poly = attributes.lookup_or_default<bool>( + ".select_poly", ATTR_DOMAIN_FACE, false); + threading::parallel_for(IndexRange(mesh->totvert), 4096, [&](const IndexRange range) { + for (const int i : range) { + if (select_poly[i]) { + ss->face_sets[i] = next_face_set; + } } - } - BM_mesh_free(bm); + }); } for (int i = 0; i < totnode; i++) { @@ -924,7 +917,7 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; float location[3]; copy_v3_v3(location, SCULPT_active_vertex_co_get(ss)); - mul_m4_v3(ob->obmat, location); + mul_m4_v3(ob->object_to_world, location); copy_v3_v3(ups->average_stroke_accum, location); ups->average_stroke_counter = 1; ups->last_stroke_valid = true; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 1fa53eaa006..078f0217416 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -146,8 +146,8 @@ void SCULPT_filter_cache_init(bContext *C, 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings); /* Setup orientation matrices. */ - copy_m4_m4(ss->filter_cache->obmat, ob->obmat); - invert_m4_m4(ss->filter_cache->obmat_inv, ob->obmat); + copy_m4_m4(ss->filter_cache->obmat, ob->object_to_world); + invert_m4_m4(ss->filter_cache->obmat_inv, ob->object_to_world); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; @@ -203,7 +203,7 @@ void SCULPT_filter_cache_init(bContext *C, /* Update last stroke location */ - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); add_v3_v3(ups->average_stroke_accum, co); ups->average_stroke_counter++; @@ -221,7 +221,7 @@ void SCULPT_filter_cache_init(bContext *C, ED_view3d_ob_project_mat_get(vc.rv3d, ob, projection_mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); copy_m3_m4(mat, vc.rv3d->viewinv); mul_m3_v3(mat, viewDir); copy_m3_m4(mat, ob->imat); diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index a740ec2773b..8affb0e9d53 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -323,7 +323,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain, BKE_report( reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable"); } - else if (is_negative_m4(ob->obmat)) { + else if (is_negative_m4(ob->object_to_world)) { BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable"); } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 13e3dd64521..eb92c865f18 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -857,7 +857,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); SculptSession *ss = ob->sculpt; @@ -911,7 +911,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); - if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) { + if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } @@ -1070,7 +1070,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } } - tag_update |= ID_REAL_USERS(ob->data) > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d) || + tag_update |= ID_REAL_USERS(ob->data) > 1 || !BKE_sculptsession_use_pbvh_draw(ob, rv3d) || ss->shapekey_active || ss->deform_modifiers_active; if (tag_update) { diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index eb56c6c4b54..343975919e2 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -104,7 +104,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region) UI_block_draw(C, block); } - /* free tempolary channels */ + /* Free temporary channels. */ ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index a9ce9a3d723..9c8d46a41f9 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -41,7 +41,7 @@ /* -------------------------------------------------------------------- */ /** \name Start / Clear Search Filter Operators * - * \note Almost a duplicate of the file browser operator #FILE_OT_start_filter. + * \note Almost a duplicate of the file browser operator #FILE_OT_start_filter. * \{ */ static int buttons_start_filter_exec(bContext *C, wmOperator *UNUSED(op)) @@ -205,7 +205,7 @@ static int file_browse_exec(bContext *C, wmOperator *op) if (BLI_is_dir(path)) { /* Do this first so '//' isn't converted to '//\' on windows. */ - BLI_path_slash_ensure(path); + BLI_path_slash_ensure(path, sizeof(path)); if (is_relative) { BLI_path_rel(path, BKE_main_blendfile_path(bmain)); str_len = strlen(path); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 5bdb4b185e7..c3249b26fdd 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -410,8 +410,15 @@ static void file_draw_preview(const SpaceFile *sfile, } icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); icon_y = yco + (ey / 2.0f) - (icon_size * ((file->typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f)); - UI_icon_draw_ex( - icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + UI_icon_draw_ex(icon_x, + icon_y, + icon, + icon_aspect / U.dpi_fac, + icon_opacity, + 0.0f, + icon_color, + false, + UI_NO_ICON_OVERLAY_TEXT); } if (is_link || is_offline) { @@ -424,8 +431,24 @@ static void file_draw_preview(const SpaceFile *sfile, /* At very bottom-left if preview style. */ const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; - UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, + icon_y - 1, + arrow, + 1.0f / U.dpi_fac, + 0.2f, + 0.0f, + dark, + false, + UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex(icon_x, + icon_y, + arrow, + 1.0f / U.dpi_fac, + 0.6f, + 0.0f, + light, + false, + UI_NO_ICON_OVERLAY_TEXT); } else { /* Link to folder or non-previewed file. */ @@ -433,8 +456,15 @@ static void file_draw_preview(const SpaceFile *sfile, UI_GetThemeColor4ubv(TH_BACK, icon_color); icon_x = xco + ((file->typeflag & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; icon_y = yco + ((file->typeflag & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; - UI_icon_draw_ex( - icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); + UI_icon_draw_ex(icon_x, + icon_y, + arrow, + icon_aspect / U.dpi_fac * 1.8, + 0.3f, + 0.0f, + icon_color, + false, + UI_NO_ICON_OVERLAY_TEXT); } } else if (icon && !is_icon && !(file->typeflag & FILE_TYPE_FTFONT)) { @@ -444,8 +474,17 @@ static void file_draw_preview(const SpaceFile *sfile, const uchar light[4] = {255, 255, 255, 255}; icon_x = xco + (2.0f * UI_DPI_FAC); icon_y = yco + (2.0f * UI_DPI_FAC); - UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); - UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x + 1, + icon_y - 1, + icon, + 1.0f / U.dpi_fac, + 0.2f, + 0.0f, + dark, + false, + UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex( + icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false, UI_NO_ICON_OVERLAY_TEXT); } const bool is_current_main_data = filelist_file_get_id(file) != NULL; @@ -456,7 +495,15 @@ static void file_draw_preview(const SpaceFile *sfile, const uchar light[4] = {255, 255, 255, 255}; icon_x = xco + ex - UI_UNIT_X; icon_y = yco + ey - UI_UNIT_Y; - UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + UI_icon_draw_ex(icon_x, + icon_y, + ICON_CURRENT_FILE, + 1.0f / U.dpi_fac, + 0.6f, + 0.0f, + light, + false, + UI_NO_ICON_OVERLAY_TEXT); } /* Contrasting outline around some preview types. */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index a4d4bf98474..f68d329329f 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -197,13 +197,12 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) } else if (file->redirection_path) { BLI_strncpy(params->dir, file->redirection_path, sizeof(params->dir)); - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); - BLI_path_slash_ensure(params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); + BLI_path_slash_ensure(params->dir, sizeof(params->dir)); } else { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); - strcat(params->dir, file->relpath); - BLI_path_slash_ensure(params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); + BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath); } ED_file_change_dir(C); @@ -1095,7 +1094,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1564,7 +1563,13 @@ void file_sfile_to_operator_ex( PropertyRNA *prop; /* XXX, not real length */ - BLI_path_join(filepath, FILE_MAX, params->dir, params->file); + if (params->file[0]) { + BLI_path_join(filepath, FILE_MAX, params->dir, params->file); + } + else { + BLI_strncpy(filepath, params->dir, FILE_MAX); + BLI_path_slash_ensure(filepath, FILE_MAX); + } if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { if (RNA_property_boolean_get(op->ptr, prop)) { @@ -1791,8 +1796,7 @@ static bool file_execute(bContext *C, SpaceFile *sfile) } else { BLI_path_normalize(BKE_main_blendfile_path(bmain), params->dir); - BLI_path_append(params->dir, sizeof(params->dir) - 1, file->relpath); - BLI_path_slash_ensure(params->dir); + BLI_path_append_dir(params->dir, sizeof(params->dir), file->relpath); } ED_file_change_dir(C); } @@ -1955,7 +1959,7 @@ static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) if (params) { if (BLI_path_parent_dir(params->dir)) { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); ED_file_change_dir(C); if (params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ @@ -2538,7 +2542,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN } } - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir, sizeof(params->dir)); if (filelist_is_dir(sfile->files, params->dir)) { if (!STREQ(params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ @@ -2625,7 +2629,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg /* if directory, open it and empty filename field */ if (filelist_is_dir(sfile->files, filepath)) { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath, sizeof(filepath)); BLI_strncpy(params->dir, filepath, sizeof(params->dir)); params->file[0] = '\0'; ED_file_change_dir(C); diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc index 4aa85f3f169..d4a42c3f4f2 100644 --- a/source/blender/editors/space_file/filelist.cc +++ b/source/blender/editors/space_file/filelist.cc @@ -1220,7 +1220,7 @@ static int filelist_geticon_ex(const FileDirEntry *file, } else if (root) { BLI_path_join(fullpath, sizeof(fullpath), root, file->relpath); - BLI_path_slash_ensure(fullpath); + BLI_path_slash_ensure(fullpath, sizeof(fullpath)); } for (; tfsm; tfsm = tfsm->next) { if (STREQ(tfsm->path, target)) { @@ -1964,7 +1964,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) const bool allow_invalid = filelist->asset_library_ref != nullptr; BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); - BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); + BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir, FILE_MAX_LIBEXTRA); const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid); BLI_assert(is_valid_path || allow_invalid); UNUSED_VARS_NDEBUG(is_valid_path); @@ -2932,7 +2932,7 @@ static int filelist_readjob_list_dir(const char *root, if (BLI_file_alias_target(full_path, entry->redirection_path)) { if (BLI_is_dir(entry->redirection_path)) { entry->typeflag = FILE_TYPE_DIR; - BLI_path_slash_ensure(entry->redirection_path); + BLI_path_slash_ensure(entry->redirection_path, FILE_MAXDIR); } else { entry->typeflag = (eFileSel_File_Types)ED_path_extension_type(entry->redirection_path); @@ -3494,7 +3494,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); - BLI_path_normalize_dir(job_params->main_name, dir); + BLI_path_normalize_dir(job_params->main_name, dir, sizeof(dir)); td_dir->dir = BLI_strdup(dir); /* Init the file indexer. */ @@ -3525,7 +3525,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, * Note that in the end, this means we 'cache' valid relative subdir once here, * this is actually better. */ BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); - BLI_path_normalize_dir(root, rel_subdir); + BLI_path_normalize_dir(root, rel_subdir, sizeof(rel_subdir)); BLI_path_rel(rel_subdir, root); bool is_lib = false; @@ -3573,7 +3573,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, max_recursion, is_lib, recursion_level, entry)) { /* We have a directory we want to list, add it to todo list! */ BLI_path_join(dir, sizeof(dir), root, entry->relpath); - BLI_path_normalize_dir(job_params->main_name, dir); + BLI_path_normalize_dir(job_params->main_name, dir, sizeof(dir)); td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs)); td_dir->level = recursion_level + 1; td_dir->dir = BLI_strdup(dir); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 8f419d256e5..6dd4e37fea8 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -199,7 +199,7 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) } if (params->dir[0]) { - BLI_path_normalize_dir(blendfile_path, params->dir); + BLI_path_normalize_dir(blendfile_path, params->dir, sizeof(params->dir)); BLI_path_abs(params->dir, blendfile_path); } @@ -1201,7 +1201,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v)) match = UI_autocomplete_end(autocpl, str); if (match == AUTOCOMPLETE_FULL_MATCH) { - BLI_path_slash_ensure(str); + BLI_path_slash_ensure(str, FILE_MAX); } } } diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 41a8368152d..f8a0dff3a41 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -1446,7 +1446,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region) GPU_blend(GPU_BLEND_NONE); } - /* free tempolary channels */ + /* Free temporary channels. */ ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index aee72860a0a..12ee6f45991 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -235,7 +235,8 @@ static bool textview_draw_string(TextViewDrawState *tds, 1.0f, 0.0f, icon_fg, - false); + false, + UI_NO_ICON_OVERLAY_TEXT); GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index f57c9fead56..45bbe50eedd 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -905,7 +905,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region) } } - /* free tempolary channels */ + /* Free temporary channels. */ ANIM_animdata_freelist(&anim_data); } diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index d7eccbf0b68..ff9e5352d0a 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC set(SRC add_node_search.cc + add_menu_assets.cc drawnode.cc link_drag_search.cc node_add.cc diff --git a/source/blender/editors/space_node/add_menu_assets.cc b/source/blender/editors/space_node/add_menu_assets.cc new file mode 100644 index 00000000000..1ba1d67d854 --- /dev/null +++ b/source/blender/editors/space_node/add_menu_assets.cc @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_multi_value_map.hh" + +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BKE_asset.h" +#include "BKE_asset_catalog.hh" +#include "BKE_asset_library.hh" +#include "BKE_idprop.h" +#include "BKE_screen.h" + +#include "BLT_translation.h" + +#include "RNA_access.h" +#include "RNA_prototypes.h" + +#include "ED_asset.h" +#include "ED_screen.h" + +#include "node_intern.hh" + +namespace blender::ed::space_node { + +static bool node_add_menu_poll(const bContext *C, MenuType * /*mt*/) +{ + return CTX_wm_space_node(C); +} + +static void node_add_menu_assets_listen_fn(const wmRegionListenerParams *params) +{ + const wmNotifier *wmn = params->notifier; + ARegion *region = params->region; + + switch (wmn->category) { + case NC_ASSET: + if (wmn->data == ND_ASSET_LIST_READING) { + ED_region_tag_refresh_ui(region); + } + break; + } +} + +struct LibraryAsset { + AssetLibraryReference library_ref; + AssetHandle handle; +}; + +struct LibraryCatalog { + bke::AssetLibrary *library; + const bke::AssetCatalog *catalog; +}; + +struct AssetItemTree { + bke::AssetCatalogTree catalogs; + MultiValueMap<bke::AssetCatalogPath, LibraryAsset> assets_per_path; + Map<const bke::AssetCatalogTreeItem *, bke::AssetCatalogPath> full_catalog_per_tree_item; +}; + +static bool all_loading_finished() +{ + for (const AssetLibraryReference &library : bke::all_valid_asset_library_refs()) { + if (!ED_assetlist_is_loaded(&library)) { + return false; + } + } + return true; +} + +static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node_tree) +{ + if (!node_tree) { + return {}; + } + const Main &bmain = *CTX_data_main(&C); + const Vector<AssetLibraryReference> all_libraries = bke::all_valid_asset_library_refs(); + + /* Merge catalogs from all libraries to deduplicate menu items. Also store the catalog and + * library for each asset ID in order to use them later when retrieving assets and removing + * empty catalogs. */ + Map<bke::CatalogID, LibraryCatalog> id_to_catalog_map; + bke::AssetCatalogTree catalogs_from_all_libraries; + for (const AssetLibraryReference &library_ref : all_libraries) { + if (bke::AssetLibrary *library = BKE_asset_library_load(&bmain, library_ref)) { + if (bke::AssetCatalogTree *tree = library->catalog_service->get_catalog_tree()) { + tree->foreach_item([&](bke::AssetCatalogTreeItem &item) { + const bke::CatalogID &id = item.get_catalog_id(); + bke::AssetCatalog *catalog = library->catalog_service->find_catalog(id); + catalogs_from_all_libraries.insert_item(*catalog); + id_to_catalog_map.add(item.get_catalog_id(), LibraryCatalog{library, catalog}); + }); + } + } + } + + /* Find all the matching node group assets for every catalog path. */ + MultiValueMap<bke::AssetCatalogPath, LibraryAsset> assets_per_path; + for (const AssetLibraryReference &library_ref : all_libraries) { + AssetFilterSettings type_filter{}; + type_filter.id_types = FILTER_ID_NT; + + ED_assetlist_storage_fetch(&library_ref, &C); + ED_assetlist_ensure_previews_job(&library_ref, &C); + ED_assetlist_iterate(library_ref, [&](AssetHandle asset) { + if (!ED_asset_filter_matches_asset(&type_filter, &asset)) { + return true; + } + const AssetMetaData &meta_data = *ED_asset_handle_get_metadata(&asset); + const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type"); + if (tree_type == nullptr || IDP_Int(tree_type) != node_tree->type) { + return true; + } + if (BLI_uuid_is_nil(meta_data.catalog_id)) { + return true; + } + const LibraryCatalog &library_catalog = id_to_catalog_map.lookup(meta_data.catalog_id); + assets_per_path.add(library_catalog.catalog->path, LibraryAsset{library_ref, asset}); + return true; + }); + } + + /* Build the final tree without any of the catalogs that don't have proper node group assets. */ + bke::AssetCatalogTree catalogs_with_node_assets; + catalogs_from_all_libraries.foreach_item([&](bke::AssetCatalogTreeItem &item) { + if (!assets_per_path.lookup(item.catalog_path()).is_empty()) { + const bke::CatalogID &id = item.get_catalog_id(); + const LibraryCatalog &library_catalog = id_to_catalog_map.lookup(id); + bke::AssetCatalog *catalog = library_catalog.library->catalog_service->find_catalog(id); + catalogs_with_node_assets.insert_item(*catalog); + } + }); + + /* Build another map storing full asset paths for each tree item, in order to have stable + * pointers to asset catalog paths to use for context pointers. This is necessary because + * #bke::AssetCatalogTreeItem doesn't store its full path directly. */ + Map<const bke::AssetCatalogTreeItem *, bke::AssetCatalogPath> full_catalog_per_tree_item; + catalogs_with_node_assets.foreach_item([&](bke::AssetCatalogTreeItem &item) { + full_catalog_per_tree_item.add_new(&item, item.catalog_path()); + }); + + return {std::move(catalogs_with_node_assets), + std::move(assets_per_path), + std::move(full_catalog_per_tree_item)}; +} + +static void node_add_catalog_assets_draw(const bContext *C, Menu *menu) +{ + bScreen &screen = *CTX_wm_screen(C); + const SpaceNode &snode = *CTX_wm_space_node(C); + if (!snode.runtime->assets_for_menu) { + BLI_assert_unreachable(); + return; + } + AssetItemTree &tree = *snode.runtime->assets_for_menu; + const bNodeTree *edit_tree = snode.edittree; + if (!edit_tree) { + return; + } + + const PointerRNA menu_path_ptr = CTX_data_pointer_get(C, "asset_catalog_path"); + if (RNA_pointer_is_null(&menu_path_ptr)) { + return; + } + const bke::AssetCatalogPath &menu_path = *static_cast<const bke::AssetCatalogPath *>( + menu_path_ptr.data); + + const Span<LibraryAsset> asset_items = tree.assets_per_path.lookup(menu_path); + bke::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item(menu_path); + BLI_assert(catalog_item != nullptr); + + if (asset_items.is_empty() && !catalog_item->has_children()) { + return; + } + + uiLayout *layout = menu->layout; + uiItemS(layout); + + for (const LibraryAsset &item : asset_items) { + uiLayout *col = uiLayoutColumn(layout, false); + PointerRNA file{ + &screen.id, &RNA_FileSelectEntry, const_cast<FileDirEntry *>(item.handle.file_data)}; + uiLayoutSetContextPointer(col, "active_file", &file); + + PointerRNA library_ptr{&screen.id, + &RNA_AssetLibraryReference, + const_cast<AssetLibraryReference *>(&item.library_ref)}; + uiLayoutSetContextPointer(col, "asset_library_ref", &library_ptr); + + uiItemO(col, ED_asset_handle_get_name(&item.handle), ICON_NONE, "NODE_OT_add_group_asset"); + } + + catalog_item->foreach_child([&](bke::AssetCatalogTreeItem &child_item) { + const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(&child_item); + PointerRNA path_ptr{ + &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); + uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); + }); +} + +static void add_root_catalogs_draw(const bContext *C, Menu *menu) +{ + bScreen &screen = *CTX_wm_screen(C); + SpaceNode &snode = *CTX_wm_space_node(C); + const bNodeTree *edit_tree = snode.edittree; + uiLayout *layout = menu->layout; + + snode.runtime->assets_for_menu = std::make_shared<AssetItemTree>( + build_catalog_tree(*C, edit_tree)); + + const bool loading_finished = all_loading_finished(); + + AssetItemTree &tree = *snode.runtime->assets_for_menu; + if (tree.catalogs.is_empty() && loading_finished) { + return; + } + + uiItemS(layout); + + if (!loading_finished) { + uiItemL(layout, IFACE_("Loading Asset Libraries"), ICON_INFO); + } + + /* Avoid adding a separate root catalog when the assets have already been added to one of the + * builtin menus. + * TODO: The need to define the builtin menu labels here is completely non-ideal. We don't have + * any UI introspection that can do this though. This can be solved in the near future by + * removing the need to define the add menu completely, instead using a per-node-type path which + * can be merged with catalog tree. + */ + static Set<std::string> all_builtin_menus = []() { + Set<std::string> menus; + menus.add_new("Attribute"); + menus.add_new("Color"); + menus.add_new("Curve"); + menus.add_new("Curve Primitives"); + menus.add_new("Curve Topology"); + menus.add_new("Geometry"); + menus.add_new("Input"); + menus.add_new("Instances"); + menus.add_new("Material"); + menus.add_new("Mesh"); + menus.add_new("Mesh Primitives"); + menus.add_new("Mesh Topology"); + menus.add_new("Output"); + menus.add_new("Point"); + menus.add_new("Text"); + menus.add_new("Texture"); + menus.add_new("Utilities"); + menus.add_new("UV"); + menus.add_new("Vector"); + menus.add_new("Volume"); + menus.add_new("Group"); + menus.add_new("Layout"); + return menus; + }(); + + tree.catalogs.foreach_root_item([&](bke::AssetCatalogTreeItem &item) { + if (all_builtin_menus.contains(item.get_name())) { + return; + } + const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(&item); + PointerRNA path_ptr{ + &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); + uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); + }); +} + +MenuType add_catalog_assets_menu_type() +{ + MenuType type{}; + BLI_strncpy(type.idname, "NODE_MT_node_add_catalog_assets", sizeof(type.idname)); + type.poll = node_add_menu_poll; + type.draw = node_add_catalog_assets_draw; + type.listener = node_add_menu_assets_listen_fn; + return type; +} + +MenuType add_root_catalogs_menu_type() +{ + MenuType type{}; + BLI_strncpy(type.idname, "NODE_MT_node_add_root_catalogs", sizeof(type.idname)); + type.poll = node_add_menu_poll; + type.draw = add_root_catalogs_draw; + type.listener = node_add_menu_assets_listen_fn; + return type; +} + +} // namespace blender::ed::space_node + +/* Note: This is only necessary because Python can't set an asset catalog path context item. */ +void uiTemplateNodeAssetMenuItems(uiLayout *layout, bContext *C, const char *catalog_path) +{ + using namespace blender; + using namespace blender::ed::space_node; + bScreen &screen = *CTX_wm_screen(C); + SpaceNode &snode = *CTX_wm_space_node(C); + AssetItemTree &tree = *snode.runtime->assets_for_menu; + const bke::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path); + if (!item) { + return; + } + const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(item); + PointerRNA path_ptr{ + &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; + uiItemS(layout); + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); + uiItemMContents(col, "NODE_MT_node_add_catalog_assets"); +} diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 07eecff320a..41f70a6d8cf 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -30,6 +30,7 @@ #include "DEG_depsgraph_build.h" +#include "ED_asset.h" #include "ED_node.h" /* own include */ #include "ED_render.h" #include "ED_screen.h" @@ -244,38 +245,36 @@ void NODE_OT_add_reroute(wmOperatorType *ot) /** \name Add Node Group Operator * \{ */ -static bNodeTree *node_add_group_get_and_poll_group_node_tree(Main *bmain, - wmOperator *op, - bNodeTree *ntree) +static bool node_group_add_poll(const bNodeTree &node_tree, + const bNodeTree &node_group, + ReportList &reports) { - bNodeTree *node_group = reinterpret_cast<bNodeTree *>( - WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_NT)); - if (!node_group) { - return nullptr; + if (node_group.type != node_tree.type) { + return false; } const char *disabled_hint = nullptr; - if ((node_group->type != ntree->type) || !nodeGroupPoll(ntree, node_group, &disabled_hint)) { + if (!nodeGroupPoll(&node_tree, &node_group, &disabled_hint)) { if (disabled_hint) { - BKE_reportf(op->reports, + BKE_reportf(&reports, RPT_ERROR, "Can not add node group '%s' to '%s':\n %s", - node_group->id.name + 2, - ntree->id.name + 2, + node_group.id.name + 2, + node_tree.id.name + 2, disabled_hint); } else { - BKE_reportf(op->reports, + BKE_reportf(&reports, RPT_ERROR, "Can not add node group '%s' to '%s'", - node_group->id.name + 2, - ntree->id.name + 2); + node_group.id.name + 2, + node_tree.id.name + 2); } - return nullptr; + return false; } - return node_group; + return true; } static int node_add_group_exec(bContext *C, wmOperator *op) @@ -284,10 +283,14 @@ static int node_add_group_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNodeTree *node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree); + bNodeTree *node_group = reinterpret_cast<bNodeTree *>( + WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_NT)); if (!node_group) { return OPERATOR_CANCELLED; } + if (!node_group_add_poll(*ntree, *node_group, *op->reports)) { + return OPERATOR_CANCELLED; + } ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); @@ -320,9 +323,8 @@ static bool node_add_group_poll(bContext *C) } const SpaceNode *snode = CTX_wm_space_node(C); if (snode->edittree->type == NTREE_CUSTOM) { - CTX_wm_operator_poll_msg_set(C, - "This node editor displays a custom (Python defined) node tree. " - "Dropping node groups isn't supported for this"); + CTX_wm_operator_poll_msg_set( + C, "Adding node groups isn't supported for custom (Python defined) node trees"); return false; } return true; @@ -367,6 +369,105 @@ void NODE_OT_add_group(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Add Node Group Asset Operator + * \{ */ + +static bool add_node_group_asset(const bContext &C, + const AssetLibraryReference &library_ref, + const AssetHandle asset, + ReportList &reports) +{ + Main &bmain = *CTX_data_main(&C); + SpaceNode &snode = *CTX_wm_space_node(&C); + bNodeTree &edit_tree = *snode.edittree; + + bNodeTree *node_group = reinterpret_cast<bNodeTree *>( + asset::get_local_id_from_asset_or_append_and_reuse(bmain, library_ref, asset)); + if (!node_group) { + return false; + } + if (!node_group_add_poll(edit_tree, *node_group, reports)) { + /* Remove the node group if it was newly appended but can't be added to the tree. */ + id_us_plus(&node_group->id); + BKE_id_free_us(&bmain, node_group); + return false; + } + + ED_preview_kill_jobs(CTX_wm_manager(&C), CTX_data_main(&C)); + + bNode *group_node = add_node( + C, ntreeTypeFind(node_group->idname)->group_idname, snode.runtime->cursor); + if (!group_node) { + BKE_report(&reports, RPT_WARNING, "Could not add node group"); + return false; + } + /* By default, don't show the data-block selector since it's not usually necessary for assets. */ + group_node->flag &= ~NODE_OPTIONS; + + group_node->id = &node_group->id; + id_us_plus(group_node->id); + BKE_ntree_update_tag_node_property(&edit_tree, group_node); + + nodeSetActive(&edit_tree, group_node); + ED_node_tree_propagate_change(&C, &bmain, nullptr); + DEG_relations_tag_update(&bmain); + + return true; +} + +static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion ®ion = *CTX_wm_region(C); + SpaceNode &snode = *CTX_wm_space_node(C); + + const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C); + if (!library_ref) { + return OPERATOR_CANCELLED; + } + bool is_valid; + const AssetHandle handle = CTX_wm_asset_handle(C, &is_valid); + if (!is_valid) { + return OPERATOR_CANCELLED; + } + + /* Convert mouse coordinates to v2d space. */ + UI_view2d_region_to_view(®ion.v2d, + event->mval[0], + event->mval[1], + &snode.runtime->cursor[0], + &snode.runtime->cursor[1]); + + snode.runtime->cursor /= UI_DPI_FAC; + + if (!add_node_group_asset(*C, *library_ref, handle, *op->reports)) { + return OPERATOR_CANCELLED; + } + + wmOperatorType *ot = WM_operatortype_find("NODE_OT_translate_attach_remove_on_cancel", true); + BLI_assert(ot); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); + WM_operator_properties_free(&ptr); + + return OPERATOR_FINISHED; +} + +void NODE_OT_add_group_asset(wmOperatorType *ot) +{ + ot->name = "Add Node Group Asset"; + ot->description = "Add a node group asset to the active node tree"; + ot->idname = "NODE_OT_add_group_asset"; + + ot->invoke = node_add_group_asset_invoke; + ot->poll = node_add_group_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Add Node Object Operator * \{ */ @@ -393,7 +494,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op) bNodeSocket *sock = nodeFindSocket(object_node, SOCK_IN, "Object"); if (!sock) { - BKE_report(op->reports, RPT_WARNING, "Could not find node object socket"); + BLI_assert_unreachable(); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index ee9ebd541a0..5ae6573df7c 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -2145,6 +2145,9 @@ static void node_draw_basis(const bContext &C, 0, ""); UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit"); + if (node.id) { + UI_but_icon_indicator_number_set(but, ID_REAL_USERS(node.id)); + } UI_block_emboss_set(&block, UI_EMBOSS); } if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) { diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 1c3026628a6..88be9a52c61 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -38,6 +38,8 @@ extern const char *node_context_dir[]; namespace blender::ed::space_node { +struct AssetItemTree; + /** Temporary data used in node link drag modal operator. */ struct bNodeLinkDrag { /** Links dragged by the operator. */ @@ -96,6 +98,15 @@ struct SpaceNode_Runtime { /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */ /** Temporary data for node insert offset (in UI called Auto-offset). */ struct NodeInsertOfsData *iofsd; + + /** + * Temporary data for node add menu in order to provide longer-term storage for context pointers. + * Recreated every time the root menu is opened. In the future this will be replaced with an "all + * libraries" cache in the asset system itself. + * + * Stored with a shared pointer so that it can be forward declared. + */ + std::shared_ptr<AssetItemTree> assets_for_menu; }; enum NodeResizeDirection { @@ -253,6 +264,7 @@ bNode *add_static_node(const bContext &C, int type, const float2 &location); void NODE_OT_add_reroute(wmOperatorType *ot); void NODE_OT_add_search(wmOperatorType *ot); void NODE_OT_add_group(wmOperatorType *ot); +void NODE_OT_add_group_asset(wmOperatorType *ot); void NODE_OT_add_object(wmOperatorType *ot); void NODE_OT_add_collection(wmOperatorType *ot); void NODE_OT_add_file(wmOperatorType *ot); @@ -383,4 +395,9 @@ void invoke_node_link_drag_add_menu(bContext &C, void invoke_add_node_search_menu(bContext &C, const float2 &cursor, bool use_transform); +/* add_menu_assets.cc */ + +MenuType add_catalog_assets_menu_type(); +MenuType add_root_catalogs_menu_type(); + } // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index d45c33a3c59..104d1acf3b4 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -78,6 +78,7 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_add_search); WM_operatortype_append(NODE_OT_add_group); + WM_operatortype_append(NODE_OT_add_group_asset); WM_operatortype_append(NODE_OT_add_object); WM_operatortype_append(NODE_OT_add_collection); WM_operatortype_append(NODE_OT_add_file); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index b12afcb1faa..637c795d4d7 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -815,7 +815,8 @@ static void draw_draglink_tooltip(const bContext * /*C*/, ARegion * /*region*/, nldrag->cursor[0]; const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC; - UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false); + UI_icon_draw_ex( + x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } static void draw_draglink_tooltip_activate(const ARegion ®ion, bNodeLinkDrag &nldrag) diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index ac49115959c..5754e77399f 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -1170,5 +1170,8 @@ void ED_spacetype_node() art->draw = node_toolbar_region_draw; BLI_addhead(&st->regiontypes, art); + WM_menutype_add(MEM_new<MenuType>(__func__, add_catalog_assets_menu_type())); + WM_menutype_add(MEM_new<MenuType>(__func__, add_root_catalogs_menu_type())); + BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index e366c58349f..699dd6d4844 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -2877,7 +2877,8 @@ static bool tselem_draw_icon(uiBlock *block, TreeStoreElem *tselem, TreeElement *te, float alpha, - const bool is_clickable) + const bool is_clickable, + const int num_elements) { TreeElementIcon data = tree_element_get_icon(tselem, te); if (data.icon == 0) { @@ -2885,6 +2886,8 @@ static bool tselem_draw_icon(uiBlock *block, } const bool is_collection = outliner_is_collection_tree_element(te); + IconTextOverlay text_overlay; + UI_icon_text_overlay_init_from_count(&text_overlay, num_elements); /* Collection colors and icons covered by restrict buttons. */ if (!is_clickable || x >= xmax || is_collection) { @@ -2904,7 +2907,8 @@ static bool tselem_draw_icon(uiBlock *block, alpha, 0.0f, btheme->collection_color[collection->color_tag].color, - true); + true, + &text_overlay); return true; } } @@ -2915,10 +2919,10 @@ static bool tselem_draw_icon(uiBlock *block, /* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */ uchar color[4]; if (UI_icon_get_theme_color(data.icon, color)) { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true); + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true, &text_overlay); } else { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false); + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false, &text_overlay); } } else { @@ -2941,104 +2945,6 @@ static bool tselem_draw_icon(uiBlock *block, return true; } -static bool outliner_is_main_row(const ARegion *region, const int ys) -{ - int ystart; - - ystart = int(region->v2d.tot.ymax); - ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - return ((ys - ystart) / UI_UNIT_Y) % 2; -} - -/** - * Get the expected row background color to use for the data-block counter - * - * This reproduces some of the logic of outliner_draw_highlights. - * At the moment it doesn't implement the search match color since - * we don't draw the data-block counter in those cases. - */ -static void outliner_get_row_color(const ARegion *region, - const TreeElement *te, - int ys, - float r_color[4]) -{ - const TreeStoreElem *tselem = TREESTORE(te); - - if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) { - UI_GetThemeColor3fv(TH_ACTIVE, r_color); - } - else if (tselem->flag & TSE_SELECTED) { - UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, r_color); - } - else if (outliner_is_main_row(region, ys)) { - UI_GetThemeColor3fv(TH_BACK, r_color); - } - else { - float color_alternating[4]; - UI_GetThemeColor4fv(TH_ROW_ALTERNATE, color_alternating); - UI_GetThemeColorBlend3f(TH_BACK, TH_ROW_ALTERNATE, color_alternating[3], r_color); - } - - if (tselem->flag & TSE_HIGHLIGHTED) { - const float color_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; - interp_v3_v3v3(r_color, r_color, color_highlight, color_highlight[3]); - } - r_color[3] = 1.0f; -} - -/** - * For icon-only children of a collapsed tree, - * Draw small number over the icon to show how many items of this type are displayed. - */ -static void outliner_draw_iconrow_number(const ARegion *region, - const uiFontStyle *fstyle, - int offsx, - int ys, - const TreeElement *te_visible, - const int num_elements) -{ - float color[4]; - outliner_get_row_color(region, te_visible, ys, color); - - float ufac = 0.25f * UI_UNIT_X; - float offset_x = float(offsx) + UI_UNIT_X * 0.35f; - rctf rect{}; - BLI_rctf_init(&rect, - offset_x + ufac, - offset_x + UI_UNIT_X - ufac, - float(ys) - UI_UNIT_Y * 0.2f + ufac, - float(ys) - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac); - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_4fv_ex( - &rect, color, NULL, 1.0f, color, U.pixelsize, float(UI_UNIT_Y) / 2.0f - ufac); - - /* Now the numbers. */ - uchar text_col[4]; - - UI_GetThemeColor3ubv(TH_TEXT, text_col); - text_col[3] = 255; - - uiFontStyle fstyle_small = *fstyle; - fstyle_small.points *= 0.8f; - - /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */ - int num_digits = 4; - char number_text[4] = "+99"; - if (num_elements < 100) { - BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements); - num_digits = num_elements < 10 ? 1 : 2; - } - UI_fontstyle_draw_simple(&fstyle_small, - (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f), - float(ys) - UI_UNIT_Y * 0.095f + ufac, - number_text, - text_col); - UI_fontstyle_set(fstyle); - GPU_blend(GPU_BLEND_ALPHA); /* Round-box and text drawing disables. */ -} - static void outliner_icon_background_colors(float icon_color[4], float icon_border[4]) { float text[4]; @@ -3069,11 +2975,8 @@ static void outliner_draw_active_indicator(const float minx, GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */ } -static void outliner_draw_iconrow_doit(const ARegion *region, - uiBlock *block, - TreeElement *te_visible, +static void outliner_draw_iconrow_doit(uiBlock *block, TreeElement *te, - const uiFontStyle *fstyle, int xmax, int *offsx, int ys, @@ -3102,13 +3005,13 @@ static void outliner_draw_iconrow_doit(const ARegion *region, if (tselem->flag & TSE_HIGHLIGHTED_ICON) { alpha_fac += 0.5; } - tselem_draw_icon(block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false); + tselem_draw_icon( + block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements); te->xs = *offsx; te->ys = ys; te->xend = short(*offsx) + UI_UNIT_X; if (num_elements > 1) { - outliner_draw_iconrow_number(region, fstyle, *offsx, ys, te_visible, num_elements); te->flag |= TE_ICONROW_MERGED; } else { @@ -3145,16 +3048,15 @@ static void outliner_draw_iconrow(bContext *C, const uiFontStyle *fstyle, const TreeViewContext *tvc, SpaceOutliner *space_outliner, - TreeElement *te_visible, ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac, + bool in_bone_hierarchy, MergedIconRow *merged) { - const ARegion *region = CTX_wm_region(C); eOLDrawState active = OL_DRAWSEL_NONE; LISTBASE_FOREACH (TreeElement *, te, lb) { @@ -3162,8 +3064,12 @@ static void outliner_draw_iconrow(bContext *C, te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ + /* Bones are also hierarchies and get a merged count, but we only start recursing into them if + * an they are at the root level of a collapsed subtree (e.g. not "hidden" in a collapsed + * collection). */ + const bool is_bone = ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL); if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) || - ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)) { + (in_bone_hierarchy && is_bone)) { /* active blocks get white circle */ if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { @@ -3194,8 +3100,7 @@ static void outliner_draw_iconrow(bContext *C, TSE_POSE_CHANNEL, TSE_POSEGRP, TSE_DEFGROUP)) { - outliner_draw_iconrow_doit( - region, block, te_visible, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); + outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1); } else { const int index = tree_element_id_type_to_index(te); @@ -3207,20 +3112,25 @@ static void outliner_draw_iconrow(bContext *C, } } - /* this tree element always has same amount of branches, so don't draw */ - if (tselem->type != TSE_R_LAYER) { + /* TSE_R_LAYER tree element always has same amount of branches, so don't draw. */ + /* Also only recurse into bone hierarchies if a direct child of the collapsed element to merge + * into. */ + const bool is_root_level_bone = is_bone && (level == 0); + in_bone_hierarchy |= is_root_level_bone; + if (!ELEM(tselem->type, TSE_R_LAYER, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL) || + in_bone_hierarchy) { outliner_draw_iconrow(C, block, fstyle, tvc, space_outliner, - te, &te->subtree, level + 1, xmax, offsx, ys, alpha_fac, + in_bone_hierarchy, merged); } } @@ -3236,11 +3146,8 @@ static void outliner_draw_iconrow(bContext *C, for (int j = 0; j < num_subtypes; j++) { const int index = index_base + j; if (merged->num_elements[index] != 0) { - outliner_draw_iconrow_doit(region, - block, - te_visible, + outliner_draw_iconrow_doit(block, merged->tree_element[index], - fstyle, xmax, offsx, ys, @@ -3429,7 +3336,8 @@ static void outliner_draw_tree_element(bContext *C, tselem, te, (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac, - true)) { + true, + 1)) { offsx += UI_UNIT_X + 4 * ufac; } else { @@ -3478,13 +3386,13 @@ static void outliner_draw_tree_element(bContext *C, fstyle, tvc, space_outliner, - te, &te->subtree, 0, xmax, &tempx, *starty, alpha_fac, + false, &merged); GPU_blend(GPU_BLEND_NONE); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 8b6d37caa41..1d20926d16c 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -129,7 +129,6 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce region->regiontype = RGN_TYPE_TOOLS; region->alignment = RGN_ALIGN_LEFT; region->flag = RGN_FLAG_HIDDEN; - region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; /* Channels. */ region = MEM_callocN(sizeof(ARegion), "channels for sequencer"); @@ -137,6 +136,7 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce BLI_addtail(&sseq->regionbase, region); region->regiontype = RGN_TYPE_CHANNELS; region->alignment = RGN_ALIGN_LEFT; + region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; /* Preview region. */ /* NOTE: if you change values here, also change them in sequencer_init_preview_region. */ diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc index 635fbd75d74..05fb0c6a720 100644 --- a/source/blender/editors/space_view3d/space_view3d.cc +++ b/source/blender/editors/space_view3d/space_view3d.cc @@ -175,11 +175,11 @@ bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d) { /* local viewmat and persmat, to calculate projections */ - mul_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->obmat); - mul_m4_m4m4(rv3d->persmatob, rv3d->persmat, ob->obmat); + mul_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->object_to_world); + mul_m4_m4m4(rv3d->persmatob, rv3d->persmat, ob->object_to_world); /* initializes object space clipping, speeds up clip tests */ - ED_view3d_clipping_local(rv3d, ob->obmat); + ED_view3d_clipping_local(rv3d, ob->object_to_world); } void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *rv3d) @@ -189,7 +189,7 @@ void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *r /* We have to multiply instead of loading `viewmatob` to make * it work with duplis using display-lists, otherwise it will * override the dupli-matrix. */ - GPU_matrix_mul(ob->obmat); + GPU_matrix_mul(ob->object_to_world); } #ifdef DEBUG @@ -710,7 +710,7 @@ static void view3d_ob_drop_matrix_from_snap(V3DSnapCursorState *snap_state, copy_v3_v3(obmat_final[3], snap_data->loc); float scale[3]; - mat4_to_size(scale, ob->obmat); + mat4_to_size(scale, ob->object_to_world); rescale_m4(obmat_final, scale); const BoundBox *bb = BKE_object_boundbox_get(ob); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 4153f19f8be..83835535d49 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -474,7 +474,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float /* Location, X/Y/Z */ mul_v3_fl(median_basis.generic.location, 1.0f / (float)tot); if (v3d->flag & V3D_GLOBAL_STATS) { - mul_m4_v3(ob->obmat, median_basis.generic.location); + mul_m4_v3(ob->object_to_world, median_basis.generic.location); } if (has_meshdata) { @@ -954,7 +954,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float memcpy(&ve_median_basis, &tfp->ve_median, sizeof(tfp->ve_median)); if (v3d->flag & V3D_GLOBAL_STATS) { - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_v3(ob->imat, median_basis.generic.location); mul_m4_v3(ob->imat, ve_median_basis.generic.location); } @@ -1215,7 +1215,7 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d BKE_object_dimensions_get(ob, tfp->ob_dims); copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims); copy_v3_v3(tfp->ob_scale_orig, ob->scale); - copy_m4_m4(tfp->ob_obmat_orig, ob->obmat); + copy_m4_m4(tfp->ob_obmat_orig, ob->object_to_world); uiDefBut(block, UI_BTYPE_LABEL, diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index b5962647278..299c8638b02 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -142,7 +142,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph vctrl->obtfm = BKE_object_tfm_backup(ob_back); BKE_object_where_is_calc(depsgraph, scene, v3d->camera); - negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]); + negate_v3_v3(rv3d->ofs, v3d->camera->object_to_world[3]); rv3d->dist = 0.0; } @@ -251,7 +251,7 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, invert_m4_m4(prev_view_imat, vctrl->view_mat_prev); mul_m4_m4m4(diff_mat, view_mat, prev_view_imat); - mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->obmat); + mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->object_to_world); if (object_apply_mat4_with_protect(vctrl->root_parent, parent_mat, false, rv3d, view_mat)) { /* Calculate again since the view locking changes the matrix. */ diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index 8a86889f2d0..31b26ba4cda 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -2066,7 +2066,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, rv3d.persp = RV3D_CAMOB; - copy_m4_m4(rv3d.viewinv, v3d.camera->obmat); + copy_m4_m4(rv3d.viewinv, v3d.camera->object_to_world); normalize_m4(rv3d.viewinv); invert_m4_m4(rv3d.viewmat, rv3d.viewinv); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c index 4f73e2fada2..8a4301d1314 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -188,7 +188,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup bspline_group->handles[i].index = i; float mat[4][4]; - mul_m4_m4m4(mat, ob->obmat, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat); + mul_m4_m4m4(mat, ob->object_to_world, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat); copy_m4_m4(gz->matrix_space, mat); /* need to set property here for undo. TODO: would prefer to do this in _init. */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c index 952ef56710b..56a1f6212a0 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -85,7 +85,7 @@ static void WIDGETGROUP_camera_setup(const bContext *C, wmGizmoGroup *gzgroup) struct CameraWidgetGroup *cagzgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__); gzgroup->customdata = cagzgroup; - negate_v3_v3(dir, ob->obmat[2]); + negate_v3_v3(dir, ob->object_to_world[2]); /* dof distance */ { @@ -138,11 +138,11 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup) RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr); - negate_v3_v3(dir, ob->obmat[2]); + negate_v3_v3(dir, ob->object_to_world[2]); if ((ca->flag & CAM_SHOWLIMITS) && (v3d->gizmo_show_camera & V3D_GIZMO_SHOW_CAMERA_DOF_DIST)) { - WM_gizmo_set_matrix_location(cagzgroup->dop_dist, ob->obmat[3]); - WM_gizmo_set_matrix_rotation_from_yz_axis(cagzgroup->dop_dist, ob->obmat[1], dir); + WM_gizmo_set_matrix_location(cagzgroup->dop_dist, ob->object_to_world[3]); + WM_gizmo_set_matrix_rotation_from_yz_axis(cagzgroup->dop_dist, ob->object_to_world[1], dir); WM_gizmo_set_scale(cagzgroup->dop_dist, ca->drawsize); WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, false); @@ -183,17 +183,17 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup) aspect[1] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? aspy / aspx : 1.0f; unit_m4(widget->matrix_basis); - WM_gizmo_set_matrix_location(widget, ob->obmat[3]); - WM_gizmo_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir); + WM_gizmo_set_matrix_location(widget, ob->object_to_world[3]); + WM_gizmo_set_matrix_rotation_from_yz_axis(widget, ob->object_to_world[1], dir); if (is_ortho) { scale_matrix = ca->ortho_scale * 0.5f; } else { const float ob_scale_inv[3] = { - 1.0f / len_v3(ob->obmat[0]), - 1.0f / len_v3(ob->obmat[1]), - 1.0f / len_v3(ob->obmat[2]), + 1.0f / len_v3(ob->object_to_world[0]), + 1.0f / len_v3(ob->object_to_world[1]), + 1.0f / len_v3(ob->object_to_world[2]), }; const float ob_scale_uniform_inv = (ob_scale_inv[0] + ob_scale_inv[1] + ob_scale_inv[2]) / 3.0f; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c index 41a763192ce..03fc7328e39 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_empty.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c @@ -139,7 +139,7 @@ static void WIDGETGROUP_empty_image_refresh(const bContext *C, wmGizmoGroup *gzg BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); - copy_m4_m4(gz->matrix_basis, ob->obmat); + copy_m4_m4(gz->matrix_basis, ob->object_to_world); RNA_enum_set(gz->ptr, "transform", diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c index 58b43301397..d194e2a6279 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c @@ -87,8 +87,8 @@ static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmGizmoGroup *gzgr PointerRNA field_ptr; RNA_pointer_create(&ob->id, &RNA_FieldSettings, pd, &field_ptr); - WM_gizmo_set_matrix_location(gz, ob->obmat[3]); - WM_gizmo_set_matrix_rotation_from_z_axis(gz, ob->obmat[2]); + WM_gizmo_set_matrix_location(gz, ob->object_to_world[3]); + WM_gizmo_set_matrix_rotation_from_z_axis(gz, ob->object_to_world[2]); WM_gizmo_set_matrix_offset_location(gz, ofs); WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); WM_gizmo_target_property_def_rna(gz, "offset", &field_ptr, "strength", -1); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_light.c b/source/blender/editors/space_view3d/view3d_gizmo_light.c index 4401dbf7935..0b115bc0604 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_light.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_light.c @@ -85,10 +85,10 @@ static void WIDGETGROUP_light_spot_refresh(const bContext *C, wmGizmoGroup *gzgr Light *la = ob->data; float dir[3]; - negate_v3_v3(dir, ob->obmat[2]); + negate_v3_v3(dir, ob->object_to_world[2]); WM_gizmo_set_matrix_rotation_from_z_axis(gz, dir); - WM_gizmo_set_matrix_location(gz, ob->obmat[3]); + WM_gizmo_set_matrix_location(gz, ob->object_to_world[3]); /* need to set property here for undo. TODO: would prefer to do this in _init. */ PointerRNA lamp_ptr; @@ -199,7 +199,7 @@ static void WIDGETGROUP_light_area_refresh(const bContext *C, wmGizmoGroup *gzgr Light *la = ob->data; wmGizmo *gz = wwrapper->gizmo; - copy_m4_m4(gz->matrix_basis, ob->obmat); + copy_m4_m4(gz->matrix_basis, ob->object_to_world); int flag = ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE; if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) { @@ -296,7 +296,7 @@ static void WIDGETGROUP_light_target_draw_prepare(const bContext *C, wmGizmoGrou Object *ob = BKE_view_layer_active_object_get(view_layer); wmGizmo *gz = wwrapper->gizmo; - normalize_m4_m4(gz->matrix_basis, ob->obmat); + normalize_m4_m4(gz->matrix_basis, ob->object_to_world); unit_m4(gz->matrix_offset); if (ob->type == OB_LAMP) { diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc index 793ada4f577..86aecfb6c34 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc @@ -97,7 +97,7 @@ static void gizmo_preselect_elem_draw(const bContext *C, wmGizmo *gz) MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; if (gz_ele->base_index != -1) { Object *ob = gz_ele->bases[gz_ele->base_index]->object; - EDBM_preselect_elem_draw(gz_ele->psel, ob->obmat); + EDBM_preselect_elem_draw(gz_ele->psel, ob->object_to_world); } } @@ -185,7 +185,7 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int BMVert *vert = (BMVert *)eve_test; float vert_p_co[2], vert_co[3]; const float mval_f[2] = {float(vc.mval[0]), float(vc.mval[1])}; - mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->obmat, vert->co); + mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->object_to_world, vert->co); ED_view3d_project_v2(vc.region, vert_co, vert_p_co); float len = len_v2v2(vert_p_co, mval_f); if (len < 35) { @@ -330,7 +330,7 @@ static void gizmo_preselect_edgering_draw(const bContext *C, wmGizmo *gz) MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; if (gz_ring->base_index != -1) { Object *ob = gz_ring->bases[gz_ring->base_index]->object; - EDBM_preselect_edgering_draw(gz_ring->psel, ob->obmat); + EDBM_preselect_edgering_draw(gz_ring->psel, ob->object_to_world); } } diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc index 932563863fe..aaa817ec00c 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.cc +++ b/source/blender/editors/space_view3d/view3d_iterators.cc @@ -307,7 +307,7 @@ void meshobject_foreachScreenVert( &me->vdata, CD_PROP_BOOL, ".hide_vert"); if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat); + ED_view3d_clipping_local(vc->rv3d, vc->obact->object_to_world); } BKE_mesh_foreach_mapped_vert(me, meshobject_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP); @@ -353,7 +353,8 @@ void mesh_foreachScreenVert( data.clip_flag = clip_flag; if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups */ } BM_mesh_elem_table_ensure(vc->em->bm, BM_VERT); @@ -422,7 +423,8 @@ void mesh_foreachScreenEdge(ViewContext *vc, data.clip_flag = clip_flag; if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups */ } if (clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) { @@ -520,7 +522,8 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc, BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE); if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != nullptr)) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups. */ BKE_mesh_foreach_mapped_edge( me, vc->em->bm->totedge, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data); } @@ -612,7 +615,8 @@ void nurbs_foreachScreenVert(ViewContext *vc, ED_view3d_check_mats_rv3d(vc->rv3d); if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, + vc->obedit->object_to_world); /* for local clipping lookups */ } LISTBASE_FOREACH (Nurb *, nu, nurbs) { @@ -732,7 +736,7 @@ void lattice_foreachScreenVert(ViewContext *vc, ED_view3d_check_mats_rv3d(vc->rv3d); if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { - ED_view3d_clipping_local(vc->rv3d, obedit->obmat); /* for local clipping lookups */ + ED_view3d_clipping_local(vc->rv3d, obedit->object_to_world); /* for local clipping lookups */ } for (i = 0; i < N; i++, bp++, co += 3) { diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c index 25073d02a7f..7d2beecd9a3 100644 --- a/source/blender/editors/space_view3d/view3d_navigate.c +++ b/source/blender/editors/space_view3d/view3d_navigate.c @@ -185,7 +185,7 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) copy_v3_v3(lastofs, stroke); } else { - copy_v3_v3(lastofs, ob_act_eval->obmat[3]); + copy_v3_v3(lastofs, ob_act_eval->object_to_world[3]); } is_set = true; } @@ -199,7 +199,7 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) } mul_v2_fl(lastofs, 1.0f / 4.0f); - mul_m4_v3(ob_act_eval->obmat, lastofs); + mul_m4_v3(ob_act_eval->object_to_world, lastofs); is_set = true; } @@ -219,11 +219,11 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) BKE_boundbox_calc_center_aabb(ob_eval->runtime.bb, cent); - mul_m4_v3(ob_eval->obmat, cent); + mul_m4_v3(ob_eval->object_to_world, cent); add_v3_v3(select_center, cent); } else { - add_v3_v3(select_center, ob_eval->obmat[3]); + add_v3_v3(select_center, ob_eval->object_to_world[3]); } tot++; } @@ -626,7 +626,7 @@ static void view3d_object_calc_minmax(Depsgraph *depsgraph, if (BKE_object_minmax_dupli(depsgraph, scene, ob_eval, min, max, false) == 0) { /* Use if duplis aren't found. */ if (only_center) { - minmax_v3v3_v3(min, max, ob_eval->obmat[3]); + minmax_v3v3_v3(min, max, ob_eval->object_to_world[3]); } else { BKE_object_minmax(ob_eval, min, max, false); @@ -934,8 +934,8 @@ static int viewselected_exec(bContext *C, wmOperator *op) CTX_DATA_END; if ((ob_eval) && (ok)) { - mul_m4_v3(ob_eval->obmat, min); - mul_m4_v3(ob_eval->obmat, max); + mul_m4_v3(ob_eval->object_to_world, min); + mul_m4_v3(ob_eval->object_to_world, max); } } else if (is_face_map) { diff --git a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c index 6b150d1e771..a5eee436fdb 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_smoothview.c +++ b/source/blender/editors/space_view3d/view3d_navigate_smoothview.c @@ -259,7 +259,7 @@ void ED_view3d_smooth_view_ex( Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); if (sview->ofs != NULL) { sms.dst.dist = ED_view3d_offset_distance( - ob_camera_eval->obmat, sview->ofs, VIEW3D_DIST_FALLBACK); + ob_camera_eval->object_to_world, sview->ofs, VIEW3D_DIST_FALLBACK); } ED_view3d_from_object(ob_camera_eval, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens); sms.to_camera = true; /* restore view3d values in end */ @@ -282,7 +282,8 @@ void ED_view3d_smooth_view_ex( if (sview->camera_old) { Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old); if (sview->ofs != NULL) { - sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f); + sms.src.dist = ED_view3d_offset_distance( + ob_camera_old_eval->object_to_world, sview->ofs, 0.0f); } ED_view3d_from_object( ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens); diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c index 3e0ce892b5a..fcb4f549353 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_walk.c +++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c @@ -849,11 +849,15 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event) if (ret) { WalkTeleport *teleport = &walk->teleport; + + /* Store the current navigation mode if we are not already teleporting. */ + if (teleport->state == WALK_TELEPORT_STATE_OFF) { + teleport->navigation_mode = walk->navigation_mode; + } teleport->state = WALK_TELEPORT_STATE_ON; teleport->initial_time = PIL_check_seconds_timer(); teleport->duration = U.walk_navigation.teleport_time; - teleport->navigation_mode = walk->navigation_mode; walk_navigation_mode_set(walk, WALK_MODE_FREE); copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]); @@ -864,9 +868,7 @@ static void walkEvent(WalkInfo *walk, const wmEvent *event) sub_v3_v3v3(teleport->direction, loc, teleport->origin); } - else { - walk->teleport.state = WALK_TELEPORT_STATE_OFF; - } + break; } @@ -1229,11 +1231,11 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) /* keep moving if we were moving */ copy_v2_v2(dvec, walk->teleport.direction); - z_cur = walk->rv3d->viewinv[3][2]; - z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid; + z_cur = walk->rv3d->viewinv[3][2] / walk->grid; + z_new = (walk->teleport.origin[2] / walk->grid) - getFreeFallDistance(walk->gravity, t); /* jump */ - z_new += t * walk->speed_jump * walk->grid; + z_new += t * walk->speed_jump; /* duration is the jump duration */ if (t > walk->teleport.duration) { diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index c5f951bd64c..2718f14c855 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -80,7 +80,7 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, float r_co[2]) { eV3DProjStatus ret = ED_view3d_project_float_global( - region, base->object->obmat[3], r_co, V3D_PROJ_TEST_CLIP_DEFAULT); + region, base->object->object_to_world[3], r_co, V3D_PROJ_TEST_CLIP_DEFAULT); /* Prevent uninitialized values when projection fails, * although the callers should check the return value. */ @@ -687,7 +687,7 @@ void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob, fl { float vmat[4][4]; - mul_m4_m4m4(vmat, rv3d->viewmat, ob->obmat); + mul_m4_m4m4(vmat, rv3d->viewmat, ob->object_to_world); mul_m4_m4m4(r_pmat, rv3d->winmat, vmat); } diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index cba85097071..9c450e85d23 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -2303,7 +2303,7 @@ static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const if (BASE_SELECTABLE(v3d, base)) { float screen_co[2]; if (ED_view3d_project_float_global( - region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == + region, base->object->object_to_world[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) { float dist_test = len_manhattan_v2v2(mval_fl, screen_co); if (base == oldbasact) { @@ -2704,7 +2704,10 @@ static bool ed_object_select_pick(bContext *C, /* When there is no `baseact` this will have operated on `oldbasact`, * allowing #SelectPick_Params.deselect_all work in pose-mode. * In this case no object operations are needed. */ - if (basact != nullptr) { + if (basact == nullptr) { + handled = true; + } + else { /* By convention the armature-object is selected when in pose-mode. * While leaving it unselected will work, leaving pose-mode would leave the object * active + unselected which isn't ideal when performing other actions on the object. */ @@ -4725,9 +4728,10 @@ static bool object_circle_select(ViewContext *vc, LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) { if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) { float screen_co[2]; - if (ED_view3d_project_float_global( - vc->region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == - V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_global(vc->region, + base->object->object_to_world[3], + screen_co, + V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) { if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); changed = true; diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index ee6b1886dc2..f2b952c4f46 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -86,18 +86,18 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) } if (tvs.transverts_tot != 0) { - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); invert_m3_m3(imat, bmat); tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit->obmat[3]); + add_v3_v3(vec, obedit->object_to_world[3]); vec[0] = gridf * floorf(0.5f + vec[0] / gridf); vec[1] = gridf * floorf(0.5f + vec[1] / gridf); vec[2] = gridf * floorf(0.5f + vec[2] / gridf); - sub_v3_v3(vec, obedit->obmat[3]); + sub_v3_v3(vec, obedit->object_to_world[3]); mul_m3_v3(imat, vec); copy_v3_v3(tv->loc, vec); @@ -118,7 +118,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) bPoseChannel *pchan_eval; bArmature *arm_eval = ob_eval->data; - invert_m4_m4(ob_eval->imat, ob_eval->obmat); + invert_m4_m4(ob_eval->imat, ob_eval->object_to_world); for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) { if (pchan_eval->bone->flag & BONE_SELECTED) { @@ -129,7 +129,7 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) /* get nearest grid point to snap to */ copy_v3_v3(nLoc, pchan_eval->pose_mat[3]); /* We must operate in world space! */ - mul_m4_v3(ob_eval->obmat, nLoc); + mul_m4_v3(ob_eval->object_to_world, nLoc); vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf); vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf); vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf); @@ -214,9 +214,12 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) for (int ob_index = 0; ob_index < objects_eval_len; ob_index++) { Object *ob_eval = objects_eval[ob_index]; Object *ob = DEG_get_original_object(ob_eval); - vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf); - vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf); - vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf); + vec[0] = -ob_eval->object_to_world[3][0] + + gridf * floorf(0.5f + ob_eval->object_to_world[3][0] / gridf); + vec[1] = -ob_eval->object_to_world[3][1] + + gridf * floorf(0.5f + ob_eval->object_to_world[3][1] / gridf); + vec[2] = -ob_eval->object_to_world[3][2] + + gridf * floorf(0.5f + ob_eval->object_to_world[3][2] / gridf); if (ob->parent) { float originmat[3][3]; @@ -343,11 +346,11 @@ static bool snap_selected_to_location(bContext *C, } if (tvs.transverts_tot != 0) { - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); invert_m3_m3(imat, bmat); /* get the cursor in object space */ - sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); + sub_v3_v3v3(snap_target_local, snap_target_global, obedit->object_to_world[3]); mul_m3_v3(imat, snap_target_local); if (use_offset) { @@ -384,7 +387,7 @@ static bool snap_selected_to_location(bContext *C, bArmature *arm = ob->data; float snap_target_local[3]; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_v3_m4v3(snap_target_local, ob->imat, snap_target_global); for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -409,7 +412,7 @@ static bool snap_selected_to_location(bContext *C, float cursor_pose[3]; if (use_offset) { - mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]); + mul_v3_m4v3(cursor_pose, ob->object_to_world, pchan->pose_mat[3]); add_v3_v3(cursor_pose, offset_global); mul_m4_v3(ob->imat, cursor_pose); @@ -510,13 +513,13 @@ static bool snap_selected_to_location(bContext *C, float cursor_parent[3]; /* parent-relative */ if (use_offset) { - add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); + add_v3_v3v3(cursor_parent, ob->object_to_world[3], offset_global); } else { copy_v3_v3(cursor_parent, snap_target_global); } - sub_v3_v3(cursor_parent, ob->obmat[3]); + sub_v3_v3(cursor_parent, ob->object_to_world[3]); if (ob->parent) { float originmat[3][3], parentmat[4][4]; @@ -730,7 +733,7 @@ static void bundle_midpoint(Scene *scene, Object *ob, float r_vec[3]) tracking = &clip->tracking; - copy_m4_m4(cammat, ob->obmat); + copy_m4_m4(cammat, ob->object_to_world); BKE_tracking_get_camera_object_matrix(ob, mat); @@ -809,13 +812,13 @@ static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_curs count += tvs.transverts_tot; if (tvs.transverts_tot != 0) { Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - copy_m3_m4(bmat, obedit_eval->obmat); + copy_m3_m4(bmat, obedit_eval->object_to_world); tv = tvs.transverts; for (int i = 0; i < tvs.transverts_tot; i++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit_eval->obmat[3]); + add_v3_v3(vec, obedit_eval->object_to_world[3]); add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); } @@ -835,7 +838,7 @@ static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_curs if (arm->layer & pchan->bone->layer) { if (pchan->bone->flag & BONE_SELECTED) { copy_v3_v3(vec, pchan->pose_head); - mul_m4_v3(obact_eval->obmat, vec); + mul_m4_v3(obact_eval->object_to_world, vec); add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); count++; @@ -845,7 +848,7 @@ static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_curs } else { FOREACH_SELECTED_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) { - copy_v3_v3(vec, ob_eval->obmat[3]); + copy_v3_v3(vec, ob_eval->object_to_world[3]); /* special case for camera -- snap to bundles */ if (ob_eval->type == OB_CAMERA) { @@ -1008,7 +1011,7 @@ bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3]) float ob_min[3], ob_max[3]; bool changed; - changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT); + changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->object_to_world, SELECT); if (changed) { minmax_v3v3_v3(r_min, r_max, ob_min); minmax_v3v3_v3(r_min, r_max, ob_max); @@ -1024,13 +1027,13 @@ bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3]) return false; } - copy_m3_m4(bmat, obedit->obmat); + copy_m3_m4(bmat, obedit->object_to_world); tv = tvs.transverts; for (int a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc); mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit->obmat[3]); + add_v3_v3(vec, obedit->object_to_world[3]); add_v3_v3(centroid, vec); minmax_v3v3_v3(r_min, r_max, vec); } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 1fc16939f3f..fc26e6b4a06 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -281,7 +281,7 @@ void ED_view3d_clipping_calc( /* optionally transform to object space */ if (ob) { float imat[4][4]; - invert_m4_m4(imat, ob->obmat); + invert_m4_m4(imat, ob->object_to_world); for (int val = 0; val < 8; val++) { mul_m4_v3(imat, bb->vec[val]); @@ -291,7 +291,7 @@ void ED_view3d_clipping_calc( /* verify if we have negative scale. doing the transform before cross * product flips the sign of the vector compared to doing cross product * before transform then, so we correct for that. */ - int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; + int flip_sign = (ob) ? is_negative_m4(ob->object_to_world) : false; ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); } @@ -466,7 +466,8 @@ void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, if (v3d->camera) { Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); - rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + rv3d->dist = ED_view3d_offset_distance( + ob_camera_eval->object_to_world, rv3d->ofs, VIEW3D_DIST_FALLBACK); ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); } @@ -558,7 +559,7 @@ void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, if (calc_dist) { /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ rv3d->dist = ED_view3d_offset_distance( - ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + ob_camera_eval->object_to_world, rv3d->ofs, VIEW3D_DIST_FALLBACK); } ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); } @@ -592,12 +593,12 @@ bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionV ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); - normalize_m4_m4(tmat, ob_camera_eval->obmat); + normalize_m4_m4(tmat, ob_camera_eval->object_to_world); invert_m4_m4(imat, tmat); mul_m4_m4m4(diff_mat, view_mat, imat); - mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->obmat); + mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->object_to_world); BKE_object_tfm_protected_backup(root_parent, &obtfm); BKE_object_apply_mat4(root_parent, parent_mat, true, false); @@ -1508,7 +1509,7 @@ void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], c void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens) { - ED_view3d_from_m4(ob->obmat, ofs, quat, dist); + ED_view3d_from_m4(ob->object_to_world, ofs, quat, dist); if (lens) { CameraParams params; @@ -1555,7 +1556,7 @@ static bool view3d_camera_to_view_selected_impl(struct Main *bmain, is_ortho_camera = true; } - copy_m4_m4(obmat_new, camera_ob_eval->obmat); + copy_m4_m4(obmat_new, camera_ob_eval->object_to_world); copy_v3_v3(obmat_new[3], co); /* only touch location */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index d0db4de0c47..c630a1a5653 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -365,7 +365,7 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) rv3d->view = RV3D_VIEW_USER; /* don't show the grid */ - normalize_m4_m4(bmat, ob->obmat); + normalize_m4_m4(bmat, ob->object_to_world); invert_m4_m4(rv3d->viewmat, bmat); /* view quat calculation, needed for add object */ @@ -404,12 +404,12 @@ void view3d_viewmatrix_set(Depsgraph *depsgraph, Object *ob_eval = DEG_get_evaluated_object(depsgraph, v3d->ob_center); float vec[3]; - copy_v3_v3(vec, ob_eval->obmat[3]); + copy_v3_v3(vec, ob_eval->object_to_world[3]); if (ob_eval->type == OB_ARMATURE && v3d->ob_center_bone[0]) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob_eval->pose, v3d->ob_center_bone); if (pchan) { copy_v3_v3(vec, pchan->pose_mat[3]); - mul_m4_v3(ob_eval->obmat, vec); + mul_m4_v3(ob_eval->object_to_world, vec); } } translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 34e5b78c48f..ad6ab625438 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1594,9 +1594,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_enum_set(op->ptr, "snap_target", t->tsnap.source_select); eSnapTargetSelect target = t->tsnap.target_select; - RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) != 0); - RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) != 0); - RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) != 0); + RNA_boolean_set(op->ptr, "use_snap_self", (target & SCE_SNAP_TARGET_NOT_ACTIVE) == 0); + RNA_boolean_set(op->ptr, "use_snap_edit", (target & SCE_SNAP_TARGET_NOT_EDITED) == 0); + RNA_boolean_set(op->ptr, "use_snap_nonedit", (target & SCE_SNAP_TARGET_NOT_NONEDITED) == 0); RNA_boolean_set( op->ptr, "use_snap_selectable", (target & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0); } @@ -1721,13 +1721,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } -static void initSnapSpatial(TransInfo *t, float r_snap[2], float r_snap_y[2]) +static void initSnapSpatial(TransInfo *t, float r_snap[3], float *r_snap_precision) { + /* Default values. */ + r_snap[0] = r_snap[1] = 1.0f; + r_snap[2] = 0.0f; + *r_snap_precision = 0.1f; + if (t->spacetype == SPACE_VIEW3D) { if (t->region->regiondata) { View3D *v3d = t->area->spacedata.first; - r_snap[0] = ED_view3d_grid_view_scale(t->scene, v3d, t->region, NULL) * 1.0f; - r_snap[1] = r_snap[0] * 0.1f; + r_snap[0] = r_snap[1] = r_snap[2] = ED_view3d_grid_view_scale( + t->scene, v3d, t->region, NULL); } } else if (t->spacetype == SPACE_IMAGE) { @@ -1741,24 +1746,16 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2], float r_snap_y[2]) ED_space_image_grid_steps(sima, grid_steps_x, grid_steps_y, grid_size); /* Snapping value based on what type of grid is used (adaptive-subdividing or custom-grid). */ r_snap[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_x, zoom_factor); - r_snap[1] = r_snap[0] / 2.0f; - r_snap_y[0] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); - r_snap_y[1] = r_snap_y[0] / 2.0f; + r_snap[1] = ED_space_image_increment_snap_value(grid_size, grid_steps_y, zoom_factor); + *r_snap_precision = 0.5f; } else if (t->spacetype == SPACE_CLIP) { - r_snap[0] = 0.125f; - r_snap[1] = 0.0625f; + r_snap[0] = r_snap[1] = 0.125f; + *r_snap_precision = 0.5f; } else if (t->spacetype == SPACE_NODE) { r_snap[0] = r_snap[1] = ED_node_grid_size(); } - else if (t->spacetype == SPACE_GRAPH) { - r_snap[0] = 1.0; - r_snap[1] = 0.1f; - } - else { - r_snap[0] = r_snap[1] = 1.0f; - } } bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode) @@ -1898,7 +1895,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve initSnapping(t, op); /* Initialize snapping data AFTER mode flags */ - initSnapSpatial(t, t->snap_spatial_x, t->snap_spatial_y); + initSnapSpatial(t, t->snap_spatial, &t->snap_spatial_precision); /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. * will be removed (ton) */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 95686f12fe2..1e260ecd292 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -469,7 +469,8 @@ typedef struct TransDataContainer { /** * Store matrix, this avoids having to have duplicate check all over - * Typically: 'obedit->obmat' or 'poseobj->obmat', but may be used elsewhere too. + * Typically: 'obedit->object_to_world' or 'poseobj->object_to_world', but may be used elsewhere + * too. */ bool use_local_mat; @@ -555,9 +556,12 @@ typedef struct TransInfo { /** Snapping Gears. */ float snap[2]; /** Spatial snapping gears(even when rotating, scaling... etc). */ - float snap_spatial_x[2]; - /** Spatial snapping in the Y coordinate, for non-uniform grid in UV Editor. */ - float snap_spatial_y[2]; + float snap_spatial[3]; + /** + * Precision factor that is multiplied to snap_spatial when precision + * modifier is enabled for snap to grid or incremental snap. + */ + float snap_spatial_precision; /** Mouse side of the current frame, 'L', 'R' or 'B' */ char frame_side; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index fa56456d8e7..7abf0e5c00c 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -404,9 +404,11 @@ static void applyAxisConstraintVec(const TransInfo *t, } } + /* Fallback for when axes are aligned. */ + mul_m3_v3(t->con.pmtx, out); + if (is_snap_to_point) { - /* With snap points, a projection is alright, no adjustments needed. */ - mul_m3_v3(t->con.pmtx, out); + /* Pass. With snap points, a projection is alright, no adjustments needed. */ } else { const int dims = getConstraintSpaceDimension(t); @@ -422,14 +424,9 @@ static void applyAxisConstraintVec(const TransInfo *t, /* Disabled, as it has not proven to be really useful. (See T82386). */ // constraint_snap_plane_to_face(t, plane, out); } - else { + else if (!isPlaneProjectionViewAligned(t, plane)) { /* View alignment correction. */ - if (!isPlaneProjectionViewAligned(t, plane)) { - planeProjection(t, plane, in, out); - } - else { - mul_m3_v3(t->con.pmtx, out); - } + planeProjection(t, plane, in, out); } } } diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 7a68ee1bfbf..a5b2442f11c 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -981,7 +981,7 @@ static void init_TransDataContainers(TransInfo *t, if (tc->use_local_mat) { BLI_assert((t->flag & T_2D_EDIT) == 0); - copy_m4_m4(tc->mat, objects[i]->obmat); + copy_m4_m4(tc->mat, objects[i]->object_to_world); copy_m3_m4(tc->mat3, tc->mat); /* for non-invertible scale matrices, invert_m4_m4_fallback() * can still provide a valid pivot */ @@ -1235,8 +1235,8 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc) if (mmd->mirror_ob) { float obinv[4][4]; - invert_m4_m4(obinv, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, obinv, ob->obmat); + invert_m4_m4(obinv, mmd->mirror_ob->object_to_world); + mul_m4_m4m4(mtx, obinv, ob->object_to_world); invert_m4_m4(imtx, mtx); } diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 8466fd88e1d..4798d666d70 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -226,8 +226,6 @@ void transform_convert_mesh_crazyspace_transdata_set(const float mtx[3][3], struct TransData *r_td); void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_crazyspace_data); -void special_aftertrans_update__mesh(bContext *C, TransInfo *t); - /* transform_convert_mesh_edge.c */ extern TransConvertTypeInfo TransConvertType_MeshEdge; diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 4b79625fa66..2e37f6b7c34 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -306,8 +306,9 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) * just make things obey standard rotation locks too */ if (data->rootbone == 0) { for (bPoseChannel *pchan_iter = pchan; pchan_iter; pchan_iter = pchan_iter->parent) { - /* here, we set ik-settings for bone from pchan->protectflag */ - /* XXX: careful with quats/axis-angle rotations where we're locking 4d components. */ + /* Here, we set IK-settings for bone from `pchan->protectflag`. */ + /* XXX: careful with quaternion/axis-angle rotations + * where we're locking 4d components. */ if (pchan_iter->protectflag & OB_LOCK_ROTX) { pchan_iter->ikflag |= BONE_IK_NO_XDOF_TEMP; } @@ -592,7 +593,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr td->ext->rotOrder = pchan->rotmode; /* proper way to get parent transform + own transform + constraints transform */ - copy_m3_m4(omat, ob->obmat); + copy_m3_m4(omat, ob->object_to_world); /* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */ { @@ -954,7 +955,7 @@ static void createTransArmatureVerts(bContext *UNUSED(C), TransInfo *t) bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0); BoneInitData *bid = tc->custom.type.data; - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone"); diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 404b1293208..13ba28ec3d0 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -174,7 +174,7 @@ static void createTransCurveVerts(bContext *UNUSED(C), TransInfo *t) transform_mode_use_local_origins(t)); float mtx[3][3], smtx[3][3]; - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); TransData *td = tc->data; diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c index b77538dc249..e9b3401974b 100644 --- a/source/blender/editors/transform/transform_convert_lattice.c +++ b/source/blender/editors/transform/transform_convert_lattice.c @@ -66,7 +66,7 @@ static void createTransLatticeVerts(bContext *UNUSED(C), TransInfo *t) } tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)"); - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); td = tc->data; diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c index 7ae93524d0b..c90052e9e8c 100644 --- a/source/blender/editors/transform/transform_convert_mball.c +++ b/source/blender/editors/transform/transform_convert_mball.c @@ -61,7 +61,7 @@ static void createTransMBallVerts(bContext *UNUSED(C), TransInfo *t) tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "MetaElement_TransExtension"); - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); for (ml = mb->editelems->first; ml; ml = ml->next) { diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index af7982f862a..3192b1b6786 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1527,7 +1527,7 @@ static void createTransEditVerts(bContext *UNUSED(C), TransInfo *t) em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); /* we use a pseudo-inverse so that when one of the axes is scaled to 0, * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); @@ -2068,7 +2068,7 @@ static void recalcData_mesh(TransInfo *t) /** \name Special After Transform Mesh * \{ */ -void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) +static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) { const bool is_canceling = (t->state == TRANS_CANCEL); const bool use_automerge = !is_canceling && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c index 7f26029850b..fd62b199345 100644 --- a/source/blender/editors/transform/transform_convert_mesh_edge.c +++ b/source/blender/editors/transform/transform_convert_mesh_edge.c @@ -62,7 +62,7 @@ static void createTransEdge(bContext *UNUSED(C), TransInfo *t) td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease"); - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); /* create data we need */ @@ -125,5 +125,5 @@ TransConvertTypeInfo TransConvertType_MeshEdge = { /* flags */ T_EDIT, /* createTransData */ createTransEdge, /* recalcData */ recalcData_mesh_edge, - /* special_aftertrans_update */ special_aftertrans_update__mesh, + /* special_aftertrans_update */ NULL, }; diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c index 376e559181e..cb6108a4c45 100644 --- a/source/blender/editors/transform/transform_convert_mesh_skin.c +++ b/source/blender/editors/transform/transform_convert_mesh_skin.c @@ -130,7 +130,7 @@ static void createTransMeshSkin(bContext *UNUSED(C), TransInfo *t) em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); /* we use a pseudo-inverse so that when one of the axes is scaled to 0, * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); diff --git a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c index 59836180166..d253261f458 100644 --- a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c +++ b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c @@ -131,7 +131,7 @@ static void createTransMeshVertCData(bContext *UNUSED(C), TransInfo *t) em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data); } - copy_m3_m4(mtx, tc->obedit->obmat); + copy_m3_m4(mtx, tc->obedit->object_to_world); /* we use a pseudo-inverse so that when one of the axes is scaled to 0, * matrix inversion still works and we can still moving along the other */ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index af5a51cbff6..830094ebe83 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -60,9 +60,9 @@ typedef struct TransDataNla { * \{ */ /** - * \brief Applies a translation to the given NlaStrip. - * \param strip_rna_ptr The RNA pointer of the NLA strip to modify. - * \param transdata The transformation info structure. + * \brief Applies a translation to the given #NlaStrip. + * \param strip_rna_ptr: The RNA pointer of the NLA strip to modify. + * \param transdata: The transformation info structure. */ static void applyTransformNLA_translation(PointerRNA *strip_rna_ptr, const TransDataNla *transdata) { diff --git a/source/blender/editors/transform/transform_convert_node.cc b/source/blender/editors/transform/transform_convert_node.cc index eb5eb822d69..6ab0e1fe701 100644 --- a/source/blender/editors/transform/transform_convert_node.cc +++ b/source/blender/editors/transform/transform_convert_node.cc @@ -155,9 +155,52 @@ static void createTransNodeData(bContext * /*C*/, TransInfo *t) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Node Transform Creation +/** \name Flush Transform Nodes * \{ */ +static void node_snap_grid_apply(TransInfo *t) +{ + int i; + + if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { + return; + } + + float grid_size[2]; + copy_v2_v2(grid_size, t->snap_spatial); + if (t->modifiers & MOD_PRECISION) { + mul_v2_fl(grid_size, t->snap_spatial_precision); + } + + /* Early exit on unusable grid size. */ + if (is_zero_v2(grid_size)) { + return; + } + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + TransData *td; + + for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { + float iloc[2], loc[2], tvec[2]; + if (td->flag & TD_SKIP) { + continue; + } + + if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { + continue; + } + + copy_v2_v2(iloc, td->loc); + + loc[0] = roundf(iloc[0] / grid_size[0]) * grid_size[0]; + loc[1] = roundf(iloc[1] / grid_size[1]) * grid_size[1]; + + sub_v2_v2v2(tvec, loc, iloc); + add_v2_v2(td->loc, tvec); + } + } +} + static void flushTransNodes(TransInfo *t) { using namespace blender::ed; @@ -191,7 +234,7 @@ static void flushTransNodes(TransInfo *t) } FOREACH_TRANS_DATA_CONTAINER (t, tc) { - applyGridAbsolute(t); + node_snap_grid_apply(t); /* flush to 2d vector from internally used 3d vector */ for (int i = 0; i < tc->data_len; i++) { diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index 0dcfd7206ad..55f7cd9b23d 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -158,14 +158,14 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) copy_qt_qt(td->ext->oquat, ob->quat); } /* update object's loc/rot to get current rigid body transform */ - mat4_to_loc_rot_size(ob->loc, rot, scale, ob->obmat); + mat4_to_loc_rot_size(ob->loc, rot, scale, ob->object_to_world); sub_v3_v3(ob->loc, ob->dloc); BKE_object_mat3_to_rot(ob, rot, false); /* drot is already corrected here */ } } /* axismtx has the real orientation */ - transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->obmat)); + transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->object_to_world)); if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) { if (!gimbal_axis_object(ob, td->ext->axismtx_gimbal)) { copy_m3_m3(td->ext->axismtx_gimbal, td->axismtx); @@ -192,7 +192,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) * More proper solution would be to make a shallow copy of the object and * evaluate that, and access matrix of that evaluated copy of the object. * Might be more tricky than it sounds, if some logic later on accesses the - * object matrix via td->ob->obmat. */ + * object matrix via td->ob->object_to_world. */ Object *object_eval = DEG_get_evaluated_object(t->depsgraph, ob); if (skip_invert == false && constinv == false) { object_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc checks this */ @@ -208,7 +208,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) } /* Copy newly evaluated fields to the original object, similar to how * active dependency graph will do it. */ - copy_m4_m4(ob->obmat, object_eval->obmat); + copy_m4_m4(ob->object_to_world, object_eval->object_to_world); /* Only copy negative scale flag, this is the only flag which is modified by * the BKE_object_where_is_calc(). The rest of the flags we need to keep, * otherwise we might lose dupli flags (see T61787). */ @@ -258,9 +258,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) copy_v3_v3(td->ext->isize, ob->scale); copy_v3_v3(td->ext->dscale, ob->dscale); - copy_v3_v3(td->center, ob->obmat[3]); + copy_v3_v3(td->center, ob->object_to_world[3]); - copy_m4_m4(td->ext->obmat, ob->obmat); + copy_m4_m4(td->ext->obmat, ob->object_to_world); /* is there a need to set the global<->data space conversion matrices? */ if (ob->parent || constinv) { @@ -271,7 +271,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) * done, as it doesn't work well. */ BKE_object_to_mat3(ob, obmtx); - copy_m3_m4(totmat, ob->obmat); + copy_m3_m4(totmat, ob->object_to_world); /* If the object scale is zero on any axis, this might result in a zero matrix. * In this case, the transformation would not do anything, see: T50103. */ diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c index 839bf6b77b3..b4c1c134d49 100644 --- a/source/blender/editors/transform/transform_convert_object_texspace.c +++ b/source/blender/editors/transform/transform_convert_object_texspace.c @@ -67,8 +67,8 @@ static void createTransTexspace(bContext *UNUSED(C), TransInfo *t) td->flag = TD_SELECTED; td->ob = ob; - copy_m3_m4(td->mtx, ob->obmat); - copy_m3_m4(td->axismtx, ob->obmat); + copy_m3_m4(td->mtx, ob->object_to_world); + copy_m3_m4(td->axismtx, ob->object_to_world); normalize_m3(td->axismtx); pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON); diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c index 3e056b6a048..f212f042773 100644 --- a/source/blender/editors/transform/transform_convert_particle.c +++ b/source/blender/editors/transform/transform_convert_particle.c @@ -95,7 +95,7 @@ static void createTransParticleVerts(bContext *UNUSED(C), TransInfo *t) unit_m4(mat); - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) { TransData *head, *tail; diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c index f4f2e2a1c6e..cdbf497c584 100644 --- a/source/blender/editors/transform/transform_convert_sculpt.c +++ b/source/blender/editors/transform/transform_convert_sculpt.c @@ -49,7 +49,7 @@ static void createTransSculpt(bContext *C, TransInfo *t) td->flag = TD_SELECTED; copy_v3_v3(td->center, ss->pivot_pos); - mul_m4_v3(ob->obmat, td->center); + mul_m4_v3(ob->object_to_world, td->center); td->ob = ob; td->loc = ss->pivot_pos; @@ -60,16 +60,16 @@ static void createTransSculpt(bContext *C, TransInfo *t) } float obmat_inv[3][3]; - copy_m3_m4(obmat_inv, ob->obmat); + copy_m3_m4(obmat_inv, ob->object_to_world); invert_m3(obmat_inv); td->ext->rot = NULL; td->ext->rotAxis = NULL; td->ext->rotAngle = NULL; td->ext->quat = ss->pivot_rot; - copy_m4_m4(td->ext->obmat, ob->obmat); + copy_m4_m4(td->ext->obmat, ob->object_to_world); copy_m3_m3(td->ext->l_smtx, obmat_inv); - copy_m3_m4(td->ext->r_mtx, ob->obmat); + copy_m3_m4(td->ext->r_mtx, ob->object_to_world); copy_m3_m3(td->ext->r_smtx, obmat_inv); copy_qt_qt(td->ext->iquat, ss->pivot_rot); @@ -83,8 +83,8 @@ static void createTransSculpt(bContext *C, TransInfo *t) copy_v3_v3(td->ext->isize, ss->init_pivot_scale); copy_m3_m3(td->smtx, obmat_inv); - copy_m3_m4(td->mtx, ob->obmat); - copy_m3_m4(td->axismtx, ob->obmat); + copy_m3_m4(td->mtx, ob->object_to_world); + copy_m3_m4(td->axismtx, ob->object_to_world); BLI_assert(!(t->options & CTX_PAINT_CURVE)); ED_sculpt_init_transform(C, ob, t->mval, t->undo_name); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 301eac4536e..e1f93bf881b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1063,7 +1063,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } if (tc->obedit) { if (ED_object_calc_active_center_for_editmode(tc->obedit, select_only, r_center)) { - mul_m4_v3(tc->obedit->obmat, r_center); + mul_m4_v3(tc->obedit->object_to_world, r_center); return true; } } @@ -1071,7 +1071,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) BKE_view_layer_synced_ensure(t->scene, t->view_layer); Object *ob = BKE_view_layer_active_object_get(t->view_layer); if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) { - mul_m4_v3(ob->obmat, r_center); + mul_m4_v3(ob->object_to_world, r_center); return true; } } @@ -1088,7 +1088,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) BKE_view_layer_synced_ensure(t->scene, t->view_layer); Base *base = BKE_view_layer_active_base_get(t->view_layer); if (base && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) { - copy_v3_v3(r_center, base->object->obmat[3]); + copy_v3_v3(r_center, base->object->object_to_world[3]); return true; } } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index f3d17559a63..2be210d24e7 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -581,12 +581,12 @@ bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3]) mul_m3_m3m3(mat, parent_mat, tmat); /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); + copy_m3_m4(obmat, ob->object_to_world); mul_m3_m3m3(gmat, obmat, mat); } else { /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); + copy_m3_m4(obmat, ob->object_to_world); mul_m3_m3m3(gmat, obmat, tmat); } @@ -608,7 +608,7 @@ bool gimbal_axis_object(Object *ob, float gmat[3][3]) if (ob->parent) { float parent_mat[3][3]; - copy_m3_m4(parent_mat, ob->parent->obmat); + copy_m3_m4(parent_mat, ob->parent->object_to_world); normalize_m3(parent_mat); mul_m3_m3m3(gmat, parent_mat, gmat); } @@ -675,14 +675,14 @@ int ED_transform_calc_gizmo_stats(const bContext *C, copy_m3_m4(tbounds->axis, rv3d->twmat); if (params->use_local_axis && (ob && ob->mode & (OB_MODE_EDIT | OB_MODE_POSE))) { float diff_mat[3][3]; - copy_m3_m4(diff_mat, ob->obmat); + copy_m3_m4(diff_mat, ob->object_to_world); normalize_m3(diff_mat); invert_m3(diff_mat); mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); normalize_m3(tbounds->axis); tbounds->use_matrix_space = true; - copy_m4_m4(tbounds->matrix_space, ob->obmat); + copy_m4_m4(tbounds->matrix_space, ob->object_to_world); } if (is_gp_edit) { @@ -751,7 +751,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, #define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) \ { \ - invert_m4_m4(obedit->imat, obedit->obmat); \ + invert_m4_m4(obedit->imat, obedit->object_to_world); \ uint objects_len = 0; \ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( \ scene, view_layer, CTX_wm_view3d(C), &objects_len); \ @@ -780,7 +780,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { @@ -800,7 +800,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) { if (EBONE_VISIBLE(arm, ebo)) { @@ -833,7 +833,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } nu = nurbs->first; @@ -893,7 +893,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) { @@ -913,7 +913,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, obedit->imat, ob_iter->object_to_world); } while (a--) { @@ -933,13 +933,13 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* selection center */ if (totsel) { mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ - mul_m4_v3(obedit->obmat, tbounds->center); - mul_m4_v3(obedit->obmat, tbounds->min); - mul_m4_v3(obedit->obmat, tbounds->max); + mul_m4_v3(obedit->object_to_world, tbounds->center); + mul_m4_v3(obedit->object_to_world, tbounds->min); + mul_m4_v3(obedit->object_to_world, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_POSE)) { - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); uint objects_len = 0; Object **objects = BKE_object_pose_array_get(scene, view_layer, v3d, &objects_len); @@ -954,7 +954,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, float mat_local[4][4]; if (use_mat_local) { - mul_m4_m4m4(mat_local, ob->imat, ob_iter->obmat); + mul_m4_m4m4(mat_local, ob->imat, ob_iter->object_to_world); } /* Use channels to get stats. */ @@ -971,18 +971,18 @@ int ED_transform_calc_gizmo_stats(const bContext *C, if (totsel) { mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ - mul_m4_v3(ob->obmat, tbounds->center); - mul_m4_v3(ob->obmat, tbounds->min); - mul_m4_v3(ob->obmat, tbounds->max); + mul_m4_v3(ob->object_to_world, tbounds->center); + mul_m4_v3(ob->object_to_world, tbounds->min); + mul_m4_v3(ob->object_to_world, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { if (ob->mode & OB_MODE_SCULPT) { totsel = 1; - calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->obmat); - mul_m4_v3(ob->obmat, tbounds->center); - mul_m4_v3(ob->obmat, tbounds->min); - mul_m4_v3(ob->obmat, tbounds->max); + calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->object_to_world); + mul_m4_v3(ob->object_to_world, tbounds->center); + mul_m4_v3(ob->object_to_world, tbounds->min); + mul_m4_v3(ob->object_to_world, tbounds->max); } } else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { @@ -1037,12 +1037,12 @@ int ED_transform_calc_gizmo_stats(const bContext *C, } if (params->use_only_center || (bb == NULL)) { - calc_tw_center(tbounds, base->object->obmat[3]); + calc_tw_center(tbounds, base->object->object_to_world[3]); } else { for (uint j = 0; j < 8; j++) { float co[3]; - mul_v3_m4v3(co, base->object->obmat, bb->vec[j]); + mul_v3_m4v3(co, base->object->object_to_world, bb->vec[j]); calc_tw_center(tbounds, co); } } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 2eaeaf92c86..aeceedf0690 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -1041,7 +1041,7 @@ void ElementResize(const TransInfo *t, if (t->options & CTX_POSE_BONE) { /* Without this, the resulting location of scaled bones aren't correct, * especially noticeable scaling root or disconnected bones around the cursor, see T92515. */ - mul_mat3_m4_v3(tc->poseobj->obmat, vec); + mul_mat3_m4_v3(tc->poseobj->object_to_world, vec); } mul_m3_v3(td->smtx, vec); } diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c index f7f9e14b8ac..0b87b45679a 100644 --- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include "BLI_math.h" +#include "BLI_math_bits.h" #include "BLI_string.h" #include "BKE_context.h" @@ -62,7 +63,14 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) } if (td->val) { - *td->val = td->ival * ratio; + if (td->ival == 0.0f && ratio > 1.0f) { + /* Allow Shrink/Fatten for zero radius. */ + *td->val = (ratio - 1.0f) * uint_as_float(POINTER_AS_UINT(t->custom.mode.data)); + } + else { + *td->val = td->ival * ratio; + } + /* apply PET */ *td->val = interpf(*td->val, td->ival, td->factor); CLAMP_MIN(*td->val, 0.0f); @@ -92,6 +100,18 @@ void initCurveShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->flag |= T_NO_CONSTRAINT; + + float scale_factor = 0.0f; + if (((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW) && + (t->data_len_all == 1)) || + (t->data_len_all == 3 && TRANS_DATA_CONTAINER_FIRST_OK(t)->data[0].val == NULL)) { + /* For cases where only one point on the curve is being transformed and the radius of that + * point is zero, use the factor to multiply the offset of the ratio and allow scaling. + * Note that for bezier curves, 3 TransData equals 1 point in most cases. */ + RegionView3D *rv3d = t->region->regiondata; + scale_factor = rv3d->pixsize * t->mouse.factor * t->zfac; + } + t->custom.mode.data = POINTER_FROM_UINT(float_as_uint(scale_factor)); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 5baf06006d9..5cdb4d3bf61 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1149,7 +1149,7 @@ void drawEdgeSlide(TransInfo *t) GPU_blend(GPU_BLEND_ALPHA); GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world); uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 91388ecd661..59d34c3918b 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -170,7 +170,7 @@ static void transdata_elem_translate_fn(void *__restrict iter_data_v, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Transform (Translation) +/** \name Transform (Translation) Header * \{ */ static void translate_dist_to_str(char *r_str, @@ -341,6 +341,96 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Translation) Snapping + * \{ */ + +static void translate_snap_target_grid_ensure(TransInfo *t) +{ + /* Only need to calculate once. */ + if ((t->tsnap.status & TARGET_GRID_INIT) == 0) { + if (t->data_type == &TransConvertType_Cursor3D) { + /* Use a fallback when transforming the cursor. + * In this case the center is _not_ derived from the cursor which is being transformed. */ + copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); + } + else if (t->around == V3D_AROUND_CURSOR) { + /* Use a fallback for cursor selection, + * this isn't useful as a global center for absolute grid snapping + * since its not based on the position of the selection. */ + tranform_snap_target_median_calc(t, t->tsnap.snapTargetGrid); + } + else { + copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global); + } + t->tsnap.status |= TARGET_GRID_INIT; + } +} + +static void translate_snap_grid_apply(TransInfo *t, + const int max_index, + const float grid_dist[3], + const float loc[3], + float r_out[3]) +{ + BLI_assert(max_index <= 2); + translate_snap_target_grid_ensure(t); + const float *center_global = t->tsnap.snapTargetGrid; + const float *asp = t->aspect; + + float in[3]; + if (t->con.mode & CON_APPLY) { + BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); + t->con.applyVec(t, NULL, NULL, loc, in); + } + else { + copy_v3_v3(in, loc); + } + + for (int i = 0; i <= max_index; i++) { + const float iter_fac = grid_dist[i] * asp[i]; + r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i]; + } +} + +static bool translate_snap_grid(TransInfo *t, float *val) +{ + if (!activeSnap(t)) { + return false; + } + + if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) { + /* Don't do grid snapping if there is a valid snap point. */ + return false; + } + + /* Don't do grid snapping if not in 3D viewport or UV editor */ + if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) { + return false; + } + + if (t->mode != TFM_TRANSLATION) { + return false; + } + + float grid_dist[3]; + copy_v3_v3(grid_dist, t->snap_spatial); + if (t->modifiers & MOD_PRECISION) { + mul_v3_fl(grid_dist, t->snap_spatial_precision); + } + + /* Early bailing out if no need to snap */ + if (is_zero_v3(grid_dist)) { + return false; + } + + translate_snap_grid_apply(t, t->idx_max, grid_dist, val, val); + t->tsnap.snapElem = SCE_SNAP_MODE_GRID; + return true; +} + static void ApplySnapTranslation(TransInfo *t, float vec[3]) { float point[3]; @@ -372,6 +462,12 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform (Translation) + * \{ */ + static void applyTranslationValue(TransInfo *t, const float vec[3]) { struct TranslateCustomData *custom_data = t->custom.mode.data; @@ -514,7 +610,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) t->tsnap.snapElem = SCE_SNAP_MODE_NONE; applySnappingAsGroup(t, global_dir); - transform_snap_grid(t, global_dir); + translate_snap_grid(t, global_dir); if (t->con.mode & CON_APPLY) { float in[3]; @@ -590,7 +686,8 @@ void initTranslation(TransInfo *t) t->num.flag = 0; t->num.idx_max = t->idx_max; - copy_v2_v2(t->snap, t->snap_spatial_x); + t->snap[0] = t->snap_spatial[0]; + t->snap[1] = t->snap_spatial[0] * t->snap_spatial_precision; copy_v3_fl(t->num.val_inc, t->snap[0]); t->num.unit_sys = t->scene->unit.system; diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index d7c4d862b23..cc1ea188fbc 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -167,7 +167,7 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2] float dir_dot; sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]); - mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir); + mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world, tdir); project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]); normalize_v3(tdir); @@ -382,7 +382,7 @@ void drawVertSlide(TransInfo *t) GPU_blend(GPU_BLEND_ALPHA); GPU_matrix_push(); - GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world); GPU_line_width(line_size); @@ -437,14 +437,15 @@ void drawVertSlide(TransInfo *t) xy_delta[0] = t->mval[0] - t->mouse.imval[0]; xy_delta[1] = t->mval[1] - t->mouse.imval[1]; - mul_v3_m4v3( - co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d); + mul_v3_m4v3(co_orig_3d, + TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world, + curr_sv->co_orig_3d); zfac = ED_view3d_calc_zfac(t->region->regiondata, co_orig_3d); ED_view3d_win_to_delta(t->region, xy_delta, zfac, co_dest_3d); invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, - TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat); + TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->object_to_world); mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d); add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 212df5978e4..66fee01f864 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -126,7 +126,7 @@ static TransformOrientation *createObjectSpace(bContext *C, ob = base->object; - copy_m3_m4(mat, ob->obmat); + copy_m3_m4(mat, ob->object_to_world); normalize_m3(mat); /* use object name if no name is given */ @@ -532,7 +532,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); } else { - transform_orientations_create_from_axis(r_mat, UNPACK3(ob->obmat)); + transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world)); } break; } @@ -764,7 +764,7 @@ int getTransformOrientation_ex(const Scene *scene, float imat[3][3], mat[3][3]; /* we need the transpose of the inverse for a normal... */ - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3_m3(mat, imat); transpose_m3(mat); @@ -1192,8 +1192,8 @@ int getTransformOrientation_ex(const Scene *scene, if (result == ORIENTATION_EDGE) { float tvec[3]; - mul_mat3_m4_v3(ob->obmat, normal); - mul_mat3_m4_v3(ob->obmat, plane); + mul_mat3_m4_v3(ob->object_to_world, normal); + mul_mat3_m4_v3(ob->object_to_world, plane); /* align normal to edge direction (so normal is perpendicular to the plane). * 'ORIENTATION_EDGE' will do the other way around. @@ -1235,7 +1235,7 @@ int getTransformOrientation_ex(const Scene *scene, /* use for both active & all */ if (ok) { /* we need the transpose of the inverse for a normal... */ - copy_m3_m4(imat, ob->obmat); + copy_m3_m4(imat, ob->object_to_world); invert_m3_m3(mat, imat); transpose_m3(mat); @@ -1267,8 +1267,8 @@ int getTransformOrientation_ex(const Scene *scene, } if (ok) { - copy_v3_v3(normal, ob->obmat[2]); - copy_v3_v3(plane, ob->obmat[1]); + copy_v3_v3(normal, ob->object_to_world[2]); + copy_v3_v3(plane, ob->object_to_world[1]); } } result = ORIENTATION_NORMAL; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 553202b5798..11cb57dc911 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -372,7 +372,7 @@ static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td } else if (t->options & CTX_OBJECT) { BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(iloc, td->ob->obmat[3]); + copy_v3_v3(iloc, td->ob->object_to_world[3]); } if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) != @@ -444,7 +444,7 @@ static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td } else if (t->options & CTX_OBJECT) { BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(init_loc, td->ob->obmat[3]); + copy_v3_v3(init_loc, td->ob->object_to_world[3]); } eSnapMode hit = ED_transform_snap_object_project_view3d( @@ -511,56 +511,6 @@ void applySnappingIndividual(TransInfo *t) } } -void applyGridAbsolute(TransInfo *t) -{ - int i; - - if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { - return; - } - - float grid_size_x = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_x[1] : t->snap_spatial_x[0]; - float grid_size_y = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_y[1] : t->snap_spatial_y[0]; - float grid_size_z = grid_size_x; - - /* Early exit on unusable grid size. */ - if (grid_size_x == 0.0f || grid_size_y == 0.0f || grid_size_z == 0.0f) { - return; - } - - FOREACH_TRANS_DATA_CONTAINER (t, tc) { - TransData *td; - - for (i = 0, td = tc->data; i < tc->data_len; i++, td++) { - float iloc[3], loc[3], tvec[3]; - if (td->flag & TD_SKIP) { - continue; - } - - if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) { - continue; - } - - copy_v3_v3(iloc, td->loc); - if (tc->use_local_mat) { - mul_m4_v3(tc->mat, iloc); - } - else if (t->options & CTX_OBJECT) { - BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob); - copy_v3_v3(iloc, td->ob->obmat[3]); - } - - loc[0] = roundf(iloc[0] / grid_size_x) * grid_size_x; - loc[1] = roundf(iloc[1] / grid_size_y) * grid_size_y; - loc[2] = roundf(iloc[2] / grid_size_z) * grid_size_z; - - sub_v3_v3v3(tvec, loc, iloc); - mul_m3_v3(td->smtx, tvec); - add_v3_v3(td->loc, tvec); - } - } -} - void applySnappingAsGroup(TransInfo *t, float *vec) { if (!activeSnap_SnappingAsGroup(t)) { @@ -1187,7 +1137,7 @@ static void snap_calc_sequencer_fn(TransInfo *t, float *UNUSED(vec)) /** \name Target * \{ */ -static void snap_target_median_impl(TransInfo *t, float r_median[3]) +void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]) { int i_accum = 0; @@ -1223,28 +1173,6 @@ static void snap_target_median_impl(TransInfo *t, float r_median[3]) // TargetSnapOffset(t, NULL); } -static void snap_target_grid_ensure(TransInfo *t) -{ - /* Only need to calculate once. */ - if ((t->tsnap.status & TARGET_GRID_INIT) == 0) { - if (t->data_type == &TransConvertType_Cursor3D) { - /* Use a fallback when transforming the cursor. - * In this case the center is _not_ derived from the cursor which is being transformed. */ - copy_v3_v3(t->tsnap.snapTargetGrid, TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->data->iloc); - } - else if (t->around == V3D_AROUND_CURSOR) { - /* Use a fallback for cursor selection, - * this isn't useful as a global center for absolute grid snapping - * since its not based on the position of the selection. */ - snap_target_median_impl(t, t->tsnap.snapTargetGrid); - } - else { - copy_v3_v3(t->tsnap.snapTargetGrid, t->center_global); - } - t->tsnap.status |= TARGET_GRID_INIT; - } -} - static void TargetSnapOffset(TransInfo *t, TransData *td) { if (t->spacetype == SPACE_NODE && td != NULL) { @@ -1316,7 +1244,7 @@ static void TargetSnapMedian(TransInfo *t) { /* Only need to calculate once. */ if ((t->tsnap.status & TARGET_INIT) == 0) { - snap_target_median_impl(t, t->tsnap.snapTarget); + tranform_snap_target_median_calc(t, t->tsnap.snapTarget); t->tsnap.status |= TARGET_INIT; } } @@ -1654,66 +1582,6 @@ bool snapNodesTransform( /** \name snap Grid * \{ */ -static void snap_grid_apply(TransInfo *t, - const int max_index, - const float grid_dist_x, - const float grid_dist_y, - const float loc[3], - float r_out[3]) -{ - BLI_assert(max_index <= 2); - snap_target_grid_ensure(t); - const float *center_global = t->tsnap.snapTargetGrid; - const float *asp = t->aspect; - - float in[3]; - if (t->con.mode & CON_APPLY) { - BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE); - t->con.applyVec(t, NULL, NULL, loc, in); - } - else { - copy_v3_v3(in, loc); - } - - for (int i = 0; i <= max_index; i++) { - const float iter_fac = ((i == 1) ? grid_dist_y : grid_dist_x) * asp[i]; - r_out[i] = iter_fac * roundf((in[i] + center_global[i]) / iter_fac) - center_global[i]; - } -} - -bool transform_snap_grid(TransInfo *t, float *val) -{ - if (!activeSnap(t)) { - return false; - } - - if (!(t->tsnap.mode & SCE_SNAP_MODE_GRID) || validSnap(t)) { - /* Don't do grid snapping if there is a valid snap point. */ - return false; - } - - /* Don't do grid snapping if not in 3D viewport or UV editor */ - if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) { - return false; - } - - if (t->mode != TFM_TRANSLATION) { - return false; - } - - float grid_dist_x = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_x[1] : t->snap_spatial_x[0]; - float grid_dist_y = (t->modifiers & MOD_PRECISION) ? t->snap_spatial_y[1] : t->snap_spatial_y[0]; - - /* Early bailing out if no need to snap */ - if (grid_dist_x == 0.0f || grid_dist_y == 0.0f) { - return false; - } - - snap_grid_apply(t, t->idx_max, grid_dist_x, grid_dist_y, val, val); - t->tsnap.snapElem = SCE_SNAP_MODE_GRID; - return true; -} - static void snap_increment_apply_ex(const TransInfo *UNUSED(t), const int max_index, const float increment_val, diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 2b78c554ad8..16d9062e978 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -38,10 +38,10 @@ bool snapNodesTransform(struct TransInfo *t, bool transformModeUseSnap(const TransInfo *t); +void tranform_snap_target_median_calc(const TransInfo *t, float r_median[3]); bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val); bool transform_snap_increment(const TransInfo *t, float *val); float transform_snap_increment_get(const TransInfo *t); -bool transform_snap_grid(TransInfo *t, float *val); bool activeSnap(const TransInfo *t); bool activeSnap_SnappingIndividual(const TransInfo *t); @@ -52,7 +52,6 @@ bool validSnap(const TransInfo *t); void initSnapping(struct TransInfo *t, struct wmOperator *op); void freeSnapping(struct TransInfo *t); void applySnappingIndividual(TransInfo *t); -void applyGridAbsolute(TransInfo *t); void applySnappingAsGroup(TransInfo *t, float *vec); void resetSnapping(TransInfo *t); eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event); diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 7971e1ca9af..24d76a50117 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -565,7 +565,7 @@ static void iter_snap_objects(SnapObjectContext *sctx, free_object_duplilist(lb); } - sob_callback(sctx, params, obj_eval, obj_eval->obmat, is_object_active, data); + sob_callback(sctx, params, obj_eval, obj_eval->object_to_world, is_object_active, data); } } @@ -1145,7 +1145,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * \param r_index: Hit index or -1 when no valid index is found. * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). * \param r_ob: Hit object. - * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). + * \param r_obmat: Object matrix (may not be #Object.object_to_world with dupli-instances). * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). */ static bool raycastObjects(SnapObjectContext *sctx, @@ -1483,7 +1483,7 @@ static void nearest_world_object_fn(SnapObjectContext *sctx, * \param r_no: Normal of nearest point on target surface. * \param r_index: Index of nearest polygon on target surface. * \param r_ob: Nearest target object. - * \param r_obmat: Nearest target matrix (may not be #Object.obmat with dupli-instances). + * \param r_obmat: Nearest target matrix (may not be #Object.object_to_world with dupli-instances). */ static bool nearestWorldObjects(SnapObjectContext *sctx, const struct SnapObjectParams *params, @@ -3177,7 +3177,7 @@ static void snap_obj_fn(SnapObjectContext *sctx, * \param r_index: Hit index or -1 when no valid index is found. * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). * \param r_ob: Hit object. - * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). + * \param r_obmat: Object matrix (may not be #Object.object_to_world with dupli-instances). */ static eSnapMode snapObjectsRay(SnapObjectContext *sctx, const SnapObjectParams *params, diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc index 5c03367cba8..4da1559b726 100644 --- a/source/blender/editors/util/ed_viewer_path.cc +++ b/source/blender/editors/util/ed_viewer_path.cc @@ -249,6 +249,9 @@ bool is_active_geometry_nodes_viewer(const bContext &C, if (md->type != eModifierType_Nodes) { return false; } + if ((md->mode & eModifierMode_Realtime) == 0) { + return false; + } modifier = reinterpret_cast<const NodesModifierData *>(md); break; } diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc index bdd05b06d94..92745667505 100644 --- a/source/blender/editors/uvedit/uvedit_islands.cc +++ b/source/blender/editors/uvedit/uvedit_islands.cc @@ -600,6 +600,22 @@ static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_ return box_array; } +static bool island_has_pins(FaceIsland *island) +{ + BMLoop *l; + BMIter iter; + const int cd_loop_uv_offset = island->cd_loop_uv_offset; + for (int i = 0; i < island->faces_len; i++) { + BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) { + MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset)); + if (luv->flag & MLOOPUV_PINNED) { + return true; + } + } + } + return false; +} + /* -------------------------------------------------------------------- */ /** \name Public UV Island Packing * @@ -651,8 +667,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, aspect_y, cd_loop_uv_offset); - int index; - LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) { + /* Remove from linked list and append to blender::Vector. */ + LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) { + BLI_remlink(&island_list, island); + if (params->ignore_pinned && island_has_pins(island)) { + MEM_freeN(island->faces); + MEM_freeN(island); + continue; + } island_vector.append(island); } } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5e2d9097abd..b65f4889347 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -37,6 +37,7 @@ #include "BKE_node.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "ED_image.h" #include "ED_mesh.h" @@ -113,7 +114,8 @@ bool ED_object_get_active_image(Object *ob, bNode **r_node, bNodeTree **r_ntree) { - Material *ma = BKE_object_material_get(ob, mat_nr); + Material *ma = DEG_is_evaluated_object(ob) ? BKE_object_material_get_eval(ob, mat_nr) : + BKE_object_material_get(ob, mat_nr); bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL; diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 7dd223a9252..777cc1d97e4 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -4705,7 +4705,7 @@ static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4742,7 +4742,7 @@ static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4818,7 +4818,7 @@ static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4859,7 +4859,7 @@ static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) bool changed = false; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -4927,7 +4927,7 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op) BMesh *bm = em->bm; float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); @@ -4963,7 +4963,7 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op) const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); float ob_m3[3][3]; - copy_m3_m4(ob_m3, ob->obmat); + copy_m3_m4(ob_m3, ob->object_to_world); BMFace *face; BMIter iter; @@ -5053,7 +5053,7 @@ static int uv_select_similar_island_exec(bContext *C, wmOperator *op) } float ob_m3[3][3]; - copy_m3_m4(ob_m3, obedit->obmat); + copy_m3_m4(ob_m3, obedit->object_to_world); int index; LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { @@ -5082,7 +5082,7 @@ static int uv_select_similar_island_exec(bContext *C, wmOperator *op) continue; } float ob_m3[3][3]; - copy_m3_m4(ob_m3, obedit->obmat); + copy_m3_m4(ob_m3, obedit->object_to_world); bool changed = false; int index; diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 2c977552e72..de1c88fe896 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1050,31 +1050,6 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /** \name Pack UV Islands Operator * \{ */ -/** - * \warning Since this uses #ParamHandle it doesn't work with non-manifold meshes (see T82637). - * Use #ED_uvedit_pack_islands_multi for a more general solution. - * - * TODO: remove this function, in favor of #ED_uvedit_pack_islands_multi. - */ -static void uvedit_pack_islands_multi(const Scene *scene, - Object **objects, - const uint objects_len, - const UnwrapOptions *options, - bool rotate, - bool ignore_pinned) -{ - ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options); - GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); - GEO_uv_parametrizer_flush(handle); - GEO_uv_parametrizer_delete(handle); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); - } -} - /* Packing targets. */ enum { PACK_UDIM_SRC_CLOSEST = 0, @@ -1119,16 +1094,22 @@ static int pack_islands_exec(bContext *C, wmOperator *op) const bool use_udim_params = ED_uvedit_udim_params_from_image_space( sima, use_active, &udim_params); - struct UVPackIsland_Params params = { + const struct UVPackIsland_Params pack_island_params = { .rotate = RNA_boolean_get(op->ptr, "rotate"), - .only_selected_uvs = true, - .only_selected_faces = true, - .correct_aspect = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = false, .margin_method = RNA_enum_get(op->ptr, "margin_method"), .margin = RNA_float_get(op->ptr, "margin"), }; - ED_uvedit_pack_islands_multi( - scene, objects, objects_len, NULL, use_udim_params ? &udim_params : NULL, ¶ms); + ED_uvedit_pack_islands_multi(scene, + objects, + objects_len, + NULL, + use_udim_params ? &udim_params : NULL, + &pack_island_params); MEM_freeN(objects); return OPERATOR_FINISHED; @@ -1407,7 +1388,7 @@ static void uv_map_transform_center(const Scene *scene, } case V3D_AROUND_CURSOR: /* cursor center */ { - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_v3_m4v3(r_center, ob->imat, scene->cursor.location); break; } @@ -1458,7 +1439,7 @@ static void uv_map_rotation_matrix_ex(float result[4][4], zero_v3(viewmatrix[3]); /* get rotation of the current object matrix */ - copy_m4_m4(rotobj, ob->obmat); + copy_m4_m4(rotobj, ob->object_to_world); zero_v3(rotobj[3]); /* but shifting */ @@ -1793,8 +1774,8 @@ static void uv_map_clip_correct(const Scene *scene, dy = 1.0f / dy; } - if (dx == 1.0f && dy == 1.0f) { - /* Scaling by 1.0 has no effect. */ + if (dx == 1.0f && dy == 1.0f && min[0] == 0.0f && min[1] == 0.0f) { + /* Scaling by 1.0, without translating, has no effect. */ return; } @@ -1889,12 +1870,19 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0, .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0, }; - - bool rotate = true; - bool ignore_pinned = true; - uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + + const struct UVPackIsland_Params pack_island_params = { + .rotate = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = true, + .margin_method = ED_UVPACK_MARGIN_SCALED, + .margin = scene->toolsettings->uvcalc_margin, + }; + ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params); } } @@ -1926,8 +1914,6 @@ static int unwrap_exec(bContext *C, wmOperator *op) .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"), }; - bool rotate = true; - bool ignore_pinned = true; if (CTX_wm_space_image(C)) { /* Inside the UV Editor, only unwrap selected UVs. */ options.only_selected_uvs = true; @@ -1962,7 +1948,7 @@ static int unwrap_exec(bContext *C, wmOperator *op) continue; } - mat4_to_size(obsize, obedit->obmat); + mat4_to_size(obsize, obedit->object_to_world); if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) { if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) { BKE_report(op->reports, @@ -1972,7 +1958,7 @@ static int unwrap_exec(bContext *C, wmOperator *op) reported_errors |= UNWRAP_ERROR_NONUNIFORM; } } - else if (is_negative_m4(obedit->obmat)) { + else if (is_negative_m4(obedit->object_to_world)) { if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) { BKE_report( op->reports, @@ -2032,7 +2018,18 @@ static int unwrap_exec(bContext *C, wmOperator *op) .count_failed = 0, }; uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info); - uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); + + const struct UVPackIsland_Params pack_island_params = { + .rotate = true, + .only_selected_uvs = options.only_selected_uvs, + .only_selected_faces = options.only_selected_faces, + .use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams, + .correct_aspect = options.correct_aspect, + .ignore_pinned = true, + .margin_method = RNA_enum_get(op->ptr, "margin_method"), + .margin = RNA_float_get(op->ptr, "margin"), + }; + ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params); MEM_freeN(objects); @@ -2541,7 +2538,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) float objects_pos_avg[4] = {0}; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]); + add_v4_v4(objects_pos_avg, objects[ob_index]->object_to_world[3]); } mul_v4_fl(objects_pos_avg, 1.0f / objects_len); @@ -2579,7 +2576,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds"); struct ProjCameraInfo *uci = BLI_uvproject_camera_info( v3d->camera, - obedit->obmat, + obedit->object_to_world, camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f, camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f); @@ -2600,7 +2597,7 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) } } else { - copy_m4_m4(rotmat, obedit->obmat); + copy_m4_m4(rotmat, obedit->object_to_world); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 0d41b5a773d..53c2b1d235b 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -431,7 +431,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) // Compute matrix including camera transform float obmat[4][4], nmat[4][4]; - mul_m4_m4m4(obmat, viewmat, ob->obmat); + mul_m4_m4m4(obmat, viewmat, ob->object_to_world); invert_m4_m4(nmat, obmat); transpose_m4(nmat); diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp index ad9b7dfa5ed..0d47665c6d3 100644 --- a/source/blender/freestyle/intern/geometry/FitCurve.cpp +++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp @@ -12,6 +12,8 @@ #include "FitCurve.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp index c17fb92a58c..db6816bf045 100644 --- a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp +++ b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp @@ -25,6 +25,8 @@ #include "BKE_global.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp index f1e4297ab5e..b8beeed5880 100644 --- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp +++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp @@ -7,6 +7,8 @@ #include "GeomUtils.h" +#include "BLI_sys_types.h" + namespace Freestyle::GeomUtils { // This internal procedure is defined below. diff --git a/source/blender/freestyle/intern/geometry/HashGrid.cpp b/source/blender/freestyle/intern/geometry/HashGrid.cpp index 51c87757645..46ce9184951 100644 --- a/source/blender/freestyle/intern/geometry/HashGrid.cpp +++ b/source/blender/freestyle/intern/geometry/HashGrid.cpp @@ -7,6 +7,8 @@ #include "HashGrid.h" +#include "BLI_sys_types.h" + namespace Freestyle { void HashGrid::clear() diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp index 306913e6297..04e271f7a5b 100644 --- a/source/blender/freestyle/intern/geometry/Noise.cpp +++ b/source/blender/freestyle/intern/geometry/Noise.cpp @@ -12,6 +12,7 @@ #include "BLI_compiler_attrs.h" #include "BLI_rand.h" +#include "BLI_sys_types.h" #include "Noise.h" diff --git a/source/blender/freestyle/intern/image/ImagePyramid.cpp b/source/blender/freestyle/intern/image/ImagePyramid.cpp index 95afa4dda48..bc68d17a1f9 100644 --- a/source/blender/freestyle/intern/image/ImagePyramid.cpp +++ b/source/blender/freestyle/intern/image/ImagePyramid.cpp @@ -11,6 +11,8 @@ #include "Image.h" #include "ImagePyramid.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp index 114fafea55b..d79c2f4d9b0 100644 --- a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp +++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp @@ -9,6 +9,8 @@ #include "../stroke/ContextFunctions.h" +#include "BLI_sys_types.h" + using namespace Freestyle; #ifdef __cplusplus diff --git a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp index 097fdb6a16b..684edb26a97 100644 --- a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp +++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp @@ -9,6 +9,8 @@ #include "../system/RandGen.h" +#include "BLI_sys_types.h" + #include <sstream> #ifdef __cplusplus diff --git a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp index d88d3edecc0..711cf9c6bab 100644 --- a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp +++ b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp @@ -12,6 +12,8 @@ #include "UnaryFunction0D/BPy_UnaryFunction0DFloat.h" #include "UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp index 1c5e90474ab..860573016f2 100644 --- a/source/blender/freestyle/intern/python/BPy_Operators.cpp +++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp @@ -16,6 +16,8 @@ #include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h" #include "UnaryFunction1D/BPy_UnaryFunction1DVoid.h" +#include "BLI_sys_types.h" + #include <sstream> #ifdef __cplusplus diff --git a/source/blender/freestyle/intern/python/BPy_SShape.cpp b/source/blender/freestyle/intern/python/BPy_SShape.cpp index 7fb647119e6..92867e36479 100644 --- a/source/blender/freestyle/intern/python/BPy_SShape.cpp +++ b/source/blender/freestyle/intern/python/BPy_SShape.cpp @@ -12,6 +12,8 @@ #include "Interface0D/BPy_SVertex.h" #include "Interface1D/BPy_FEdge.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp index 77c3c708103..130526ac309 100644 --- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp +++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp @@ -11,6 +11,8 @@ #include "Interface0D/BPy_ViewVertex.h" #include "Interface1D/BPy_ViewEdge.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Director.cpp b/source/blender/freestyle/intern/python/Director.cpp index ad54787ad05..40df2033221 100644 --- a/source/blender/freestyle/intern/python/Director.cpp +++ b/source/blender/freestyle/intern/python/Director.cpp @@ -42,6 +42,8 @@ #include "UnaryFunction1D/BPy_UnaryFunction1DVec3f.h" #include "UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h" +#include "BLI_sys_types.h" + using namespace Freestyle; // BinaryPredicate0D: __call__ diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp index cb84b7e82ba..55faebc509c 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp @@ -10,6 +10,8 @@ #include "../BPy_Id.h" #include "../Interface1D/BPy_FEdge.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp index e9dcedef34e..6f90406d74d 100644 --- a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp @@ -13,6 +13,8 @@ #include "../Interface0D/CurvePoint/BPy_StrokeVertex.h" #include "../Iterator/BPy_StrokeVertexIterator.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp index 0a4d1a5d32c..aae8d5514c9 100644 --- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp @@ -9,6 +9,8 @@ #include "../../BPy_Convert.h" #include "../../Interface0D/BPy_SVertex.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp index 51ae9334f37..6516ad8af9c 100644 --- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp @@ -9,6 +9,8 @@ #include "../../BPy_Convert.h" #include "../../Interface0D/BPy_SVertex.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp index 29e1a1d3525..8faefd085d6 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp @@ -11,6 +11,8 @@ #include "UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp index e0aa5af2adb..7f5b98da223 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp @@ -11,6 +11,8 @@ #include "UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp index 3a2c9868014..82362704119 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp @@ -8,6 +8,8 @@ #include "../../../stroke/AdvancedFunctions0D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp index 41bc3199271..800a5da1978 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp @@ -12,6 +12,8 @@ #include "UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp index 242f4a141bc..fa15983f0d3 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp @@ -14,6 +14,8 @@ #include "UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h" #include "UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp index b513686524e..d1479f27935 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp @@ -10,6 +10,8 @@ #include "../../BPy_Convert.h" #include "../../BPy_IntegrationType.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp index ecf95e189d8..99c688985f5 100644 --- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp @@ -6,6 +6,8 @@ #include "BPy_EqualToChainingTimeStampUP1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp index b75e45cb132..48365507d1a 100644 --- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp @@ -6,6 +6,8 @@ #include "BPy_EqualToTimeStampUP1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp index ad8aba9eb29..b410ee14831 100644 --- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp @@ -6,6 +6,8 @@ #include "BPy_ShapeUP1D.h" +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp index 3962ac0aa35..39dbf4b87a9 100644 --- a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp +++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp @@ -7,6 +7,8 @@ #include "IndexedFaceSet.h" +#include "BLI_sys_types.h" + namespace Freestyle { IndexedFaceSet::IndexedFaceSet() diff --git a/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp b/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp index 97fa07df4c9..0089f68ce2d 100644 --- a/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp +++ b/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp @@ -9,6 +9,7 @@ #include "NodeTransform.h" #include "BLI_math.h" +#include "BLI_sys_types.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp index a4ef70722d0..0ab83003514 100644 --- a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp +++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp @@ -6,6 +6,8 @@ #include "SceneHash.h" +#include "BLI_sys_types.h" + #include <sstream> namespace Freestyle { diff --git a/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp index cc5d8ef6ed4..4a2b6979985 100644 --- a/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp +++ b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp @@ -10,6 +10,8 @@ #include "IndexedFaceSet.h" #include "ScenePrettyPrinter.h" +#include "BLI_sys_types.h" + namespace Freestyle { #define VISIT(CLASS) \ diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp index 79825b626d5..a221e0e8bbd 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp +++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp @@ -10,6 +10,8 @@ #include "../view_map/SteerableViewMap.h" +#include "BLI_sys_types.h" + namespace Freestyle::Functions1D { int GetSteerableViewMapDensityF1D::operator()(Interface1D &inter) diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h index c19ac31ae4a..e5009f2b4f8 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h +++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h @@ -33,7 +33,7 @@ class DensityF1D : public UnaryFunction1D<double> { public: /** Builds the functor. * \param sigma: - * Thesigma used in DensityF0D and determining the window size used in each density query. + * The sigma used in DensityF0D and determining the window size used in each density query. * \param iType: * The integration method used to compute a single value from a set of values. * \param sampling: diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp index 4ff00dd0a08..6508c95f2b4 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp +++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp @@ -11,6 +11,8 @@ #include "../system/PseudoNoise.h" #include "../system/RandGen.h" +#include "BLI_sys_types.h" + namespace Freestyle { ///////////////////////////////////////// diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp index 4df0bd7b089..e77ba63f3d6 100644 --- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp +++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp @@ -23,6 +23,8 @@ #include "BKE_global.h" +#include "BLI_sys_types.h" + #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/freestyle/intern/stroke/Canvas.cpp b/source/blender/freestyle/intern/stroke/Canvas.cpp index af79a8eb4eb..741fad592cf 100644 --- a/source/blender/freestyle/intern/stroke/Canvas.cpp +++ b/source/blender/freestyle/intern/stroke/Canvas.cpp @@ -22,6 +22,8 @@ #include "../view_map/SteerableViewMap.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" // soc #include <qimage.h> diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp index 879ea49b43a..cd37a5f893d 100644 --- a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp +++ b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp @@ -12,6 +12,8 @@ #include "../system/TimeStamp.h" +#include "BLI_sys_types.h" + namespace Freestyle::ContextFunctions { uint GetTimeStampCF() diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp index b45e3218a13..93524e6ebe5 100644 --- a/source/blender/freestyle/intern/stroke/Operators.cpp +++ b/source/blender/freestyle/intern/stroke/Operators.cpp @@ -14,6 +14,8 @@ #include "Stroke.h" #include "StrokeIterators.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp index 30dacb7f7df..095cb74d607 100644 --- a/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp +++ b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp @@ -9,6 +9,8 @@ #include "../geometry/GeomUtils.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/system/StringUtils.cpp b/source/blender/freestyle/intern/system/StringUtils.cpp index 79b2cea0446..fbd85815da1 100644 --- a/source/blender/freestyle/intern/system/StringUtils.cpp +++ b/source/blender/freestyle/intern/system/StringUtils.cpp @@ -10,6 +10,8 @@ #include "StringUtils.h" #include "FreestyleConfig.h" +#include "BLI_sys_types.h" + namespace Freestyle::StringUtils { void getPathName(const string &path, const string &base, vector<string> &pathnames) diff --git a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp index 7fa4f52506d..f4619e6e85f 100644 --- a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp +++ b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp @@ -7,6 +7,8 @@ #include "ArbitraryGridDensityProvider.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp index 11ba5933ce0..b984d5dba29 100644 --- a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp +++ b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp @@ -7,6 +7,8 @@ #include "AverageAreaGridDensityProvider.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.cpp b/source/blender/freestyle/intern/view_map/BoxGrid.cpp index 36afb0119a2..4464aab6419 100644 --- a/source/blender/freestyle/intern/view_map/BoxGrid.cpp +++ b/source/blender/freestyle/intern/view_map/BoxGrid.cpp @@ -10,6 +10,8 @@ #include "BoxGrid.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp index e2886370800..c1afb6de881 100644 --- a/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp +++ b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp @@ -9,6 +9,8 @@ #include "../geometry/GridHelpers.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp index e455011f187..b7e805f8767 100644 --- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -12,6 +12,8 @@ #include "../geometry/GeomUtils.h" #include "../geometry/normal_cycle.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/Functions0D.cpp b/source/blender/freestyle/intern/view_map/Functions0D.cpp index 2157c533986..aaafc5c884a 100644 --- a/source/blender/freestyle/intern/view_map/Functions0D.cpp +++ b/source/blender/freestyle/intern/view_map/Functions0D.cpp @@ -8,6 +8,8 @@ #include "Functions0D.h" #include "ViewMap.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp index 7e4f673e2fb..40fa8387637 100644 --- a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp +++ b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp @@ -7,6 +7,8 @@ #include "HeuristicGridDensityProviderFactory.h" +#include "BLI_sys_types.h" + namespace Freestyle { HeuristicGridDensityProviderFactory::HeuristicGridDensityProviderFactory(real sizeFactor, diff --git a/source/blender/freestyle/intern/view_map/OccluderSource.cpp b/source/blender/freestyle/intern/view_map/OccluderSource.cpp index 54c30661de9..7ac5de9abbc 100644 --- a/source/blender/freestyle/intern/view_map/OccluderSource.cpp +++ b/source/blender/freestyle/intern/view_map/OccluderSource.cpp @@ -9,6 +9,8 @@ #include "OccluderSource.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp index 43809f83dc4..af6924eea6e 100644 --- a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp +++ b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp @@ -7,6 +7,8 @@ #include "Pow23GridDensityProvider.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp index 7d9d871f586..ce4c8fcd453 100644 --- a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp +++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp @@ -14,6 +14,8 @@ #include "../geometry/GeomUtils.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp index 6d800d13b3b..bb4dbd17f70 100644 --- a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp +++ b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp @@ -10,6 +10,8 @@ #include "SphericalGrid.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" using namespace std; diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp index ba37dc434f4..20472599835 100644 --- a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp +++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp @@ -16,8 +16,10 @@ #include "../image/Image.h" #include "../image/ImagePyramid.h" -#include "BKE_global.h" #include "BLI_math.h" +#include "BLI_sys_types.h" + +#include "BKE_global.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp index 277334d13fd..fcb157a4e60 100644 --- a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp @@ -13,6 +13,8 @@ #include "../winged_edge/WXEdge.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp index 0ba4850eed5..09432aa4ac7 100644 --- a/source/blender/freestyle/intern/view_map/ViewMap.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp @@ -13,6 +13,8 @@ #include "../geometry/GeomUtils.h" +#include "BLI_sys_types.h" + namespace Freestyle { /**********************************/ diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index 4ef06c0ac96..9c2919b0ca8 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -24,6 +24,8 @@ #include "../winged_edge/WFillGrid.h" +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h index 2da95d47912..c666e548884 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h +++ b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h @@ -89,7 +89,7 @@ class ViewMapTesselator { #endif }; -/** Class to tesselate the 2D projected silhouette */ +/** Class to tessellate the 2D projected silhouette */ class ViewMapTesselator2D : public ViewMapTesselator { public: inline ViewMapTesselator2D() : ViewMapTesselator() @@ -110,7 +110,7 @@ class ViewMapTesselator2D : public ViewMapTesselator { #endif }; -/** Class to tesselate the 3D silhouette */ +/** Class to tessellate the 3D silhouette */ class ViewMapTesselator3D : public ViewMapTesselator { public: inline ViewMapTesselator3D() : ViewMapTesselator() diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.cpp b/source/blender/freestyle/intern/winged_edge/WEdge.cpp index 33f72cc0c9f..3082988bd36 100644 --- a/source/blender/freestyle/intern/winged_edge/WEdge.cpp +++ b/source/blender/freestyle/intern/winged_edge/WEdge.cpp @@ -9,6 +9,8 @@ #include "WEdge.h" +#include "BLI_sys_types.h" + namespace Freestyle { /** Temporary structures */ diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.cpp b/source/blender/freestyle/intern/winged_edge/WXEdge.cpp index 2c107a01d13..6838060b44e 100644 --- a/source/blender/freestyle/intern/winged_edge/WXEdge.cpp +++ b/source/blender/freestyle/intern/winged_edge/WXEdge.cpp @@ -6,6 +6,9 @@ */ #include "WXEdge.h" + +#include "BLI_sys_types.h" + #include "BKE_global.h" namespace Freestyle { diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp index 929e9b7e4dd..e22de505472 100644 --- a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp +++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp @@ -9,6 +9,8 @@ #include "WXEdgeBuilder.h" #include "WXEdge.h" +#include "BLI_sys_types.h" + namespace Freestyle { void WXEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet &ifs) diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp index e8095d89ee1..ce6054830f3 100644 --- a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp +++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp @@ -14,6 +14,8 @@ #include "../scene_graph/NodeShape.h" +#include "BLI_sys_types.h" + using namespace std; namespace Freestyle { diff --git a/source/blender/geometry/intern/fillet_curves.cc b/source/blender/geometry/intern/fillet_curves.cc index 1bbbee6edef..2479458f88d 100644 --- a/source/blender/geometry/intern/fillet_curves.cc +++ b/source/blender/geometry/intern/fillet_curves.cc @@ -148,12 +148,14 @@ static float limit_radius(const float3 &position_prev, const float displacement_prev = radius_prev * std::tan(angle_prev / 2.0f); const float segment_length_prev = math::distance(position, position_prev); const float total_displacement_prev = displacement_prev + displacement; - const float factor_prev = std::clamp(segment_length_prev / total_displacement_prev, 0.0f, 1.0f); + const float factor_prev = std::clamp( + safe_divide(segment_length_prev, total_displacement_prev), 0.0f, 1.0f); const float displacement_next = radius_next * std::tan(angle_next / 2.0f); const float segment_length_next = math::distance(position, position_next); const float total_displacement_next = displacement_next + displacement; - const float factor_next = std::clamp(segment_length_next / total_displacement_next, 0.0f, 1.0f); + const float factor_next = std::clamp( + safe_divide(segment_length_next, total_displacement_next), 0.0f, 1.0f); return radius * std::min(factor_prev, factor_next); } diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index c649bde06ca..2d9c23df348 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -433,7 +433,7 @@ static void foreach_geometry_in_reference( int index = 0; FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) { const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object); - const float4x4 matrix = base_transform * offset_matrix * object->obmat; + const float4x4 matrix = base_transform * offset_matrix * object->object_to_world; const int sub_id = noise::hash(id, index); fn(object_geometry_set, matrix, sub_id); index++; diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc index a7f6ac16f8d..3be850ec097 100644 --- a/source/blender/geometry/intern/resample_curves.cc +++ b/source/blender/geometry/intern/resample_curves.cc @@ -139,6 +139,9 @@ static void gather_point_attributes_to_interpolate( if (meta_data.domain != ATTR_DOMAIN_POINT) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) { return true; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index 8bb61136cc2..e51fe8832f0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -104,9 +104,9 @@ static void BKE_gpencil_instance_modifier_instance_tfm(Object *ob, if (mmd->flag & GP_ARRAY_USE_OFFSET) { add_v3_v3(mat_offset[3], mmd->offset); } - invert_m4_m4(obinv, ob->obmat); + invert_m4_m4(obinv, ob->object_to_world); - mul_m4_series(r_offset, mat_offset, obinv, mmd->object->obmat); + mul_m4_series(r_offset, mat_offset, obinv, mmd->object->object_to_world); copy_m4_m4(mat_offset, r_offset); /* clear r_mat locations to avoid double transform */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index 3c971ec6af0..49ac3275c82 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -303,8 +303,8 @@ static void build_sequential(Object *ob, /* Compute distance to control object if set, and build according to that order. */ if (mmd->object) { float sv1[3], sv2[3]; - mul_v3_m4v3(sv1, ob->obmat, &gps->points[0].x); - mul_v3_m4v3(sv2, ob->obmat, &gps->points[gps->totpoints - 1].x); + mul_v3_m4v3(sv1, ob->object_to_world, &gps->points[0].x); + mul_v3_m4v3(sv2, ob->object_to_world, &gps->points[gps->totpoints - 1].x); float dist_l = len_v3v3(sv1, mmd->object->loc); float dist_r = len_v3v3(sv2, mmd->object->loc); if (dist_r < dist_l) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index 1a2bfebdc55..6e31fffd11d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -234,13 +234,13 @@ static void deformStroke(GpencilModifierData *md, /* get world-space matrix of target, corrected for the space the verts are in */ if (mmd->subtarget[0] && pchan) { /* bone target if there's a matching pose-channel */ - mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat); + mul_m4_m4m4(dmat, mmd->object->object_to_world, pchan->pose_mat); } else { /* just object target */ - copy_m4_m4(dmat, mmd->object->obmat); + copy_m4_m4(dmat, mmd->object->object_to_world); } - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv); /* loop points and apply deform */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 326e86091c5..bc91094e80e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -81,8 +81,8 @@ static void update_mirror_object(Object *ob, float tmp[4][4]; float itmp[4][4]; - invert_m4_m4(tmp, mmd->object->obmat); - mul_m4_m4m4(tmp, tmp, ob->obmat); + invert_m4_m4(tmp, mmd->object->object_to_world); + mul_m4_m4m4(tmp, tmp, ob->object_to_world); invert_m4_m4(itmp, tmp); mul_m4_series(mtx, itmp, mtx, tmp); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index 1cf11a694ac..cb4a7893080 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -109,7 +109,7 @@ static void duplicateStroke(Object *ob, float opacity_factor; /* Apply object scale to offset distance. */ - offset *= mat4_to_scale(ob->obmat); + offset *= mat4_to_scale(ob->object_to_world); BKE_gpencil_stroke_normal(gps, stroke_normal); if (len_v3(stroke_normal) < FLT_EPSILON) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c index 387e3c2d5ce..455d8b0b528 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c @@ -116,7 +116,7 @@ static void convert_stroke(GpencilModifierData *md, /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Stroke. */ @@ -197,7 +197,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec } Object *cam_ob = scene->camera; float viewmat[4][4]; - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl); @@ -240,7 +240,7 @@ static void bakeModifier(Main *UNUSED(bmain), BKE_scene_graph_update_for_newframe(depsgraph); /* Ensure the camera is the right one. */ BKE_scene_camera_switch_update(scene); - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); /* Prepare transform matrix. */ float diff_mat[4][4]; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 94d8cb98290..7add5c7b84e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -144,7 +144,7 @@ static void deformStroke(GpencilModifierData *md, float coba_res[4]; float matrix[4][4]; if (is_gradient) { - mul_m4_m4m4(matrix, mmd->object->imat, ob->obmat); + mul_m4_m4m4(matrix, mmd->object->imat, ob->object_to_world); } /* loop points and apply color. */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c index 3ecff4bf447..e9761732614 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c @@ -97,7 +97,7 @@ static void deformStroke(GpencilModifierData *md, /* Apply the rotation of the object. */ if (mmd->space == GP_SPACE_LOCAL) { - mul_mat3_m4_v3(ob->obmat, vec_ref); + mul_mat3_m4_v3(ob->object_to_world, vec_ref); } /* Ensure there is a vertex group. */ @@ -122,8 +122,8 @@ static void deformStroke(GpencilModifierData *md, bGPDspoint *pt1 = (i > 0) ? &gps->points[i] : &gps->points[i + 1]; bGPDspoint *pt2 = (i > 0) ? &gps->points[i - 1] : &gps->points[i]; float fpt1[3], fpt2[3]; - mul_v3_m4v3(fpt1, ob->obmat, &pt1->x); - mul_v3_m4v3(fpt2, ob->obmat, &pt2->x); + mul_v3_m4v3(fpt1, ob->object_to_world, &pt1->x); + mul_v3_m4v3(fpt2, ob->object_to_world, &pt2->x); float vec[3]; sub_v3_v3v3(vec, fpt1, fpt2); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c index f64c83443d8..ddf852bcd11 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c @@ -64,8 +64,8 @@ static float calc_point_weight_by_distance(Object *ob, { float weight; float gvert[3]; - mul_v3_m4v3(gvert, ob->obmat, &pt->x); - float dist = len_v3v3(mmd->object->obmat[3], gvert); + mul_v3_m4v3(gvert, ob->object_to_world, &pt->x); + float dist = len_v3v3(mmd->object->object_to_world[3], gvert); if (dist > dist_max) { weight = 1.0f; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc index 5e741ccbd55..85f158d42e6 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc @@ -9,17 +9,15 @@ #include "MOD_lineart.h" #include "lineart_intern.h" -static bool cmp_adjacent_items(const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2) -{ - int a = p1.v1 - p2.v1; - int b = p1.v2 - p2.v2; - /* parallel_sort() requires cmp() to return true when the first element needs to appear before - * the second element in the sorted array, false otherwise (strict weak ordering), see - * https://en.cppreference.com/w/cpp/named_req/Compare. */ - return a < 0 ? true : (a == 0 ? b < 0 : false); -} - void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length) { - blender::parallel_sort(ai, ai + length, cmp_adjacent_items); + blender::parallel_sort( + ai, ai + length, [](const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2) { + int a = p1.v1 - p2.v1; + int b = p1.v2 - p2.v2; + /* parallel_sort() requires cmp() to return true when the first element needs to appear + * before the second element in the sorted array, false otherwise (strict weak ordering), + * see https://en.cppreference.com/w/cpp/named_req/Compare. */ + return a < 0 ? true : (a == 0 ? b < 0 : false); + }); } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index c1e71bde254..4b5c40c0e38 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -2633,7 +2633,7 @@ void lineart_main_load_geometries(Depsgraph *depsgraph, scene, eval_ob, eval_ob, - eval_ob->obmat, + eval_ob->object_to_world, is_render, olti, thread_count, @@ -3589,11 +3589,11 @@ static LineartData *lineart_create_render_buffer(Scene *scene, clipping_offset = 0.0001; } - copy_v3db_v3fl(ld->conf.camera_pos, camera->obmat[3]); + copy_v3db_v3fl(ld->conf.camera_pos, camera->object_to_world[3]); if (active_camera) { - copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->obmat[3]); + copy_v3db_v3fl(ld->conf.active_camera_pos, active_camera->object_to_world[3]); } - copy_m4_m4(ld->conf.cam_obmat, camera->obmat); + copy_m4_m4(ld->conf.cam_obmat, camera->object_to_world); ld->conf.cam_is_persp = (c->type == CAM_PERSP); ld->conf.near_clip = c->clip_start + clipping_offset; @@ -3620,8 +3620,8 @@ static LineartData *lineart_create_render_buffer(Scene *scene, if (lmd->light_contour_object) { Object *light_obj = lmd->light_contour_object; - copy_v3db_v3fl(ld->conf.camera_pos_secondary, light_obj->obmat[3]); - copy_m4_m4(ld->conf.cam_obmat_secondary, light_obj->obmat); + copy_v3db_v3fl(ld->conf.camera_pos_secondary, light_obj->object_to_world[3]); + copy_m4_m4(ld->conf.cam_obmat_secondary, light_obj->object_to_world); ld->conf.light_reference_available = true; if (light_obj->type == OB_LAMP) { ld->conf.cam_is_persp_secondary = ((Light *)light_obj->data)->type != LA_SUN; @@ -5418,7 +5418,7 @@ void MOD_lineart_gpencil_generate(LineartCache *cache, } float gp_obmat_inverse[4][4]; - invert_m4_m4(gp_obmat_inverse, ob->obmat); + invert_m4_m4(gp_obmat_inverse, ob->object_to_world); lineart_gpencil_generate(cache, depsgraph, ob, diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c index e34e6fc43ea..edea052e728 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c @@ -1167,7 +1167,7 @@ bool lineart_main_try_generate_shadow(Depsgraph *depsgraph, copy_v3_v3_db(ld->conf.camera_pos_secondary, ld->conf.camera_pos); copy_m4_m4(ld->conf.cam_obmat_secondary, ld->conf.cam_obmat); - copy_m4_m4(ld->conf.cam_obmat, lmd->light_contour_object->obmat); + copy_m4_m4(ld->conf.cam_obmat, lmd->light_contour_object->object_to_world); copy_v3db_v3fl(ld->conf.camera_pos, ld->conf.cam_obmat[3]); ld->conf.cam_is_persp_secondary = ld->conf.cam_is_persp; ld->conf.cam_is_persp = is_persp; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5a1e0cde1d8..bfbbf1be225 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -12,6 +12,7 @@ endif() set(INC . intern + vulkan metal opengl ../blenkernel @@ -184,6 +185,34 @@ set(OPENGL_SRC opengl/gl_vertex_buffer.hh ) +set(VULKAN_SRC + vulkan/vk_backend.cc + vulkan/vk_batch.cc + vulkan/vk_context.cc + vulkan/vk_drawlist.cc + vulkan/vk_framebuffer.cc + vulkan/vk_index_buffer.cc + vulkan/vk_query.cc + vulkan/vk_shader.cc + vulkan/vk_storage_buffer.cc + vulkan/vk_texture.cc + vulkan/vk_uniform_buffer.cc + vulkan/vk_vertex_buffer.cc + + vulkan/vk_backend.hh + vulkan/vk_batch.hh + vulkan/vk_context.hh + vulkan/vk_drawlist.hh + vulkan/vk_framebuffer.hh + vulkan/vk_index_buffer.hh + vulkan/vk_query.hh + vulkan/vk_shader.hh + vulkan/vk_storage_buffer.hh + vulkan/vk_texture.hh + vulkan/vk_uniform_buffer.hh + vulkan/vk_vertex_buffer.hh +) + set(METAL_SRC metal/mtl_backend.mm metal/mtl_batch.mm @@ -235,6 +264,10 @@ if(WITH_OPENGL) list(APPEND SRC ${OPENGL_SRC}) endif() +if(WITH_VULKAN_BACKEND) + list(APPEND SRC ${VULKAN_SRC}) +endif() + if(WITH_METAL_BACKEND) list(APPEND SRC ${METAL_SRC}) endif() @@ -282,6 +315,8 @@ set(GLSL_SRC shaders/gpu_shader_2D_image_vert.glsl shaders/gpu_shader_2D_image_rect_vert.glsl shaders/gpu_shader_2D_image_multi_rect_vert.glsl + shaders/gpu_shader_icon_frag.glsl + shaders/gpu_shader_icon_vert.glsl shaders/gpu_shader_image_frag.glsl shaders/gpu_shader_image_desaturate_frag.glsl shaders/gpu_shader_image_overlays_merge_frag.glsl @@ -349,6 +384,7 @@ set(GLSL_SRC shaders/compositor/compositor_morphological_distance_feather.glsl shaders/compositor/compositor_morphological_distance_threshold.glsl shaders/compositor/compositor_morphological_step.glsl + shaders/compositor/compositor_normalize.glsl shaders/compositor/compositor_parallel_reduction.glsl shaders/compositor/compositor_projector_lens_distortion.glsl shaders/compositor/compositor_realize_on_domain.glsl @@ -357,6 +393,8 @@ set(GLSL_SRC shaders/compositor/compositor_split_viewer.glsl shaders/compositor/compositor_symmetric_blur.glsl shaders/compositor/compositor_symmetric_separable_blur.glsl + shaders/compositor/compositor_tone_map_photoreceptor.glsl + shaders/compositor/compositor_tone_map_simple.glsl shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl shaders/compositor/library/gpu_shader_compositor_blur_common.glsl @@ -606,6 +644,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/gpu_shader_3D_smooth_color_info.hh shaders/infos/gpu_shader_3D_uniform_color_info.hh shaders/infos/gpu_shader_gpencil_stroke_info.hh + shaders/infos/gpu_shader_icon_info.hh shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh shaders/infos/gpu_shader_keyframe_shape_info.hh shaders/infos/gpu_shader_line_dashed_uniform_color_info.hh @@ -631,6 +670,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_morphological_distance_info.hh shaders/compositor/infos/compositor_morphological_distance_threshold_info.hh shaders/compositor/infos/compositor_morphological_step_info.hh + shaders/compositor/infos/compositor_normalize_info.hh shaders/compositor/infos/compositor_parallel_reduction_info.hh shaders/compositor/infos/compositor_projector_lens_distortion_info.hh shaders/compositor/infos/compositor_realize_on_domain_info.hh @@ -639,6 +679,8 @@ set(SRC_SHADER_CREATE_INFOS shaders/compositor/infos/compositor_split_viewer_info.hh shaders/compositor/infos/compositor_symmetric_blur_info.hh shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh + shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh + shaders/compositor/infos/compositor_tone_map_simple_info.hh ) set(SRC_SHADER_CREATE_INFOS_MTL diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index b59ea9e55d2..ac82774039a 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -21,6 +21,8 @@ extern "C" { * automatically initializes the back-end, and #GPU_context_discard frees it when there * are no more contexts. */ bool GPU_backend_supported(void); +void GPU_backend_type_selection_set(const eGPUBackendType backend); +eGPUBackendType GPU_backend_type_selection_get(void); eGPUBackendType GPU_backend_get_type(void); /** Opaque type hiding blender::gpu::Context. */ diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index bdb384c16f1..917407eece3 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -47,6 +47,9 @@ typedef struct GPUOffScreen GPUOffScreen; GPUFrameBuffer *GPU_framebuffer_create(const char *name); void GPU_framebuffer_free(GPUFrameBuffer *fb); void GPU_framebuffer_bind(GPUFrameBuffer *fb); + +const char *GPU_framebuffer_get_name(GPUFrameBuffer *fb); + /** * Workaround for binding a SRGB frame-buffer without doing the SRGB transform. */ diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h index b63fe4c0580..657b45df1a5 100644 --- a/source/blender/gpu/GPU_platform.h +++ b/source/blender/gpu/GPU_platform.h @@ -16,6 +16,7 @@ typedef enum eGPUBackendType { GPU_BACKEND_NONE = 0, GPU_BACKEND_OPENGL = 1 << 0, GPU_BACKEND_METAL = 1 << 1, + GPU_BACKEND_VULKAN = 1 << 3, GPU_BACKEND_ANY = 0xFFFFFFFFu } eGPUBackendType; diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 3f35db42eb9..1148207fc57 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -209,6 +209,10 @@ typedef enum eGPUBuiltinShader { GPU_SHADER_KEYFRAME_SHAPE, GPU_SHADER_SIMPLE_LIGHTING, /** + * Draw an icon, leaving a semi-transparent rectangle on top of the icon. + */ + GPU_SHADER_ICON, + /** * Take a 2D position and color for each vertex with linear interpolation in window space. * * \param color: in vec4 diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 48d7b2019c5..7e94538892a 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -33,6 +33,9 @@ # include "gl_backend.hh" # include "gl_context.hh" #endif +#ifdef WITH_VULKAN_BACKEND +# include "vk_backend.hh" +#endif #ifdef WITH_METAL_BACKEND # include "mtl_backend.hh" #endif @@ -223,9 +226,19 @@ void GPU_render_step() /* NOTE: To enable Metal API, we need to temporarily change this to `GPU_BACKEND_METAL`. * Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL: * `m_useMetalForRendering = true`. */ -static const eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL; +static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL; static GPUBackend *g_backend = nullptr; +void GPU_backend_type_selection_set(const eGPUBackendType backend) +{ + g_backend_type = backend; +} + +eGPUBackendType GPU_backend_type_selection_get() +{ + return g_backend_type; +} + bool GPU_backend_supported(void) { switch (g_backend_type) { @@ -235,6 +248,12 @@ bool GPU_backend_supported(void) #else return false; #endif + case GPU_BACKEND_VULKAN: +#ifdef WITH_VULKAN_BACKEND + return true; +#else + return false; +#endif case GPU_BACKEND_METAL: #ifdef WITH_METAL_BACKEND return MTLBackend::metal_is_supported(); @@ -258,6 +277,11 @@ static void gpu_backend_create() g_backend = new GLBackend; break; #endif +#ifdef WITH_VULKAN_BACKEND + case GPU_BACKEND_VULKAN: + g_backend = new VKBackend; + break; +#endif #ifdef WITH_METAL_BACKEND case GPU_BACKEND_METAL: g_backend = new MTLBackend; diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index 6528f39d4ec..5b50fd66196 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -238,6 +238,11 @@ void GPU_framebuffer_free(GPUFrameBuffer *gpu_fb) delete unwrap(gpu_fb); } +const char *GPU_framebuffer_get_name(GPUFrameBuffer *gpu_fb) +{ + return unwrap(gpu_fb)->name_get(); +} + /* ---------- Binding ----------- */ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb) diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh index 76e816e7f65..cb7fd62445c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer_private.hh +++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh @@ -95,11 +95,6 @@ class FrameBuffer { #endif public: - /* Reference of a pointer that needs to be cleaned when deallocating the frame-buffer. - * Points to #BPyGPUFrameBuffer::fb */ - void **ref = nullptr; - - public: FrameBuffer(const char *name); virtual ~FrameBuffer(); @@ -209,6 +204,11 @@ class FrameBuffer { { return attachments_[GPU_FB_COLOR_ATTACHMENT0 + slot].tex; }; + + inline const char *const name_get() const + { + return name_; + }; }; /* Syntactic sugar. */ diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 3b4accf9cc5..81c0a65bb7c 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -45,7 +45,7 @@ void immBindShader(GPUShader *shader) BLI_assert(imm->shader == nullptr); imm->shader = shader; - imm->builtin_shader_bound = GPU_SHADER_TEXT; /* Default value. */ + imm->builtin_shader_bound = std::nullopt; if (!imm->vertex_format.packed) { VertexFormat_pack(&imm->vertex_format); @@ -125,9 +125,12 @@ static void wide_line_workaround_start(GPUPrimType prim_type) /* No need to change the shader. */ return; } + if (!imm->builtin_shader_bound) { + return; + } eGPUBuiltinShader polyline_sh; - switch (imm->builtin_shader_bound) { + switch (*imm->builtin_shader_bound) { case GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR: polyline_sh = GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR; break; @@ -180,8 +183,8 @@ static void wide_line_workaround_end() } immUnbindProgram(); - immBindBuiltinProgram(imm->prev_builtin_shader); - imm->prev_builtin_shader = GPU_SHADER_TEXT; + immBindBuiltinProgram(*imm->prev_builtin_shader); + imm->prev_builtin_shader = std::nullopt; } } diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh index 74ebbdc7ae3..c4e11e7082b 100644 --- a/source/blender/gpu/intern/gpu_immediate_private.hh +++ b/source/blender/gpu/intern/gpu_immediate_private.hh @@ -9,6 +9,8 @@ #pragma once +#include <optional> + #include "GPU_batch.h" #include "GPU_primitive.h" #include "GPU_shader.h" @@ -42,9 +44,9 @@ class Immediate { /** Wide Line workaround. */ /** Previously bound shader to restore after drawing. */ - eGPUBuiltinShader prev_builtin_shader = GPU_SHADER_TEXT; - /** Builtin shader index. Used to test if the workaround can be done. */ - eGPUBuiltinShader builtin_shader_bound = GPU_SHADER_TEXT; + std::optional<eGPUBuiltinShader> prev_builtin_shader; + /** Builtin shader index. Used to test if the line width workaround can be done. */ + std::optional<eGPUBuiltinShader> builtin_shader_bound; /** Uniform color: Kept here to update the wide-line shader just before #immBegin. */ float uniform_color[4]; diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc index 3aa2963ecd0..abb45ca074a 100644 --- a/source/blender/gpu/intern/gpu_shader_builder.cc +++ b/source/blender/gpu/intern/gpu_shader_builder.cc @@ -15,6 +15,8 @@ #include "GPU_init_exit.h" #include "gpu_shader_create_info_private.hh" +#include "BLI_vector.hh" + #include "CLG_log.h" namespace blender::gpu::shader_builder { @@ -41,6 +43,22 @@ void ShaderBuilder::init() CLG_init(); GHOST_GLSettings glSettings = {0}; + switch (GPU_backend_type_selection_get()) { + case GPU_BACKEND_OPENGL: + glSettings.context_type = GHOST_kDrawingContextTypeOpenGL; + break; + +#ifdef WITH_METAL_BACKEND + case GPU_BACKEND_METAL: + glSettings.context_type = GHOST_kDrawingContextTypeMetal; + break; +#endif + + default: + BLI_assert_unreachable(); + break; + } + ghost_system_ = GHOST_CreateSystem(); ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings); GHOST_ActivateOpenGLContext(ghost_context_); @@ -73,13 +91,32 @@ int main(int argc, const char *argv[]) int exit_code = 0; - blender::gpu::shader_builder::ShaderBuilder builder; - builder.init(); - if (!builder.bake_create_infos()) { - exit_code = 1; + struct NamedBackend { + std::string name; + eGPUBackendType backend; + }; + + blender::Vector<NamedBackend> backends_to_validate; + backends_to_validate.append({"OpenGL", GPU_BACKEND_OPENGL}); +#ifdef WITH_METAL_BACKEND + backends_to_validate.append({"Metal", GPU_BACKEND_METAL}); +#endif + for (NamedBackend &backend : backends_to_validate) { + GPU_backend_type_selection_set(backend.backend); + if (!GPU_backend_supported()) { + printf("%s isn't supported on this platform. Shader compilation is skipped\n", + backend.name.c_str()); + continue; + } + blender::gpu::shader_builder::ShaderBuilder builder; + builder.init(); + if (!builder.bake_create_infos()) { + printf("Shader compilation failed for %s backend\n", backend.name.c_str()); + exit_code = 1; + } + builder.exit(); } - builder.exit(); - exit(exit_code); + exit(exit_code); return exit_code; } diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index 7a06ede5c6d..65bda7ba858 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -46,6 +46,15 @@ void IMB_freeImBuf(ImBuf * /*ibuf*/) BLI_assert_unreachable(); } +struct ImBuf *IMB_allocImBuf(unsigned int /*x*/, + unsigned int /*y*/, + unsigned char /*planes*/, + unsigned int /*flags*/) +{ + BLI_assert_unreachable(); + return nullptr; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index 8a6586e06f6..470643ba863 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -153,6 +153,11 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .create_info = "gpu_shader_2D_diag_stripes", }, + [GPU_SHADER_ICON] = + { + .name = "GPU_SHADER_ICON", + .create_info = "gpu_shader_icon", + }, [GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] = { .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE", diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 2ad31183206..124b1751b96 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -588,7 +588,7 @@ inline eGPUFrameBufferBits to_framebuffer_bits(eGPUTextureFormat tex_format) static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format) { - if (format->attr_len > 1 || format->attr_len == 0) { + if (format->attr_len == 0) { BLI_assert_msg(0, "Incorrect vertex format for buffer texture"); return GPU_DEPTH_COMPONENT24; } diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc index b30e3c358c8..76d95ac1b55 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.cc +++ b/source/blender/gpu/intern/gpu_vertex_format.cc @@ -361,8 +361,12 @@ void VertexFormat_texture_buffer_pack(GPUVertFormat *format) * minimum per-vertex stride, which mandates 4-byte alignment in Metal. * This additional alignment padding caused smaller data types, e.g. U16, * to mis-align. */ - BLI_assert_msg(format->attr_len == 1, - "Texture buffer mode should only use a single vertex attribute."); + for (int i = 0; i < format->attr_len; i++) { + /* The buffer texture setup uses the first attribute for type and size. + * Make sure all attributes use the same size. */ + BLI_assert_msg(format->attrs[i].size == format->attrs[0].size, + "Texture buffer mode should only use a attributes with the same size."); + } /* Pack vertex format without minimum stride, as this is not required by texture buffers. */ VertexFormat_pack_impl(format, 1); diff --git a/source/blender/gpu/metal/mtl_batch.mm b/source/blender/gpu/metal/mtl_batch.mm index e9804d4be77..988fb9b793b 100644 --- a/source/blender/gpu/metal/mtl_batch.mm +++ b/source/blender/gpu/metal/mtl_batch.mm @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup gpu @@ -68,7 +69,7 @@ void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_ensure() } } - /* Initialise cache if not ready. */ + /* Initialize cache if not ready. */ if (cache_context_ == nullptr) { this->vertex_descriptor_cache_init(MTLContext::get()); } @@ -188,7 +189,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts, buffer_stride); } else { - /* Ensure stride is correct for de-interlevaed attributes. */ + /* Ensure stride is correct for de-interleaved attributes. */ desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride; } @@ -278,7 +279,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts, * elements). * * Certain conversion cannot be performed however, and in these cases, we need to - * instruct the shader to generate a specialised version with a conversion routine upon + * instruct the shader to generate a specialized version with a conversion routine upon * attribute read. * - This handles cases such as conversion between types e.g. Integer to float without * normalization. @@ -310,7 +311,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts, * This then controls how a given attribute is interpreted. The data will be read * as specified and then converted appropriately to the correct form. * - * e.g. if `GPU_FETCH_INT_TO_FLOAT` is specified, the specialised read-routine + * e.g. if `GPU_FETCH_INT_TO_FLOAT` is specified, the specialized read-routine * in the shader will read the data as an int, and cast this to floating point * representation. (Rather than reading the source data as float). * @@ -403,7 +404,7 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi active_shader_ = (shader) ? static_cast<MTLShader *>(unwrap(shader)) : nullptr; if (active_shader_ == nullptr || !active_shader_->is_valid()) { - /* Skip drawing if there is no vaid Metal shader. + /* Skip drawing if there is no valid Metal shader. * This will occur if the path through which the shader is prepared * is invalid (e.g. Python without create-info), or, the source shader uses a geometry pass. */ BLI_assert_msg(false, "No valid Metal shader!"); @@ -455,7 +456,7 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi /* Fetch RenderPassState to enable resource binding for active pass. */ MTLRenderPassState &rps = ctx->main_command_buffer.get_render_pass_state(); - /* Debug Check: Ensure Framebuffer instance is not dirty. */ + /* Debug Check: Ensure Frame-buffer instance is not dirty. */ BLI_assert(!ctx->main_command_buffer.get_active_framebuffer()->get_dirty()); /* Bind Shader. */ @@ -495,8 +496,8 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi if (mtl_elem != nullptr) { - /* Fetch index buffer. This function can situationally return an optimised - * index buffer of a different primtiive type. If this is the case, `final_prim_type` + /* Fetch index buffer. This function can situationally return an optimized + * index buffer of a different primitive type. If this is the case, `final_prim_type` * and `v_count` will be updated with the new format. * NOTE: For indexed rendering, v_count represents the number of indices. */ idx_buffer = mtl_elem->get_index_buffer(final_prim_type, v_count); @@ -594,8 +595,10 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings( desc.reset_vertex_descriptor(); /* Fetch Vertex and Instance Buffers. */ - Span<MTLVertBuf *> mtl_verts(reinterpret_cast<MTLVertBuf **>(this->verts), GPU_BATCH_VBO_MAX_LEN); - Span<MTLVertBuf *> mtl_inst(reinterpret_cast<MTLVertBuf **>(this->inst), GPU_BATCH_INST_VBO_MAX_LEN); + Span<MTLVertBuf *> mtl_verts(reinterpret_cast<MTLVertBuf **>(this->verts), + GPU_BATCH_VBO_MAX_LEN); + Span<MTLVertBuf *> mtl_inst(reinterpret_cast<MTLVertBuf **>(this->inst), + GPU_BATCH_INST_VBO_MAX_LEN); /* SSBO Vertex fetch also passes vertex descriptor information into the shader. */ if (active_shader_->get_uses_ssbo_vertex_fetch()) { @@ -671,7 +674,7 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings( } } - /* Extract Vertex attribues (First-bound vertex buffer takes priority). */ + /* Extract Vertex attributes (First-bound vertex buffer takes priority). */ for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) { if (mtl_verts[v] != NULL) { MTL_LOG_INFO(" -- [Batch] Checking bindings for bound vertex buffer %p\n", mtl_verts[v]); @@ -829,7 +832,7 @@ void MTLBatch::draw_advanced(int v_first, int v_count, int i_first, int i_count) "Index offset is not 2/4-byte aligned as per METAL spec"); /* Fetch index buffer. May return an index buffer of a differing format, - * if index buffer optimisation is used. In these cases, final_prim_type and + * if index buffer optimization is used. In these cases, final_prim_type and * index_count get updated with the new properties. */ GPUPrimType final_prim_type = this->prim_type; uint index_count = v_count; diff --git a/source/blender/gpu/metal/mtl_drawlist.mm b/source/blender/gpu/metal/mtl_drawlist.mm index 76e2abb4ea6..99194d2b72c 100644 --- a/source/blender/gpu/metal/mtl_drawlist.mm +++ b/source/blender/gpu/metal/mtl_drawlist.mm @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /** \file * \ingroup gpu * @@ -151,7 +153,7 @@ void MTLDrawList::submit() { /* Metal does not support MDI from the host side, but we still benefit from only executing the * batch bind a single time, rather than per-draw. - * NOTE(Metal): Consider using MTLIndirectCommandBuffer to achieve similar behaviour. */ + * NOTE(Metal): Consider using #MTLIndirectCommandBuffer to achieve similar behavior. */ if (command_len_ == 0) { return; } @@ -192,12 +194,12 @@ void MTLDrawList::submit() /* Common properties. */ MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(batch_->prim_type); - /* Execute multidraw indirect. */ + /* Execute multi-draw indirect. */ if (can_use_MDI && false) { /* Metal Doesn't support MDI -- Singular Indirect draw calls are supported, - * but Multidraw is not. - * TODO(Metal): Consider using IndirectCommandBuffers to provide similar - * behaviour. */ + * but Multi-draw is not. + * TODO(Metal): Consider using #IndirectCommandBuffers to provide similar + * behavior. */ } else { @@ -214,7 +216,7 @@ void MTLDrawList::submit() uint32_t index_count = cmd->indexCount; /* Fetch index buffer. May return an index buffer of a differing format, - * if index buffer optimisation is used. In these cases, mtl_prim_type and + * if index buffer optimization is used. In these cases, mtl_prim_type and * index_count get updated with the new properties. */ GPUPrimType final_prim_type = batch_->prim_type; id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count); diff --git a/source/blender/gpu/metal/mtl_shader_generator.hh b/source/blender/gpu/metal/mtl_shader_generator.hh index 43890ca0170..63e2e6d5924 100644 --- a/source/blender/gpu/metal/mtl_shader_generator.hh +++ b/source/blender/gpu/metal/mtl_shader_generator.hh @@ -497,7 +497,7 @@ inline std::string get_stage_class_name(ShaderStage stage) inline bool is_builtin_type(std::string type) { /* Add Types as needed. */ - /* TODO(Metal): Consider replacing this with a switch and constexpr hash and switch. + /* TODO(Metal): Consider replacing this with a switch and `constexpr` hash and switch. * Though most efficient and maintainable approach to be determined. */ static std::map<std::string, eMTLDataType> glsl_builtin_types = { {"float", MTL_DATATYPE_FLOAT}, diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm index 4931f8a4f52..29dcc8d32ee 100644 --- a/source/blender/gpu/metal/mtl_texture.mm +++ b/source/blender/gpu/metal/mtl_texture.mm @@ -1510,7 +1510,7 @@ bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo) texture_descriptor_.mipmapLevelCount = mtl_max_mips_; texture_descriptor_.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite | - MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimise usage flags. */ + MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */ texture_descriptor_.storageMode = [source_buffer storageMode]; texture_descriptor_.sampleCount = 1; texture_descriptor_.cpuCacheMode = [source_buffer cpuCacheMode]; diff --git a/source/blender/gpu/metal/mtl_texture_util.mm b/source/blender/gpu/metal/mtl_texture_util.mm index 5ed7659f260..33a62e2e3ef 100644 --- a/source/blender/gpu/metal/mtl_texture_util.mm +++ b/source/blender/gpu/metal/mtl_texture_util.mm @@ -34,7 +34,7 @@ MTLPixelFormat gpu_texture_format_to_metal(eGPUTextureFormat tex_format) { switch (tex_format) { - /* Formats texture & renderbuffer. */ + /* Formats texture & render-buffer. */ case GPU_RGBA8UI: return MTLPixelFormatRGBA8Uint; case GPU_RGBA8I: diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index ff8867fe3e6..28105e326ee 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -272,8 +272,8 @@ void GLBatch::bind(int i_first) #if GPU_TRACK_INDEX_RANGE /* Can be removed if GL 4.3 is required. */ - if (!GLContext::fixed_restart_index_support && (elem != nullptr)) { - glPrimitiveRestartIndex(this->elem_()->restart_index()); + if (!GLContext::fixed_restart_index_support) { + glPrimitiveRestartIndex((elem != nullptr) ? this->elem_()->restart_index() : 0xFFFFFFFFu); } #endif diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index c9432fca561..ef97d74bf81 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -200,6 +200,9 @@ static Type gpu_type_from_gl_type(int gl_type) GLShaderInterface::GLShaderInterface(GLuint program) { + GLuint last_program; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program); + /* Necessary to make #glUniform works. */ glUseProgram(program); @@ -385,6 +388,8 @@ GLShaderInterface::GLShaderInterface(GLuint program) // this->debug_print(); this->sort_inputs(); + + glUseProgram(last_program); } GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info) @@ -442,6 +447,9 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI uint32_t name_buffer_offset = 0; /* Necessary to make #glUniform works. TODO(fclem) Remove. */ + GLuint last_program; + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *)&last_program); + glUseProgram(program); /* Attributes */ @@ -552,6 +560,8 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI this->sort_inputs(); // this->debug_print(); + + glUseProgram(last_program); } GLShaderInterface::~GLShaderInterface() diff --git a/source/blender/gpu/shaders/compositor/compositor_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_blur.glsl index 4f981c84f59..c7ac620f99b 100644 --- a/source/blender/gpu/shaders/compositor/compositor_blur.glsl +++ b/source/blender/gpu/shaders/compositor/compositor_blur.glsl @@ -18,13 +18,24 @@ vec4 load_input(ivec2 texel) } /* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from - * the weights texture, where the texel (0, 0) is considered the center of weights texture. */ + * the weights texture, where the given texel (0, 0) corresponds the center of weights texture. + * Note that we load the weights texture inverted along both directions to maintain the shape of + * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D + * weights texture whose right half is all ones and whose left half is all zeros. Further, consider + * that we are blurring a single white pixel on a black background. When computing the value of a + * pixel that is to the right of the white pixel, the white pixel will be in the left region of the + * search window, and consequently, without inversion, a zero will be sampled from the left side of + * the weights texture and result will be zero. However, what we expect is that pixels to the right + * of the white pixel will be white, that is, they should sample a weight of 1 from the right side + * of the weights texture, hence the need for inversion. */ vec4 load_weight(ivec2 texel) { - /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper - * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the - * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */ - return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1)); + /* Add the radius to transform the texel into the range [0, radius * 2], with an additional 0.5 + * to sample at the center of the pixels, then divide by the upper bound plus one to transform + * the texel into the normalized range [0, 1] needed to sample the weights sampler. Finally, + * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as + * mentioned in the function description. */ + return texture(weights_tx, 1.0 - ((texel + vec2(radius + 0.5)) / (radius * 2 + 1))); } void main() diff --git a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl index e7e5aac12a5..9383bbf9825 100644 --- a/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl +++ b/source/blender/gpu/shaders/compositor/compositor_blur_variable_size.glsl @@ -2,7 +2,16 @@ #pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) /* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from - * the weights texture, where the texel (0, 0) is considered the center of weights texture. */ + * the weights texture, where the given texel (0, 0) corresponds the center of weights texture. + * Note that we load the weights texture inverted along both directions to maintain the shape of + * the weights if it was not symmetrical. To understand why inversion makes sense, consider a 1D + * weights texture whose right half is all ones and whose left half is all zeros. Further, consider + * that we are blurring a single white pixel on a black background. When computing the value of a + * pixel that is to the right of the white pixel, the white pixel will be in the left region of the + * search window, and consequently, without inversion, a zero will be sampled from the left side of + * the weights texture and result will be zero. However, what we expect is that pixels to the right + * of the white pixel will be white, that is, they should sample a weight of 1 from the right side + * of the weights texture, hence the need for inversion. */ vec4 load_weight(ivec2 texel, float radius) { /* The center zero texel is always assigned a unit weight regardless of the corresponding weight @@ -12,10 +21,12 @@ vec4 load_weight(ivec2 texel, float radius) return vec4(1.0); } - /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper - * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the - * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */ - return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1)); + /* Add the radius to transform the texel into the range [0, radius * 2], with an additional 0.5 + * to sample at the center of the pixels, then divide by the upper bound plus one to transform + * the texel into the normalized range [0, 1] needed to sample the weights sampler. Finally, + * invert the textures coordinates by subtracting from 1 to maintain the shape of the weights as + * mentioned in the function description. */ + return texture(weights_tx, 1.0 - ((texel + vec2(radius + 0.5)) / (radius * 2 + 1))); } void main() diff --git a/source/blender/gpu/shaders/compositor/compositor_normalize.glsl b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl new file mode 100644 index 00000000000..53dfeb01730 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_normalize.glsl @@ -0,0 +1,10 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + float value = texture_load(input_tx, texel).x; + float normalized_value = (value - minimum) * scale; + float clamped_value = clamp(normalized_value, 0.0, 1.0); + imageStore(output_img, texel, vec4(clamped_value)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl new file mode 100644 index 00000000000..167006585ca --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_photoreceptor.glsl @@ -0,0 +1,22 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +/* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and (7) + * from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor + * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */ +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + vec4 input_color = texture_load(input_tx, texel); + float input_luminance = dot(input_color.rgb, luminance_coefficients); + + /* Trilinear interpolation between equations (6) and (7) from Reinhard's 2005 paper. */ + vec4 local_adaptation_level = mix(vec4(input_luminance), input_color, chromatic_adaptation); + vec4 adaptation_level = mix(global_adaptation_level, local_adaptation_level, light_adaptation); + + /* Equation (1) from Reinhard's 2005 paper, assuming Vmax is 1. */ + vec4 semi_saturation = pow(intensity * adaptation_level, vec4(contrast)); + vec4 tone_mapped_color = input_color / (input_color + semi_saturation); + + imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a)); +} diff --git a/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl new file mode 100644 index 00000000000..ce42d021dd1 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/compositor_tone_map_simple.glsl @@ -0,0 +1,26 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) + +/* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction + * for digital images." Proceedings of the 29th annual conference on Computer graphics and + * interactive techniques. 2002. */ +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + + vec4 input_color = texture_load(input_tx, texel); + + /* Equation (2) from Reinhard's 2002 paper. */ + vec4 scaled_color = input_color * luminance_scale; + + /* Equation (3) from Reinhard's 2002 paper, but with the 1 replaced with the blend factor for + * more flexibility. See ToneMapOperation::compute_luminance_scale_blend_factor. */ + vec4 denominator = luminance_scale_blend_factor + scaled_color; + vec4 tone_mapped_color = safe_divide(scaled_color, denominator); + + if (inverse_gamma != 0.0) { + tone_mapped_color = pow(max(tone_mapped_color, vec4(0.0)), vec4(inverse_gamma)); + } + + imageStore(output_img, texel, vec4(tone_mapped_color.rgb, input_color.a)); +} diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh new file mode 100644 index 00000000000..02fdc424014 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_normalize_info.hh @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_normalize) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "minimum") + .push_constant(Type::FLOAT, "scale") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_normalize.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh index 2e661f280af..e2252b14758 100644 --- a/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh +++ b/source/blender/gpu/shaders/compositor/infos/compositor_parallel_reduction_info.hh @@ -12,14 +12,17 @@ GPU_SHADER_CREATE_INFO(compositor_parallel_reduction_shared) * Sum Reductions. */ -GPU_SHADER_CREATE_INFO(compositor_sum_float_shared) +GPU_SHADER_CREATE_INFO(compositor_sum_shared) .additional_info("compositor_parallel_reduction_shared") - .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") - .define("TYPE", "float") .define("IDENTITY", "vec4(0.0)") - .define("LOAD(value)", "value.x") .define("REDUCE(lhs, rhs)", "lhs + rhs"); +GPU_SHADER_CREATE_INFO(compositor_sum_float_shared) + .additional_info("compositor_sum_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .define("TYPE", "float") + .define("LOAD(value)", "value.x"); + GPU_SHADER_CREATE_INFO(compositor_sum_red) .additional_info("compositor_sum_float_shared") .define("INITIALIZE(value)", "value.r") @@ -41,6 +44,20 @@ GPU_SHADER_CREATE_INFO(compositor_sum_luminance) .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") .do_static_compilation(true); +GPU_SHADER_CREATE_INFO(compositor_sum_log_luminance) + .additional_info("compositor_sum_float_shared") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("INITIALIZE(value)", "log(max(dot(value.rgb, luminance_coefficients), 1e-5))") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_sum_color) + .additional_info("compositor_sum_shared") + .image(0, GPU_RGBA32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .define("TYPE", "vec4") + .define("INITIALIZE(value)", "value") + .define("LOAD(value)", "value") + .do_static_compilation(true); + /* -------------------------------------------------------------------- * Sum Of Squared Difference Reductions. */ @@ -74,3 +91,59 @@ GPU_SHADER_CREATE_INFO(compositor_sum_luminance_squared_difference) .push_constant(Type::VEC3, "luminance_coefficients") .define("INITIALIZE(value)", "pow(dot(value.rgb, luminance_coefficients) - subtrahend, 2.0)") .do_static_compilation(true); + +/* -------------------------------------------------------------------- + * Maximum Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_maximum_luminance) + .additional_info("compositor_parallel_reduction_shared") + .typedef_source("common_math_lib.glsl") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("TYPE", "float") + .define("IDENTITY", "vec4(FLT_MIN)") + .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "max(lhs, rhs)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_maximum_float_in_range) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::FLOAT, "lower_bound") + .push_constant(Type::FLOAT, "upper_bound") + .define("TYPE", "float") + .define("IDENTITY", "vec4(lower_bound)") + .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : lower_bound") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "((rhs > lhs) && (rhs <= upper_bound)) ? rhs : lhs") + .do_static_compilation(true); + +/* -------------------------------------------------------------------- + * Minimum Reductions. + */ + +GPU_SHADER_CREATE_INFO(compositor_minimum_luminance) + .additional_info("compositor_parallel_reduction_shared") + .typedef_source("common_math_lib.glsl") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::VEC3, "luminance_coefficients") + .define("TYPE", "float") + .define("IDENTITY", "vec4(FLT_MAX)") + .define("INITIALIZE(value)", "dot(value.rgb, luminance_coefficients)") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "min(lhs, rhs)") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_minimum_float_in_range) + .additional_info("compositor_parallel_reduction_shared") + .image(0, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .push_constant(Type::FLOAT, "lower_bound") + .push_constant(Type::FLOAT, "upper_bound") + .define("TYPE", "float") + .define("IDENTITY", "vec4(upper_bound)") + .define("INITIALIZE(v)", "((v.x <= upper_bound) && (v.x >= lower_bound)) ? v.x : upper_bound") + .define("LOAD(value)", "value.x") + .define("REDUCE(lhs, rhs)", "((rhs < lhs) && (rhs >= lower_bound)) ? rhs : lhs") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh new file mode 100644 index 00000000000..a460c9d58a6 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_photoreceptor_info.hh @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_tone_map_photoreceptor) + .local_group_size(16, 16) + .push_constant(Type::VEC4, "global_adaptation_level") + .push_constant(Type::FLOAT, "contrast") + .push_constant(Type::FLOAT, "intensity") + .push_constant(Type::FLOAT, "chromatic_adaptation") + .push_constant(Type::FLOAT, "light_adaptation") + .push_constant(Type::VEC3, "luminance_coefficients") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_tone_map_photoreceptor.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh new file mode 100644 index 00000000000..2b220af9460 --- /dev/null +++ b/source/blender/gpu/shaders/compositor/infos/compositor_tone_map_simple_info.hh @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_tone_map_simple) + .local_group_size(16, 16) + .push_constant(Type::FLOAT, "luminance_scale") + .push_constant(Type::FLOAT, "luminance_scale_blend_factor") + .push_constant(Type::FLOAT, "inverse_gamma") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_tone_map_simple.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl new file mode 100644 index 00000000000..4452349f23c --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl @@ -0,0 +1,42 @@ +/** + * Draw the icons, leaving a semi-transparent rectangle on top of the icon. + * + * The top-left corner of the rectangle is rounded and drawned with anti-alias. + * The anti-alias is done by transitioning from the outer to the inner radius of + * the rounded corner, and the rectangle sides. + */ + +void main() +{ + /* Top-left rounded corner parameters. */ + const float circle_radius_outer = 0.1; + const float circle_radius_inner = 0.075; + + /** + * Add a bit transparency to see a bit of the icon, without + * getting on the way of readability. */ + const float mask_transparency = 0.25; + + vec2 circle_center = vec2(circle_radius_outer - text_width, 0.5); + fragColor = texture(image, texCoord_interp) * color; + + /* radius in icon space (1 is the icon width). */ + float radius = length(mask_coord_interp - circle_center); + float mask = smoothstep(circle_radius_inner, circle_radius_outer, radius); + + bool lower_half = mask_coord_interp.y < circle_center.y; + bool right_half = mask_coord_interp.x > circle_center.x; + + if (right_half && mask_coord_interp.y < circle_center.y + circle_radius_outer) { + mask = smoothstep(circle_center.y + circle_radius_inner, + circle_center.y + circle_radius_outer, + mask_coord_interp.y); + } + if (lower_half && mask_coord_interp.x > circle_center.x - circle_radius_outer) { + mask = smoothstep(circle_center.x - circle_radius_inner, + circle_center.x - circle_radius_outer, + mask_coord_interp.x); + } + + fragColor = mix(vec4(0.0), fragColor, max(mask_transparency, mask)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl new file mode 100644 index 00000000000..25f64bfe0b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_icon_vert.glsl @@ -0,0 +1,37 @@ +/** + * Simple shader that just draw one icon at the specified location + * does not need any vertex input (producing less call to immBegin/End) + */ + +void main() +{ + vec2 uv; + vec2 co; + + if (gl_VertexID == 0) { + co = rect_geom.xw; + uv = rect_icon.xw; + mask_coord_interp = vec2(0, 1); + } + else if (gl_VertexID == 1) { + co = rect_geom.xy; + uv = rect_icon.xy; + mask_coord_interp = vec2(0, 0); + } + else if (gl_VertexID == 2) { + co = rect_geom.zw; + uv = rect_icon.zw; + mask_coord_interp = vec2(1, 1); + } + else { + co = rect_geom.zy; + uv = rect_icon.zy; + mask_coord_interp = vec2(1, 0); + } + + /* Put origin in lower right corner. */ + mask_coord_interp.x -= 1; + + gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f); + texCoord_interp = uv; +} diff --git a/source/blender/gpu/shaders/infos/gpu_interface_info.hh b/source/blender/gpu/shaders/infos/gpu_interface_info.hh index d77c65e48a7..060def16f81 100644 --- a/source/blender/gpu/shaders/infos/gpu_interface_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_interface_info.hh @@ -18,3 +18,6 @@ GPU_SHADER_INTERFACE_INFO(smooth_radii_outline_iface, "").smooth(Type::VEC4, "ra GPU_SHADER_INTERFACE_INFO(flat_color_smooth_tex_coord_interp_iface, "") .flat(Type::VEC4, "finalColor") .smooth(Type::VEC2, "texCoord_interp"); +GPU_SHADER_INTERFACE_INFO(smooth_icon_interp_iface, "") + .smooth(Type::VEC2, "texCoord_interp") + .smooth(Type::VEC2, "mask_coord_interp"); diff --git a/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh new file mode 100644 index 00000000000..3d4077bdb09 --- /dev/null +++ b/source/blender/gpu/shaders/infos/gpu_shader_icon_info.hh @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "gpu_interface_info.hh" +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(gpu_shader_icon) + .vertex_out(smooth_icon_interp_iface) + .fragment_out(0, Type::VEC4, "fragColor") + .push_constant(Type::MAT4, "ModelViewProjectionMatrix") + .push_constant(Type::VEC4, "color") + .push_constant(Type::VEC4, "rect_icon") + .push_constant(Type::VEC4, "rect_geom") + .push_constant(Type::FLOAT, "text_width") + .sampler(0, ImageType::FLOAT_2D, "image") + .vertex_source("gpu_shader_icon_vert.glsl") + .fragment_source("gpu_shader_icon_frag.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc new file mode 100644 index 00000000000..00bc43333d6 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_backend.hh" + +#include "vk_batch.hh" +#include "vk_context.hh" +#include "vk_drawlist.hh" +#include "vk_framebuffer.hh" +#include "vk_index_buffer.hh" +#include "vk_query.hh" +#include "vk_shader.hh" +#include "vk_storage_buffer.hh" +#include "vk_texture.hh" +#include "vk_uniform_buffer.hh" +#include "vk_vertex_buffer.hh" + +namespace blender::gpu { + +void VKBackend::delete_resources() +{ +} + +void VKBackend::samplers_update() +{ +} + +void VKBackend::compute_dispatch(int /*groups_x_len*/, int /*groups_y_len*/, int /*groups_z_len*/) +{ +} + +void VKBackend::compute_dispatch_indirect(StorageBuf * /*indirect_buf*/) +{ +} + +Context *VKBackend::context_alloc(void * /*ghost_window*/, void * /*ghost_context*/) +{ + return new VKContext(); +} + +Batch *VKBackend::batch_alloc() +{ + return new VKBatch(); +} + +DrawList *VKBackend::drawlist_alloc(int /*list_length*/) +{ + return new VKDrawList(); +} + +FrameBuffer *VKBackend::framebuffer_alloc(const char *name) +{ + return new VKFrameBuffer(name); +} + +IndexBuf *VKBackend::indexbuf_alloc() +{ + return new VKIndexBuffer(); +} + +QueryPool *VKBackend::querypool_alloc() +{ + return new VKQueryPool(); +} + +Shader *VKBackend::shader_alloc(const char *name) +{ + return new VKShader(name); +} + +Texture *VKBackend::texture_alloc(const char *name) +{ + return new VKTexture(name); +} + +UniformBuf *VKBackend::uniformbuf_alloc(int size, const char *name) +{ + return new VKUniformBuffer(size, name); +} + +StorageBuf *VKBackend::storagebuf_alloc(int size, GPUUsageType /*usage*/, const char *name) +{ + return new VKStorageBuffer(size, name); +} + +VertBuf *VKBackend::vertbuf_alloc() +{ + return new VKVertexBuffer(); +} + +void VKBackend::render_begin() +{ +} + +void VKBackend::render_end() +{ +} + +void VKBackend::render_step() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_backend.hh b/source/blender/gpu/vulkan/vk_backend.hh new file mode 100644 index 00000000000..549478586e8 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_backend.hh @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_backend.hh" + +namespace blender::gpu { + +class VKBackend : public GPUBackend { + public: + void delete_resources() override; + + void samplers_update() override; + void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override; + void compute_dispatch_indirect(StorageBuf *indirect_buf) override; + + Context *context_alloc(void *ghost_window, void *ghost_context) override; + + Batch *batch_alloc() override; + DrawList *drawlist_alloc(int list_length) override; + FrameBuffer *framebuffer_alloc(const char *name) override; + IndexBuf *indexbuf_alloc() override; + QueryPool *querypool_alloc() override; + Shader *shader_alloc(const char *name) override; + Texture *texture_alloc(const char *name) override; + UniformBuf *uniformbuf_alloc(int size, const char *name) override; + StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) override; + VertBuf *vertbuf_alloc() override; + + /* Render Frame Coordination -- + * Used for performing per-frame actions globally */ + void render_begin() override; + void render_end() override; + void render_step() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_batch.cc b/source/blender/gpu/vulkan/vk_batch.cc new file mode 100644 index 00000000000..a25f98a2e24 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_batch.cc @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_batch.hh" + +namespace blender::gpu { + +void VKBatch::draw(int /*v_first*/, int /*v_count*/, int /*i_first*/, int /*i_count*/) +{ +} + +void VKBatch::draw_indirect(GPUStorageBuf * /*indirect_buf*/, intptr_t /*offset*/) +{ +} + +void VKBatch::multi_draw_indirect(GPUStorageBuf * /*indirect_buf*/, + int /*count*/, + intptr_t /*offset*/, + intptr_t /*stride*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_batch.hh b/source/blender/gpu/vulkan/vk_batch.hh new file mode 100644 index 00000000000..0f6df41606d --- /dev/null +++ b/source/blender/gpu/vulkan/vk_batch.hh @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_batch_private.hh" + +namespace blender::gpu { + +class VKBatch : public Batch { + public: + void draw(int v_first, int v_count, int i_first, int i_count) override; + void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override; + void multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc new file mode 100644 index 00000000000..55b29ea4e2f --- /dev/null +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_context.hh" + +namespace blender::gpu { + +void VKContext::activate() +{ +} + +void VKContext::deactivate() +{ +} + +void VKContext::begin_frame() +{ +} + +void VKContext::end_frame() +{ +} + +void VKContext::flush() +{ +} + +void VKContext::finish() +{ +} + +void VKContext::memory_statistics_get(int * /*total_mem*/, int * /*free_mem*/) +{ +} + +void VKContext::debug_group_begin(const char *, int) +{ +} + +void VKContext::debug_group_end() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh new file mode 100644 index 00000000000..17292b891b6 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_context_private.hh" + +namespace blender::gpu { + +class VKContext : public Context { + public: + VKContext() + { + } + + void activate() override; + void deactivate() override; + void begin_frame() override; + void end_frame() override; + + void flush() override; + void finish() override; + + void memory_statistics_get(int *total_mem, int *free_mem) override; + + void debug_group_begin(const char *, int) override; + void debug_group_end() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_drawlist.cc b/source/blender/gpu/vulkan/vk_drawlist.cc new file mode 100644 index 00000000000..c8f3c736bb8 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_drawlist.cc @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_drawlist.hh" + +namespace blender::gpu { + +void VKDrawList::append(GPUBatch * /*batch*/, int /*i_first*/, int /*i_count*/) +{ +} + +void VKDrawList::submit() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_drawlist.hh b/source/blender/gpu/vulkan/vk_drawlist.hh new file mode 100644 index 00000000000..4707bf4bb26 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_drawlist.hh @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_drawlist_private.hh" + +namespace blender::gpu { + +class VKDrawList : public DrawList { + public: + void append(GPUBatch *batch, int i_first, int i_count) override; + void submit() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_framebuffer.cc b/source/blender/gpu/vulkan/vk_framebuffer.cc new file mode 100644 index 00000000000..48b0685bf38 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_framebuffer.cc @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_framebuffer.hh" + +namespace blender::gpu { + +void VKFrameBuffer::bind(bool /*enabled_srgb*/) +{ +} + +bool VKFrameBuffer::check(char /*err_out*/[256]) +{ + return false; +} + +void VKFrameBuffer::clear(eGPUFrameBufferBits /*buffers*/, + const float /*clear_col*/[4], + float /*clear_depth*/, + uint /*clear_stencil*/) +{ +} + +void VKFrameBuffer::clear_multi(const float (*/*clear_col*/)[4]) +{ +} + +void VKFrameBuffer::clear_attachment(GPUAttachmentType /*type*/, + eGPUDataFormat /*data_format*/, + const void * /*clear_value*/) +{ +} + +void VKFrameBuffer::attachment_set_loadstore_op(GPUAttachmentType /*type*/, + eGPULoadOp /*load_action*/, + eGPUStoreOp /*store_action*/) +{ +} + +void VKFrameBuffer::read(eGPUFrameBufferBits /*planes*/, + eGPUDataFormat /*format*/, + const int /*area*/[4], + int /*channel_len*/, + int /*slot*/, + void * /*r_data*/) +{ +} + +void VKFrameBuffer::blit_to(eGPUFrameBufferBits /*planes*/, + int /*src_slot*/, + FrameBuffer * /*dst*/, + int /*dst_slot*/, + int /*dst_offset_x*/, + int /*dst_offset_y*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_framebuffer.hh b/source/blender/gpu/vulkan/vk_framebuffer.hh new file mode 100644 index 00000000000..632d45ce709 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_framebuffer.hh @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_framebuffer_private.hh" + +namespace blender::gpu { + +class VKFrameBuffer : public FrameBuffer { + public: + VKFrameBuffer(const char *name) : FrameBuffer(name) + { + } + + void bind(bool enabled_srgb) override; + bool check(char err_out[256]) override; + void clear(eGPUFrameBufferBits buffers, + const float clear_col[4], + float clear_depth, + uint clear_stencil) override; + void clear_multi(const float (*clear_col)[4]) override; + void clear_attachment(GPUAttachmentType type, + eGPUDataFormat data_format, + const void *clear_value) override; + + void attachment_set_loadstore_op(GPUAttachmentType type, + eGPULoadOp load_action, + eGPUStoreOp store_action) override; + + void read(eGPUFrameBufferBits planes, + eGPUDataFormat format, + const int area[4], + int channel_len, + int slot, + void *r_data) override; + + void blit_to(eGPUFrameBufferBits planes, + int src_slot, + FrameBuffer *dst, + int dst_slot, + int dst_offset_x, + int dst_offset_y) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_index_buffer.cc b/source/blender/gpu/vulkan/vk_index_buffer.cc new file mode 100644 index 00000000000..119a617a159 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_index_buffer.cc @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_index_buffer.hh" + +namespace blender::gpu { + +void VKIndexBuffer::upload_data() +{ +} + +void VKIndexBuffer::bind_as_ssbo(uint /*binding*/) +{ +} + +const uint32_t *VKIndexBuffer::read() const +{ + return 0; +} + +void VKIndexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*data*/) +{ +} + +void VKIndexBuffer::strip_restart_indices() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_index_buffer.hh b/source/blender/gpu/vulkan/vk_index_buffer.hh new file mode 100644 index 00000000000..f002d5581c7 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_index_buffer.hh @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_index_buffer_private.hh" + +namespace blender::gpu { + +class VKIndexBuffer : public IndexBuf { + public: + void upload_data() override; + + void bind_as_ssbo(uint binding) override; + + const uint32_t *read() const override; + + void update_sub(uint start, uint len, const void *data) override; + + private: + void strip_restart_indices() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_query.cc b/source/blender/gpu/vulkan/vk_query.cc new file mode 100644 index 00000000000..e24fe54e5d0 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_query.cc @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_query.hh" + +namespace blender::gpu { + +void VKQueryPool::init(GPUQueryType /*type*/) +{ +} + +void VKQueryPool::begin_query() +{ +} + +void VKQueryPool::end_query() +{ +} + +void VKQueryPool::get_occlusion_result(MutableSpan<uint32_t> /*r_values*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_query.hh b/source/blender/gpu/vulkan/vk_query.hh new file mode 100644 index 00000000000..36558ef9549 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_query.hh @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_query.hh" + +namespace blender::gpu { + +class VKQueryPool : public QueryPool { + public: + void init(GPUQueryType type) override; + void begin_query() override; + void end_query() override; + void get_occlusion_result(MutableSpan<uint32_t> r_values) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc new file mode 100644 index 00000000000..d628f3eb851 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_shader.hh" + +namespace blender::gpu { +void VKShader::vertex_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +void VKShader::geometry_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +void VKShader::fragment_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +void VKShader::compute_shader_from_glsl(MutableSpan<const char *> /*sources*/) +{ +} + +bool VKShader::finalize(const shader::ShaderCreateInfo * /*info*/) +{ + return false; +} + +void VKShader::transform_feedback_names_set(Span<const char *> /*name_list*/, + eGPUShaderTFBType /*geom_type*/) +{ +} + +bool VKShader::transform_feedback_enable(GPUVertBuf *) +{ + return false; +} + +void VKShader::transform_feedback_disable() +{ +} + +void VKShader::bind() +{ +} + +void VKShader::unbind() +{ +} + +void VKShader::uniform_float(int /*location*/, + int /*comp_len*/, + int /*array_size*/, + const float * /*data*/) +{ +} +void VKShader::uniform_int(int /*location*/, + int /*comp_len*/, + int /*array_size*/, + const int * /*data*/) +{ +} + +std::string VKShader::resources_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::vertex_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::geometry_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::geometry_layout_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +std::string VKShader::compute_layout_declare(const shader::ShaderCreateInfo & /*info*/) const +{ + return std::string(); +} + +int VKShader::program_handle_get() const +{ + return -1; +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh new file mode 100644 index 00000000000..9ab0aca67eb --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_shader_private.hh" + +namespace blender::gpu { + +class VKShader : public Shader { + public: + VKShader(const char *name) : Shader(name) + { + } + + void vertex_shader_from_glsl(MutableSpan<const char *> sources) override; + void geometry_shader_from_glsl(MutableSpan<const char *> sources) override; + void fragment_shader_from_glsl(MutableSpan<const char *> sources) override; + void compute_shader_from_glsl(MutableSpan<const char *> sources) override; + bool finalize(const shader::ShaderCreateInfo *info = nullptr) override; + + void transform_feedback_names_set(Span<const char *> name_list, + eGPUShaderTFBType geom_type) override; + bool transform_feedback_enable(GPUVertBuf *) override; + void transform_feedback_disable() override; + + void bind() override; + void unbind() override; + + void uniform_float(int location, int comp_len, int array_size, const float *data) override; + void uniform_int(int location, int comp_len, int array_size, const int *data) override; + + std::string resources_declare(const shader::ShaderCreateInfo &info) const override; + std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override; + std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override; + std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override; + + /* DEPRECATED: Kept only because of BGL API. */ + int program_handle_get() const override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc new file mode 100644 index 00000000000..2b6fda0547d --- /dev/null +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_vertex_buffer.hh" + +#include "vk_storage_buffer.hh" + +namespace blender::gpu { + +void VKStorageBuffer::update(const void * /*data*/) +{ +} + +void VKStorageBuffer::bind(int /*slot*/) +{ +} + +void VKStorageBuffer::unbind() +{ +} + +void VKStorageBuffer::clear(eGPUTextureFormat /* internal_format*/, + eGPUDataFormat /*data_format*/, + void * /*data*/) +{ +} +void VKStorageBuffer::copy_sub(VertBuf * /*src*/, + uint /*dst_offset*/, + uint /*src_offset*/, + uint /*copy_size*/) +{ +} + +void VKStorageBuffer::read(void * /*data*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.hh b/source/blender/gpu/vulkan/vk_storage_buffer.hh new file mode 100644 index 00000000000..a51f89f627a --- /dev/null +++ b/source/blender/gpu/vulkan/vk_storage_buffer.hh @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "GPU_texture.h" + +#include "gpu_storage_buffer_private.hh" + +namespace blender::gpu { + +class VKStorageBuffer : public StorageBuf { + public: + VKStorageBuffer(int size, const char *name) : StorageBuf(size, name) + { + } + + void update(const void *data) override; + void bind(int slot) override; + void unbind() override; + void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; + void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; + void read(void *data) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc new file mode 100644 index 00000000000..ea5379e6572 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_texture.hh" + +namespace blender::gpu { + +void VKTexture::generate_mipmap() +{ +} + +void VKTexture::copy_to(Texture * /*tex*/) +{ +} + +void VKTexture::clear(eGPUDataFormat /*format*/, const void * /*data*/) +{ +} + +void VKTexture::swizzle_set(const char /*swizzle_mask*/[4]) +{ +} + +void VKTexture::stencil_texture_mode_set(bool /*use_stencil*/) +{ +} + +void VKTexture::mip_range_set(int /*min*/, int /*max*/) +{ +} + +void *VKTexture::read(int /*mip*/, eGPUDataFormat /*format*/) +{ + return nullptr; +} + +void VKTexture::update_sub(int /*mip*/, + int /*offset*/[3], + int /*extent*/[3], + eGPUDataFormat /*format*/, + const void * /*data*/) +{ +} + +/* TODO(fclem): Legacy. Should be removed at some point. */ +uint VKTexture::gl_bindcode_get() const +{ + return 0; +} + +bool VKTexture::init_internal() +{ + return false; +} + +bool VKTexture::init_internal(GPUVertBuf * /*vbo*/) +{ + return false; +} + +bool VKTexture::init_internal(const GPUTexture * /*src*/, int /*mip_offset*/, int /*layer_offset*/) +{ + return false; +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh new file mode 100644 index 00000000000..93094b7e540 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_texture_private.hh" + +namespace blender::gpu { + +class VKTexture : public Texture { + public: + VKTexture(const char *name) : Texture(name) + { + } + + void generate_mipmap() override; + void copy_to(Texture *tex) override; + void clear(eGPUDataFormat format, const void *data) override; + void swizzle_set(const char swizzle_mask[4]) override; + void stencil_texture_mode_set(bool use_stencil) override; + void mip_range_set(int min, int max) override; + void *read(int mip, eGPUDataFormat format) override; + void update_sub( + int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) override; + + /* TODO(fclem): Legacy. Should be removed at some point. */ + uint gl_bindcode_get() const override; + + protected: + bool init_internal() override; + bool init_internal(GPUVertBuf *vbo) override; + bool init_internal(const GPUTexture *src, int mip_offset, int layer_offset) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.cc b/source/blender/gpu/vulkan/vk_uniform_buffer.cc new file mode 100644 index 00000000000..8ef5b19273a --- /dev/null +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.cc @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_uniform_buffer.hh" + +namespace blender::gpu { + +void VKUniformBuffer::update(const void * /*data*/) +{ +} + +void VKUniformBuffer::bind(int /*slot*/) +{ +} + +void VKUniformBuffer::unbind() +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.hh b/source/blender/gpu/vulkan/vk_uniform_buffer.hh new file mode 100644 index 00000000000..f086a7aa391 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.hh @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_uniform_buffer_private.hh" + +namespace blender::gpu { + +class VKUniformBuffer : public UniformBuf { + public: + VKUniformBuffer(int size, const char *name) : UniformBuf(size, name) + { + } + + void update(const void *data) override; + void bind(int slot) override; + void unbind() override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.cc b/source/blender/gpu/vulkan/vk_vertex_buffer.cc new file mode 100644 index 00000000000..5791e20fb30 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.cc @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_vertex_buffer.hh" + +namespace blender::gpu { + +void VKVertexBuffer::bind_as_ssbo(uint /*binding*/) +{ +} + +void VKVertexBuffer::bind_as_texture(uint /*binding*/) +{ +} + +void VKVertexBuffer::wrap_handle(uint64_t /*handle*/) +{ +} + +void VKVertexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*data*/) +{ +} + +const void *VKVertexBuffer::read() const +{ + return nullptr; +} + +void *VKVertexBuffer::unmap(const void * /*mapped_data*/) const +{ + return nullptr; +} + +void VKVertexBuffer::acquire_data() +{ +} + +void VKVertexBuffer::resize_data() +{ +} + +void VKVertexBuffer::release_data() +{ +} + +void VKVertexBuffer::upload_data() +{ +} + +void VKVertexBuffer::duplicate_data(VertBuf * /*dst*/) +{ +} + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.hh b/source/blender/gpu/vulkan/vk_vertex_buffer.hh new file mode 100644 index 00000000000..84ccc65bcdf --- /dev/null +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.hh @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_vertex_buffer_private.hh" + +namespace blender::gpu { + +class VKVertexBuffer : public VertBuf { + public: + void bind_as_ssbo(uint binding) override; + void bind_as_texture(uint binding) override; + void wrap_handle(uint64_t handle) override; + + void update_sub(uint start, uint len, const void *data) override; + const void *read() const override; + void *unmap(const void *mapped_data) const override; + + protected: + void acquire_data() override; + void resize_data() override; + void release_data() override; + void upload_data() override; + void duplicate_data(VertBuf *dst) override; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 6d99fde9df6..c467e48d21e 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -406,7 +406,7 @@ static void execute_posetree(struct Depsgraph *depsgraph, } copy_v3_v3(rootmat[3], pchan->pose_head); - mul_m4_m4m4(imat, ob->obmat, rootmat); + mul_m4_m4m4(imat, ob->object_to_world, rootmat); invert_m4_m4(goalinv, imat); for (target = tree->targets.first; target; target = target->next) { @@ -465,7 +465,7 @@ static void execute_posetree(struct Depsgraph *depsgraph, /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); copy_v3_v3(end_pose[3], pchan->pose_tail); - mul_m4_series(world_pose, goalinv, ob->obmat, end_pose); + mul_m4_series(world_pose, goalinv, ob->object_to_world, end_pose); /* blend position */ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0]; diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 9317f14b7f1..2878bbb6da7 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -586,10 +586,10 @@ static bool target_callback(const iTaSC::Timestamp ×tamp, float chanmat[4][4]; copy_m4_m4(chanmat, pchan->pose_mat); copy_v3_v3(chanmat[3], pchan->pose_tail); - mul_m4_series(restmat, target->owner->obmat, chanmat, target->eeRest); + mul_m4_series(restmat, target->owner->object_to_world, chanmat, target->eeRest); } else { - mul_m4_m4m4(restmat, target->owner->obmat, target->eeRest); + mul_m4_m4m4(restmat, target->owner->object_to_world, target->eeRest); } /* blend the target */ blend_m4_m4m4(tarmat, restmat, tarmat, constraint->enforce); @@ -620,10 +620,10 @@ static bool base_callback(const iTaSC::Timestamp ×tamp, ikscene->baseFrame.setValue(&chanmat[0][0]); /* iTaSC armature is scaled to object scale, scale the base frame too */ ikscene->baseFrame.p *= ikscene->blScale; - mul_m4_m4m4(rootmat, ikscene->blArmature->obmat, chanmat); + mul_m4_m4m4(rootmat, ikscene->blArmature->object_to_world, chanmat); } else { - copy_m4_m4(rootmat, ikscene->blArmature->obmat); + copy_m4_m4(rootmat, ikscene->blArmature->object_to_world); ikscene->baseFrame = iTaSC::F_identity; } next.setValue(&rootmat[0][0]); @@ -1065,7 +1065,7 @@ static void convert_pose(IK_Scene *ikscene) int a, joint; /* assume uniform scaling and take Y scale as general scale for the armature */ - scale = len_v3(ikscene->blArmature->obmat[1]); + scale = len_v3(ikscene->blArmature->object_to_world[1]); rot = ikscene->jointArray(0); for (joint = a = 0, ikchan = ikscene->channels; a < ikscene->numchan && joint < ikscene->numjoint; @@ -1105,7 +1105,7 @@ static void BKE_pose_rest(IK_Scene *ikscene) int a, joint; /* assume uniform scaling and take Y scale as general scale for the armature */ - scale = len_v3(ikscene->blArmature->obmat[1]); + scale = len_v3(ikscene->blArmature->object_to_world[1]); /* rest pose is 0 */ SetToZero(ikscene->jointArray); /* except for transY joints */ @@ -1183,7 +1183,7 @@ static IK_Scene *convert_tree( } ikscene->blArmature = ob; /* assume uniform scaling and take Y scale as general scale for the armature */ - ikscene->blScale = len_v3(ob->obmat[1]); + ikscene->blScale = len_v3(ob->object_to_world[1]); ikscene->blInvScale = (ikscene->blScale < KDL::epsilon) ? 0.0f : 1.0f / ikscene->blScale; std::string joint; @@ -1667,7 +1667,7 @@ static void create_scene(struct Depsgraph *depsgraph, Scene *scene, Object *ob, static int init_scene(Object *ob) { /* check also if scaling has changed */ - float scale = len_v3(ob->obmat[1]); + float scale = len_v3(ob->object_to_world[1]); IK_Scene *scene; if (ob->pose->ikdata) { diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 71e0d0fe11e..94c0555dcf0 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1100,7 +1100,12 @@ static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search) * experimentally. Note: Too big offset can impact performance. Current 3 frame offset has no * measurable impact. */ - return pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3); + int64_t seek_pts = pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3); + + if (seek_pts < 0) { + seek_pts = 0; + } + return seek_pts; } /* This gives us an estimate of which pts our requested frame will have. diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 8965700c08a..63836690ee4 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -377,9 +377,9 @@ static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_l { if (!anim->index_dir[0]) { char filename[FILE_MAXFILE]; - BLI_split_dirfile(anim->name, index_dir, filename, index_dir_len, sizeof(filename)); - BLI_path_append(index_dir, index_dir_len, "BL_proxy"); - BLI_path_append(index_dir, index_dir_len, filename); + char dirname[FILE_MAXDIR]; + BLI_split_dirfile(anim->name, dirname, filename, index_dir_len, sizeof(filename)); + BLI_path_join(index_dir, index_dir_len, dirname, "BL_proxy", filename); } else { BLI_strncpy(index_dir, anim->index_dir, index_dir_len); @@ -498,7 +498,9 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( rv->anim = anim; get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true); - BLI_make_existing_file(filepath); + if (!BLI_make_existing_file(filepath)) { + return NULL; + } rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); @@ -905,6 +907,14 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, } } + if (context->proxy_ctx[0] == NULL && context->proxy_ctx[1] == NULL && + context->proxy_ctx[2] == NULL && context->proxy_ctx[3] == NULL) { + avformat_close_input(&context->iFormatCtx); + avcodec_free_context(&context->iCodecCtx); + MEM_freeN(context); + return NULL; /* Nothing to transcode. */ + } + for (i = 0; i < num_indexers; i++) { if (tcs_in_use & tc_types[i]) { char filepath[FILE_MAX]; diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c index dd509677d8d..35cdefbaaeb 100644 --- a/source/blender/imbuf/intern/util_gpu.c +++ b/source/blender/imbuf/intern/util_gpu.c @@ -174,6 +174,7 @@ static void *imb_gpu_get_data(const ImBuf *ibuf, /* Other colorspace, store as float texture to avoid precision loss. */ data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__); *r_freedata = freedata = true; + is_float_rect = true; if (data_rect == NULL) { return NULL; @@ -300,6 +301,16 @@ GPUTexture *IMB_create_gpu_texture(const char *name, int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)}; bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]); + /* Correct the smaller size to maintain the original aspect ratio of the image. */ + if (do_rescale && ibuf->x != ibuf->y) { + if (size[0] > size[1]) { + size[1] = (int)(ibuf->y * ((float)size[0] / ibuf->x)); + } + else { + size[0] = (int)(ibuf->x * ((float)size[1] / ibuf->y)); + } + } + #ifdef WITH_DDS if (ibuf->ftype == IMB_FTYPE_DDS) { eGPUTextureFormat compressed_format; diff --git a/source/blender/imbuf/intern/webp.c b/source/blender/imbuf/intern/webp.c index 27c26fb19c1..3031b8c3e33 100644 --- a/source/blender/imbuf/intern/webp.c +++ b/source/blender/imbuf/intern/webp.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file - * \ingroup imbuf + * \ingroup imbuf */ #ifdef _WIN32 diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc index f872943ad5c..13136372c56 100644 --- a/source/blender/io/alembic/exporter/abc_writer_hair.cc +++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc @@ -118,7 +118,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, context.object->obmat); + invert_m4_m4_safe(inv_mat, context.object->object_to_world); MTFace *mtface = (MTFace *)CustomData_get_layer(&mesh->fdata, CD_MTFACE); MFace *mface = (MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE); @@ -241,7 +241,7 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, context.object->obmat); + invert_m4_m4_safe(inv_mat, context.object->object_to_world); MFace *mface = (MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE); MTFace *mtface = (MTFace *)CustomData_get_layer(&mesh->fdata, CD_MTFACE); diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc index 00e5890e9d3..35a19d0fbc0 100644 --- a/source/blender/io/alembic/intern/abc_axis_conversion.cc +++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc @@ -134,15 +134,15 @@ void create_transform_matrix(Object *obj, if (mode == ABC_MATRIX_LOCAL && obj->parent) { /* Note that this produces another matrix than the local matrix, due to * constraints and modifiers as well as the obj->parentinv matrix. */ - invert_m4_m4(obj->parent->imat, obj->parent->obmat); - mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat); + invert_m4_m4(obj->parent->imat, obj->parent->object_to_world); + mul_m4_m4m4(zup_mat, obj->parent->imat, obj->object_to_world); } else { - copy_m4_m4(zup_mat, obj->obmat); + copy_m4_m4(zup_mat, obj->object_to_world); } if (proxy_from) { - mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat); + mul_m4_m4m4(zup_mat, proxy_from->object_to_world, zup_mat); } copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index f08514dc45c..2531bd62609 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -763,7 +763,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, std::map<std::string, int> mat_map; bke::MutableAttributeAccessor attributes = new_mesh->attributes_for_write(); bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); material_indices.finish(); } @@ -823,8 +823,8 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel { std::map<std::string, int> mat_map; bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); - bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(sample_sel, material_indices.span, mat_map); material_indices.finish(); utils::assign_materials(bmain, m_object, mat_map); diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc index af26565f8d6..f3a07eaad3f 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.cc +++ b/source/blender/io/alembic/intern/abc_reader_object.cc @@ -165,7 +165,7 @@ void AbcObjectReader::setupObjectTransform(const chrono_t time) /* Apply the matrix to the object. */ BKE_object_apply_mat4(m_object, transform_from_alembic, true, false); - BKE_object_to_mat4(m_object, m_object->obmat); + BKE_object_to_mat4(m_object, m_object->object_to_world); if (!is_constant || m_settings->always_add_cache_reader) { bConstraint *con = BKE_constraint_add_for_object( diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 2d872377bbf..826d7864067 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -332,8 +332,8 @@ void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob) float mat[4][4]; TransformReader::get_node_mat(mat, node, &uid_animated_map, ob); if (ob) { - copy_m4_m4(ob->obmat, mat); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + copy_m4_m4(ob->object_to_world, mat); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); } } @@ -2097,7 +2097,7 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, if (par_job) { float temp[4][4], ipar[4][4]; - invert_m4_m4(ipar, par_job->obmat); + invert_m4_m4(ipar, par_job->object_to_world); copy_m4_m4(temp, mat); mul_m4_m4m4(mat, ipar, temp); } diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp index 1310337f501..7de08f89b7d 100644 --- a/source/blender/io/collada/ArmatureImporter.cpp +++ b/source/blender/io/collada/ArmatureImporter.cpp @@ -114,7 +114,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, Object *ob_arm = skin->BKE_armature_from_object(); if (ob_arm) { float invmat[4][4]; - invert_m4_m4(invmat, ob_arm->obmat); + invert_m4_m4(invmat, ob_arm->object_to_world); mul_m4_m4m4(mat, invmat, mat); } @@ -708,7 +708,7 @@ void ArmatureImporter::set_pose(Object *ob_arm, copy_m4_m4(mat, obmat); float invObmat[4][4]; - invert_m4_m4(invObmat, ob_arm->obmat); + invert_m4_m4(invObmat, ob_arm->object_to_world); mul_m4_m4m4(pchan->pose_mat, invObmat, mat); } diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp index 6bf8d904a41..62bcdc5bf4c 100644 --- a/source/blender/io/collada/ControllerExporter.cpp +++ b/source/blender/io/collada/ControllerExporter.cpp @@ -406,7 +406,7 @@ void ControllerExporter::add_bind_shape_mat(Object *ob) bc_add_global_transform(f_obmat, export_settings.get_global_transform()); } - // UnitConverter::mat4_to_dae_double(bind_mat, ob->obmat); + // UnitConverter::mat4_to_dae_double(bind_mat, ob->object_to_world); UnitConverter::mat4_to_dae_double(bind_mat, f_obmat); if (this->export_settings.get_limit_precision()) { BCMatrix::sanitize(bind_mat, LIMITTED_PRECISION); @@ -523,7 +523,7 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, } /* make world-space matrix (bind_mat is armature-space) */ - mul_m4_m4m4(world, ob_arm->obmat, bind_mat); + mul_m4_m4m4(world, ob_arm->object_to_world, bind_mat); if (!has_bindmat) { if (export_settings.get_apply_global_orientation()) { diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp index 5e432682564..dae1c4ba894 100644 --- a/source/blender/io/collada/DocumentImporter.cpp +++ b/source/blender/io/collada/DocumentImporter.cpp @@ -412,8 +412,8 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, } } /* calc new matrix and apply */ - mul_m4_m4m4(obn->obmat, obn->obmat, mat); - BKE_object_apply_mat4(obn, obn->obmat, false, false); + mul_m4_m4m4(obn->object_to_world, obn->object_to_world, mat); + BKE_object_apply_mat4(obn, obn->object_to_world, false, false); } } else { diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp index 0654bae3730..b4615635318 100644 --- a/source/blender/io/collada/SkinInfo.cpp +++ b/source/blender/io/collada/SkinInfo.cpp @@ -214,12 +214,12 @@ void SkinInfo::link_armature(bContext *C, ob->partype = PAROBJECT; BKE_object_workob_calc_parent(scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); + invert_m4_m4(ob->parentinv, workob.object_to_world); DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); #endif - copy_m4_m4(ob->obmat, bind_shape_matrix); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + copy_m4_m4(ob->object_to_world, bind_shape_matrix); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); amd->deformflag = ARM_DEF_VGROUP; diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index 22a73cd7db2..96ff78a715a 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -129,7 +129,7 @@ bool bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) const bool keep_transform = false; if (par && is_parent_space) { - mul_m4_m4m4(ob->obmat, par->obmat, ob->obmat); + mul_m4_m4m4(ob->object_to_world, par->object_to_world, ob->object_to_world); } bool ok = ED_object_parent_set( @@ -348,10 +348,10 @@ std::string bc_replace_string(std::string data, void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene) { if (scale_to_scene) { - mul_m4_m4m4(ob->obmat, bc_unit.get_scale(), ob->obmat); + mul_m4_m4m4(ob->object_to_world, bc_unit.get_scale(), ob->object_to_world); } - mul_m4_m4m4(ob->obmat, bc_unit.get_rotation(), ob->obmat); - BKE_object_apply_mat4(ob, ob->obmat, false, false); + mul_m4_m4m4(ob->object_to_world, bc_unit.get_rotation(), ob->object_to_world); + BKE_object_apply_mat4(ob, ob->object_to_world, false, false); } void bc_match_scale(std::vector<Object *> *objects_done, diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc index 03c1ba94d94..d559b0efe82 100644 --- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc @@ -416,7 +416,7 @@ void AbstractHierarchyIterator::visit_object(Object *object, context->original_export_path = ""; context->higher_up_export_path = ""; - copy_m4_m4(context->matrix_world, object->obmat); + copy_m4_m4(context->matrix_world, object->object_to_world); ExportGraph::key_type graph_index = determine_graph_index_object(context); context_update_for_graph_index(context, graph_index); diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc index b9d7b6719b1..6cc977bfced 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_base.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc @@ -79,7 +79,7 @@ void GpencilIO::prepare_camera_params(Scene *scene, const GpencilIOParams *ipara BKE_camera_params_compute_matrix(¶ms); float viewmat[4][4]; - invert_m4_m4(viewmat, cam_ob->obmat); + invert_m4_m4(viewmat, cam_ob->object_to_world); mul_m4_m4m4(persmat_, params.winmat, viewmat); } @@ -152,7 +152,7 @@ void GpencilIO::create_object_list() /* Save z-depth from view to sort from back to front. */ if (is_camera_) { - float camera_z = dot_v3v3(camera_z_axis, object->obmat[3]); + float camera_z = dot_v3v3(camera_z_axis, object->object_to_world[3]); ObjectZ obz = {camera_z, object}; ob_list_.append(obz); } @@ -160,10 +160,10 @@ void GpencilIO::create_object_list() float zdepth = 0; if (rv3d_) { if (rv3d_->is_persp) { - zdepth = ED_view3d_calc_zfac(rv3d_, object->obmat[3]); + zdepth = ED_view3d_calc_zfac(rv3d_, object->object_to_world[3]); } else { - zdepth = -dot_v3v3(rv3d_->viewinv[2], object->obmat[3]); + zdepth = -dot_v3v3(rv3d_->viewinv[2], object->object_to_world[3]); } ObjectZ obz = {zdepth * -1.0f, object}; ob_list_.append(obz); diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc index ddd72f816b0..c042ca597c8 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc @@ -177,7 +177,7 @@ void GpencilExporterPDF::export_gpencil_layers() /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); /* Fill. */ if ((is_fill) && (params_.flag & GP_EXPORT_FILL)) { diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc index 58f12e9b8b1..8acb87f8e58 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc @@ -197,7 +197,7 @@ void GpencilExporterSVG::export_gpencil_layers() /* Apply layer thickness change. */ gps_duplicate->thickness += gpl->line_change; /* Apply object scale to thickness. */ - gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world); CLAMP_MIN(gps_duplicate->thickness, 1.0f); const bool is_normalized = ((params_.flag & GP_EXPORT_NORM_THICKNESS) != 0) || diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt index 3a21da5c579..f7eb933d198 100644 --- a/source/blender/io/stl/CMakeLists.txt +++ b/source/blender/io/stl/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ./importer + importer ../common ../../blenkernel ../../blenlib diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 77c79852141..8138f38fcad 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -33,6 +33,7 @@ #include <pxr/base/vt/value.h> #include <pxr/usd/sdf/types.h> #include <pxr/usd/usdGeom/mesh.h> +#include <pxr/usd/usdGeom/primvarsAPI.h> #include <pxr/usd/usdGeom/subset.h> #include <pxr/usd/usdShade/materialBindingAPI.h> @@ -287,11 +288,13 @@ bool USDMeshReader::topology_changed(const Mesh *existing_mesh, const double mot mesh_prim_.GetFaceVertexCountsAttr().Get(&face_counts_, motionSampleTime); mesh_prim_.GetPointsAttr().Get(&positions_, motionSampleTime); + pxr::UsdGeomPrimvarsAPI primvarsAPI(mesh_prim_); + /* TODO(makowalski): Reading normals probably doesn't belong in this function, * as this is not required to determine if the topology has changed. */ /* If 'normals' and 'primvars:normals' are both specified, the latter has precedence. */ - pxr::UsdGeomPrimvar primvar = mesh_prim_.GetPrimvar(usdtokens::normalsPrimvar); + pxr::UsdGeomPrimvar primvar = primvarsAPI.GetPrimvar(usdtokens::normalsPrimvar); if (primvar.HasValue()) { primvar.ComputeFlattened(&normals_, motionSampleTime); normal_interpolation_ = primvar.GetInterpolation(); @@ -355,6 +358,8 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo std::vector<UVSample> uv_primvars(ldata->totlayer); + pxr::UsdGeomPrimvarsAPI primvarsAPI(mesh_prim_); + if (has_uvs_) { for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) { const CustomDataLayer *layer = &ldata->layers[layer_idx]; @@ -385,11 +390,11 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo } /* Early out if mesh doesn't have primvar. */ - if (!mesh_prim_.HasPrimvar(uv_token)) { + if (!primvarsAPI.HasPrimvar(uv_token)) { continue; } - if (pxr::UsdGeomPrimvar uv_primvar = mesh_prim_.GetPrimvar(uv_token)) { + if (pxr::UsdGeomPrimvar uv_primvar = primvarsAPI.GetPrimvar(uv_token)) { uv_primvar.ComputeFlattened(&uv_primvars[layer_idx].uvs, motionSampleTime); uv_primvars[layer_idx].interpolation = uv_primvar.GetInterpolation(); } @@ -804,8 +809,8 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot std::map<pxr::SdfPath, int> mat_map; bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); - bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); this->assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); material_indices.finish(); /* Build material name map if it's not built yet. */ @@ -835,12 +840,14 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, is_left_handed_ = true; } + pxr::UsdGeomPrimvarsAPI primvarsAPI(mesh_prim_); + std::vector<pxr::TfToken> uv_tokens; /* Currently we only handle UV primvars. */ if (read_flag & MOD_MESHSEQ_READ_UV) { - std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim_.GetPrimvars(); + std::vector<pxr::UsdGeomPrimvar> primvars = primvarsAPI.GetPrimvars(); for (pxr::UsdGeomPrimvar p : primvars) { @@ -914,7 +921,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, std::map<pxr::SdfPath, int> mat_map; bke::MutableAttributeAccessor attributes = active_mesh->attributes_for_write(); bke::SpanAttributeWriter<int> material_indices = - attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_span<int>("material_index", ATTR_DOMAIN_FACE); assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); material_indices.finish(); } diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index e949bafe517..e7d79e888e4 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -4,6 +4,7 @@ #include "usd_hierarchy_iterator.h" #include <pxr/usd/usdGeom/mesh.h> +#include <pxr/usd/usdGeom/primvarsAPI.h> #include <pxr/usd/usdShade/material.h> #include <pxr/usd/usdShade/materialBindingAPI.h> @@ -107,6 +108,8 @@ void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_ { pxr::UsdTimeCode timecode = get_export_time_code(); + pxr::UsdGeomPrimvarsAPI primvarsAPI(usd_mesh.GetPrim()); + const CustomData *ldata = &mesh->ldata; for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) { const CustomDataLayer *layer = &ldata->layers[layer_idx]; @@ -119,7 +122,7 @@ void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_ * for texture coordinates by naming the UV Map as such, without having to guess which UV Map * is the "standard" one. */ pxr::TfToken primvar_name(pxr::TfMakeValidIdentifier(layer->name)); - pxr::UsdGeomPrimvar uv_coords_primvar = usd_mesh.CreatePrimvar( + pxr::UsdGeomPrimvar uv_coords_primvar = primvarsAPI.CreatePrimvar( primvar_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->faceVarying); MLoopUV *mloopuv = static_cast<MLoopUV *>(layer->data); diff --git a/source/blender/io/usd/tests/usd_imaging_test.cc b/source/blender/io/usd/tests/usd_imaging_test.cc index 5cd3c042e59..80c232ad099 100644 --- a/source/blender/io/usd/tests/usd_imaging_test.cc +++ b/source/blender/io/usd/tests/usd_imaging_test.cc @@ -42,8 +42,8 @@ TEST_F(USDImagingTest, CapsuleAdapterTest) } pxr::UsdImagingCapsuleAdapter capsule_adapter; - pxr::VtValue points_value = pxr::UsdImagingCapsuleAdapter::GetMeshPoints( - capsule.GetPrim(), pxr::UsdTimeCode::Default()); + pxr::VtValue points_value = capsule_adapter.GetPoints(capsule.GetPrim(), + pxr::UsdTimeCode::Default()); if (!points_value.IsHolding<pxr::VtArray<pxr::GfVec3f>>()) { FAIL() << "Mesh points value holding unexpected type."; return; @@ -52,7 +52,8 @@ TEST_F(USDImagingTest, CapsuleAdapterTest) pxr::VtArray<pxr::GfVec3f> points = points_value.Get<pxr::VtArray<pxr::GfVec3f>>(); EXPECT_FALSE(points.empty()); - pxr::VtValue topology_value = pxr::UsdImagingCapsuleAdapter::GetMeshTopology(); + pxr::VtValue topology_value = capsule_adapter.GetTopology( + capsule.GetPrim(), pxr::SdfPath(), pxr::UsdTimeCode::Default()); if (!topology_value.IsHolding<pxr::HdMeshTopology>()) { FAIL() << "Mesh topology value holding unexpected type."; diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt index f7958ef4ec6..bfbc715a45f 100644 --- a/source/blender/io/wavefront_obj/CMakeLists.txt +++ b/source/blender/io/wavefront_obj/CMakeLists.txt @@ -2,8 +2,8 @@ set(INC . - ./exporter - ./importer + exporter + importer ../common ../../blenkernel ../../blenlib diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index d00c09b9013..f5a94b1fc8a 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -124,10 +124,11 @@ void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) unit_m3(axes_transform); /* +Y-forward and +Z-up are the default Blender axis settings. */ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform); - mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat); + mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.object_to_world); /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */ - mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]); - world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3]; + mul_v3_m3v3( + world_and_axes_transform_[3], axes_transform, export_object_eval_.object_to_world[3]); + world_and_axes_transform_[3][3] = export_object_eval_.object_to_world[3][3]; /* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */ float normal_matrix[3][3]; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc index 812c3e7b5d4..1b1ee5f8386 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc @@ -31,10 +31,10 @@ void OBJCurve::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) unit_m3(axes_transform); /* +Y-forward and +Z-up are the Blender's default axis settings. */ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform); - mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat); - /* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */ - mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]); - world_axes_transform_[3][3] = export_object_eval_->obmat[3][3]; + mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->object_to_world); + /* #mul_m4_m3m4 does not transform last row of #Object.object_to_world, i.e. location data. */ + mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->object_to_world[3]); + world_axes_transform_[3][3] = export_object_eval_->object_to_world[3][3]; } const char *OBJCurve::get_curve_name() const diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 287a9e2f3b9..0355ed3febe 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -116,7 +116,7 @@ typedef enum eCustomDataType { CD_PROP_BYTE_COLOR = 17, CD_TANGENT = 18, CD_MDISPS = 19, - CD_PREVIEW_MCOL = 20, /* for displaying weightpaint colors */ + CD_PREVIEW_MCOL = 20, /* For displaying weight-paint colors. */ /* CD_ID_MCOL = 21, */ /* CD_TEXTURE_MLOOPCOL = 22, */ /* UNUSED */ CD_CLOTH_ORCO = 23, @@ -209,7 +209,7 @@ typedef enum eCustomDataType { #define CD_MASK_HAIRLENGTH (1ULL << CD_HAIRLENGTH) -/** Multires loop data. */ +/** Multi-resolution loop data. */ #define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK) /* All data layers. */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 26dbb544f52..8b3f4956cfe 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -243,12 +243,15 @@ typedef struct bGPDstroke_Runtime { /** Runtime falloff factor (only for transform). */ float multi_frame_falloff; - /** Vertex offset in the VBO where this stroke starts. */ + /** Triangle offset in the IBO where this stroke starts. */ int stroke_start; /** Triangle offset in the IBO where this fill starts. */ int fill_start; + /** Vertex offset in the VBO where this stroke starts. */ + int vertex_start; /** Curve Handles offset in the IBO where this handle starts. */ int curve_start; + int _pad0; /** Original stroke (used to dereference evaluated data) */ struct bGPDstroke *gps_orig; @@ -613,8 +616,9 @@ typedef struct bGPdata_Runtime { /** Stroke buffer. */ void *sbuffer; /** Temp batches cleared after drawing. */ - struct GPUBatch *sbuffer_stroke_batch; - struct GPUBatch *sbuffer_fill_batch; + struct GPUVertBuf *sbuffer_position_buf; + struct GPUVertBuf *sbuffer_color_buf; + struct GPUBatch *sbuffer_batch; /** Temp stroke used for drawing. */ struct bGPDstroke *sbuffer_gps; diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 827e07725a1..6ea35dfb770 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -134,13 +134,13 @@ typedef struct ViewLayerAOV { typedef struct ViewLayerLightgroup { struct ViewLayerLightgroup *next, *prev; - /* Name of the Lightgroup */ + /* Name of the Light-group. */ char name[64]; } ViewLayerLightgroup; -/* Lightgroup membership information. */ +/* Light-group membership information. */ typedef struct LightgroupMembership { - /* Name of the Lightgroup */ + /* Name of the Light-group. */ char name[64]; } LightgroupMembership; diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h index d0c09a0d6ab..b4a66a46efe 100644 --- a/source/blender/makesdna/DNA_meta_types.h +++ b/source/blender/makesdna/DNA_meta_types.h @@ -42,7 +42,7 @@ typedef struct MetaElem { float rad2; /** Stiffness, how much of the element to fill. */ float s; - /** Old, only used for backwards compat. use dimensions now. */ + /** Old, only used for backwards compatibility. use dimensions now. */ float len; /** Matrix and inverted matrix. */ @@ -63,7 +63,7 @@ typedef struct MetaBall { /* material of the mother ball will define the material used of all others */ struct Material **mat; - /** Flag is enum for updates, flag2 is bitflags for settings. */ + /** Flag is enum for updates, flag2 is bit-flags for settings. */ char flag, flag2; short totcol; /** Used to store MB_AUTOSPACE. */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 7625f04fefa..c4180071352 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -195,7 +195,7 @@ typedef struct LatticeModifierData { ModifierData modifier; struct Object *object; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char name[64]; float strength; short flag; @@ -212,7 +212,7 @@ typedef struct CurveModifierData { ModifierData modifier; struct Object *object; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char name[64]; /** Axis along which curve deforms. */ short defaxis; @@ -262,7 +262,7 @@ typedef struct MaskModifierData { /** Armature to use to in place of hardcoded vgroup. */ struct Object *ob_arm; - /** Name of vertex group to use to mask, MAX_VGROUP_NAME. */ + /** Name of vertex group to use to mask, #MAX_VGROUP_NAME. */ char vgroup[64]; /** Using armature or hardcoded vgroup. */ @@ -447,7 +447,7 @@ typedef struct BevelModifierData { float bevel_angle; float spread; /** if the MOD_BEVEL_VWEIGHT option is set, - * this will be the name of the vert group, MAX_VGROUP_NAME */ + * this will be the name of the vert group, #MAX_VGROUP_NAME */ char defgrp_name[64]; char _pad1[4]; @@ -565,7 +565,7 @@ typedef struct DisplaceModifierData { float strength; int direction; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; float midlevel; int space; @@ -635,7 +635,7 @@ typedef struct DecimateModifierData { /** (mode == MOD_DECIM_MODE_DISSOLVE). */ float angle; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; float defgrp_factor; short flag, mode; @@ -663,7 +663,7 @@ enum { typedef struct SmoothModifierData { ModifierData modifier; float fac; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag, repeat; @@ -684,7 +684,7 @@ typedef struct CastModifierData { float fac; float radius; float size; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag; /** Cast modifier projection type. */ @@ -725,7 +725,7 @@ typedef struct WaveModifierData { /* End MappingInfoModifierData. */ struct Object *objectcenter; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag; @@ -760,7 +760,7 @@ typedef struct ArmatureModifierData { struct Object *object; /** Stored input of previous modifier, for vertex-group blending. */ float (*vert_coords_prev)[3]; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; } ArmatureModifierData; @@ -803,11 +803,11 @@ typedef struct HookModifierData { struct CurveMapping *curfalloff; - /** If NULL, it's using vertexgroup. */ + /** If NULL, it's using vertex-group. */ int *indexar; int indexar_num; float force; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char name[64]; void *_pad1; } HookModifierData; @@ -946,7 +946,7 @@ typedef struct MeshDeformModifierData { /** Mesh object. */ struct Object *object; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char defgrp_name[64]; short gridsize, flag; @@ -1124,7 +1124,7 @@ typedef struct ShrinkwrapModifierData { struct Object *target; /** Additional shrink target. */ struct Object *auxTarget; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char vgroup_name[64]; /** Distance offset to keep from mesh/projection point. */ float keepDist; @@ -1171,9 +1171,9 @@ enum { /** #ShrinkwrapModifierData.shrinkOpts */ enum { - /** allow shrinkwrap to move the vertex in the positive direction of axis */ + /** Allow shrink-wrap to move the vertex in the positive direction of axis. */ MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0), - /** allow shrinkwrap to move the vertex in the negative direction of axis */ + /** Allow shrink-wrap to move the vertex in the negative direction of axis. */ MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR = (1 << 1), /** ignore vertex moves if a vertex ends projected on a front face of the target */ @@ -1207,7 +1207,7 @@ typedef struct SimpleDeformModifierData { /** Object to control the origin of modifier space coordinates. */ struct Object *origin; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char vgroup_name[64]; /** Factors to control simple deforms. */ float factor; @@ -1250,7 +1250,7 @@ typedef struct ShapeKeyModifierData { typedef struct SolidifyModifierData { ModifierData modifier; - /** Name of vertex group to use, MAX_VGROUP_NAME. */ + /** Name of vertex group to use, #MAX_VGROUP_NAME. */ char defgrp_name[64]; char shell_defgrp_name[64]; char rim_defgrp_name[64]; @@ -1451,7 +1451,7 @@ typedef struct WarpModifierData { char bone_to[64]; struct CurveMapping *curfalloff; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char defgrp_name[64]; float strength; float falloff_radius; @@ -1484,7 +1484,7 @@ typedef enum { typedef struct WeightVGEditModifierData { ModifierData modifier; - /** Name of vertex group to edit. MAX_VGROUP_NAME. */ + /** Name of vertex group to edit. #MAX_VGROUP_NAME. */ char defgrp_name[64]; /** Using MOD_WVG_EDIT_* flags. */ @@ -1504,7 +1504,7 @@ typedef struct WeightVGEditModifierData { /* Masking options. */ /** The global "influence", if no vgroup nor tex is used as mask. */ float mask_constant; - /** Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME. */ + /** Name of mask vertex group from which to get weight factors. #MAX_VGROUP_NAME. */ char mask_defgrp_name[64]; /* Texture masking. */ @@ -1540,9 +1540,9 @@ enum { typedef struct WeightVGMixModifierData { ModifierData modifier; - /** Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ + /** Name of vertex group to modify/weight. #MAX_VGROUP_NAME. */ char defgrp_name_a[64]; - /** Name of other vertex group to mix in. MAX_VGROUP_NAME. */ + /** Name of other vertex group to mix in. #MAX_VGROUP_NAME. */ char defgrp_name_b[64]; /** Default weight value for first vgroup. */ float default_weight_a; @@ -1558,7 +1558,7 @@ typedef struct WeightVGMixModifierData { /* Masking options. */ /** The global "influence", if no vgroup nor tex is used as mask. */ float mask_constant; - /** Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME. */ + /** Name of mask vertex group from which to get weight factors. #MAX_VGROUP_NAME. */ char mask_defgrp_name[64]; /* Texture masking. */ @@ -1628,7 +1628,7 @@ enum { typedef struct WeightVGProximityModifierData { ModifierData modifier; - /** Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ + /** Name of vertex group to modify/weight. #MAX_VGROUP_NAME. */ char defgrp_name[64]; /* Mapping stuff. */ @@ -1646,7 +1646,7 @@ typedef struct WeightVGProximityModifierData { /* Masking options. */ /** The global "influence", if no vgroup nor tex is used as mask. */ float mask_constant; - /** Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME. */ + /** Name of mask vertex group from which to get weight factors. #MAX_VGROUP_NAME. */ char mask_defgrp_name[64]; /* Texture masking. */ @@ -1840,7 +1840,7 @@ typedef struct LaplacianSmoothModifierData { float lambda, lambda_border; char _pad1[4]; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; short flag, repeat; } LaplacianSmoothModifierData; @@ -1887,7 +1887,7 @@ typedef struct CorrectiveSmoothModifierData { char smooth_type, rest_source; char _pad[6]; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; /* runtime-only cache */ @@ -1932,7 +1932,7 @@ typedef struct UVWarpModifierData { /** Optional name of bone target, MAX_ID_NAME-2. */ char bone_dst[64]; - /** Optional vertexgroup name, MAX_VGROUP_NAME. */ + /** Optional vertex-group name, #MAX_VGROUP_NAME. */ char vgroup_name[64]; /** MAX_CUSTOMDATA_LAYER_NAME. */ char uvlayer_name[64]; @@ -2013,7 +2013,7 @@ enum { typedef struct LaplacianDeformModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char anchor_grp_name[64]; int verts_num, repeat; float *vertexco; @@ -2035,7 +2035,7 @@ enum { */ typedef struct WireframeModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; float offset; float offset_fac; @@ -2059,7 +2059,7 @@ typedef struct WeldModifierData { /* The limit below which to merge vertices. */ float merge_dist; - /* Name of vertex group to use to mask, MAX_VGROUP_NAME. */ + /** Name of vertex group to use to mask, #MAX_VGROUP_NAME. */ char defgrp_name[64]; char mode; @@ -2107,7 +2107,7 @@ typedef struct DataTransferModifierData { /** See CDT_MIX_ enum in BKE_customdata.h. */ int mix_mode; float mix_factor; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; int flags; @@ -2130,7 +2130,7 @@ enum { /** Set Split Normals modifier. */ typedef struct NormalEditModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; /** Source of normals, or center of ellipsoid. */ struct Object *target; @@ -2253,7 +2253,7 @@ enum { typedef struct WeightedNormalModifierData { ModifierData modifier; - /** MAX_VGROUP_NAME. */ + /** #MAX_VGROUP_NAME. */ char defgrp_name[64]; char mode, flag; short weight; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 315bcbd971c..74714cf7e41 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -931,7 +931,7 @@ typedef struct NodeImageMultiFileSocket { char path[1024]; ImageFormatData format; - /* multilayer output */ + /* Multi-layer output. */ /** EXR_TOT_MAXNAME-2 ('.' and channel char are appended). */ char layer[30]; char _pad2[2]; @@ -1273,7 +1273,7 @@ typedef struct CryptomatteLayer { typedef struct NodeCryptomatte_Runtime { /* Contains `CryptomatteLayer`. */ ListBase layers; - /* Temp storage for the cryptomatte picker. */ + /* Temp storage for the crypto-matte picker. */ float add[3]; float remove[3]; } NodeCryptomatte_Runtime; @@ -2083,6 +2083,12 @@ typedef enum CMPNodeLevelsChannel { CMP_NODE_LEVLES_LUMINANCE_BT709 = 5, } CMPNodeLevelsChannel; +/* Tone Map Node. Stored in NodeTonemap.type. */ +typedef enum CMPNodeToneMapType { + CMP_NODE_TONE_MAP_SIMPLE = 0, + CMP_NODE_TONE_MAP_PHOTORECEPTOR = 1, +} CMPNodeToneMapType; + /* Plane track deform node. */ enum { diff --git a/source/blender/makesdna/DNA_object_defaults.h b/source/blender/makesdna/DNA_object_defaults.h index 14683869bc4..2a5796d2aea 100644 --- a/source/blender/makesdna/DNA_object_defaults.h +++ b/source/blender/makesdna/DNA_object_defaults.h @@ -23,7 +23,7 @@ \ .constinv = _DNA_DEFAULT_UNIT_M4, \ .parentinv = _DNA_DEFAULT_UNIT_M4, \ - .obmat = _DNA_DEFAULT_UNIT_M4, \ + .object_to_world = _DNA_DEFAULT_UNIT_M4, \ \ .scale = {1, 1, 1}, \ .dscale = {1, 1, 1}, \ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 8296855ec29..3ef32d28e85 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -323,7 +323,7 @@ typedef struct Object { /** Axis angle rotation - angle part. */ float rotAngle, drotAngle; /** Final world-space matrix with constraints & animsys applied. */ - float obmat[4][4]; + float object_to_world[4][4]; /** Inverse result of parent, so that object doesn't 'stick' to parent. */ float parentinv[4][4]; /** Inverse result of constraints. @@ -333,7 +333,7 @@ typedef struct Object { * Inverse matrix of 'obmat' for any other use than rendering! * * \note this isn't assured to be valid as with 'obmat', - * before using this value you should do: `invert_m4_m4(ob->imat, ob->obmat)` + * before using this value you should do: `invert_m4_m4(ob->imat, ob->object_to_world)` */ float imat[4][4]; diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 44f1d3479b1..c4f11905e10 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -465,7 +465,7 @@ enum { #define PART_REACT_MULTIPLE 2 //#define PART_LOOP 4 /* not used anymore */ -/* for dopesheet */ +/* For dope-sheet. */ #define PART_DS_EXPAND 8 #define PART_HAIR_REGROW 16 /* regrow hair for each frame */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 5fa5d4c7787..28359038be5 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -472,6 +472,7 @@ typedef struct ImageFormatData { #define R_IMF_IMTYPE_THEORA 33 #define R_IMF_IMTYPE_PSD 34 #define R_IMF_IMTYPE_WEBP 35 +#define R_IMF_IMTYPE_AV1 36 #define R_IMF_IMTYPE_INVALID 255 diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 55563ca6823..d05ba0f7e2e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -667,7 +667,7 @@ typedef struct SpaceSeq { struct SequencerPreviewOverlay preview_overlay; struct SequencerTimelineOverlay timeline_overlay; - /** Multiview current eye - for internal use. */ + /** Multi-view current eye - for internal use. */ char multiview_eye; char _pad2[7]; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 9b235fac049..7231a995f10 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -89,13 +89,13 @@ typedef struct Report { } Report; /** - * \note Saved in the wm, don't remove. + * \note Saved in the #wmWindowManager, don't remove. */ typedef struct ReportList { ListBase list; - /** eReportType. */ + /** #eReportType. */ int printlevel; - /** eReportType. */ + /** #eReportType. */ int storelevel; int flag; char _pad[4]; diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index e99f317f057..0cd1144b30d 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -199,8 +199,10 @@ typedef struct WorkSpaceInstanceHook { WorkSpace *active; struct WorkSpaceLayout *act_layout; - /** Needed because we can't change workspaces/layouts in running handler loop, - * it would break context. */ + /** + * Needed because we can't change work-spaces/layouts in running handler loop, + * it would break context. + */ WorkSpace *temp_workspace_store; struct WorkSpaceLayout *temp_layout_store; } WorkSpaceInstanceHook; diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 0d04d7df067..50fd51e88a1 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -116,8 +116,8 @@ blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # ----------------------------------------------------------------------------- # Build bf_dna_blenlib library set(INC + .. ../../blenlib - ../../makesdna ../../../../intern/atomic ../../../../intern/guardedalloc ) diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index f968b7409f7..864fbc45b13 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -97,6 +97,7 @@ DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection) DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale) DNA_STRUCT_RENAME_ELEM(Object, restrictflag, visibility_flag) DNA_STRUCT_RENAME_ELEM(Object, size, scale) +DNA_STRUCT_RENAME_ELEM(Object, obmat, object_to_world) DNA_STRUCT_RENAME_ELEM(Object_Runtime, crazyspace_num_verts, crazyspace_verts_num) DNA_STRUCT_RENAME_ELEM(MEdge, bweight, bweight_legacy) DNA_STRUCT_RENAME_ELEM(MEdge, crease, crease_legacy) diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 0a17ae637bc..4fbb246e056 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -201,7 +201,7 @@ set(INC ../../imbuf ../../makesdna ../../modifiers - ../../nodes/ + ../../nodes ../../sequencer ../../simulation ../../windowmanager diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index e6b1ea1321c..a2386205013 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -1129,7 +1129,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) RNA_define_lib_overridable(false); } -/* err... bones should not be directly edited (only editbones should be...) */ +/* Err... bones should not be directly edited (only edit-bones should be...). */ static void rna_def_bone(BlenderRNA *brna) { StructRNA *srna; diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index a04fdbae465..7fbb6926cf1 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -505,6 +505,12 @@ static void rna_def_asset_handle(BlenderRNA *brna) rna_def_asset_handle_api(srna); } +static void rna_def_asset_catalog_path(BlenderRNA *brna) +{ + StructRNA *srna = RNA_def_struct(brna, "AssetCatalogPath", NULL); + RNA_def_struct_ui_text(srna, "Catalog Path", ""); +} + static void rna_def_asset_library_reference(BlenderRNA *brna) { StructRNA *srna = RNA_def_struct(brna, "AssetLibraryReference", NULL); @@ -556,6 +562,7 @@ void RNA_def_asset(BlenderRNA *brna) rna_def_asset_library_reference(brna); rna_def_asset_library_reference_custom(brna); rna_def_asset_handle(brna); + rna_def_asset_catalog_path(brna); RNA_define_animate_sdna(true); } diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 35e01be366b..5ba31070e1d 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -3616,6 +3616,10 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Use Vertex", "Use this brush in grease pencil vertex color mode"); + prop = RNA_def_property(srna, "use_paint_sculpt_curves", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_SCULPT_CURVES); + RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in sculpt curves mode"); + /* texture */ prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "BrushTextureSlot"); @@ -3659,13 +3663,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mask Texture Overlay Alpha", ""); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "add_col"); RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Add Color", "Color of cursor when adding"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "cursor_color_subtract", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "cursor_color_subtract", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "sub_col"); RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Subtract Color", "Color of cursor when subtracting"); diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index db5b3c33c59..9af76de2a2b 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -168,7 +168,7 @@ static void rna_DepsgraphObjectInstance_matrix_world_get(PointerRNA *ptr, float /* We can return actual object's matrix here, no reason to return identity matrix * when this is not actually an instance... */ Object *ob = (Object *)di->iter.current; - copy_m4_m4((float(*)[4])mat, ob->obmat); + copy_m4_m4((float(*)[4])mat, ob->object_to_world); } } diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 727d329781d..9fe7dda0e20 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -2416,7 +2416,7 @@ static void rna_def_fcurve(BlenderRNA *brna) prop, "Color Mode", "Method used to determine color of F-Curve in Graph Editor"); RNA_def_property_update(prop, NC_ANIMATION, NULL); - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color", "Color of the F-Curve in the Graph Editor"); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index cf0ff546d41..a55a1b0ffcd 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -334,13 +334,13 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char ** static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr) { if (type == PAROBJECT) { - invert_m4_m4(gpl->inverse, par->obmat); + invert_m4_m4(gpl->inverse, par->object_to_world); gpl->parent = par; gpl->partype |= PAROBJECT; gpl->parsubstr[0] = 0; } else if (type == PARSKEL) { - invert_m4_m4(gpl->inverse, par->obmat); + invert_m4_m4(gpl->inverse, par->object_to_world); gpl->parent = par; gpl->partype |= PARSKEL; gpl->parsubstr[0] = 0; @@ -349,7 +349,7 @@ static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char * bPoseChannel *pchan = BKE_pose_channel_find_name(par->pose, substr); if (pchan) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, par->obmat, pchan->pose_mat); + mul_m4_m4m4(tmp_mat, par->object_to_world, pchan->pose_mat); invert_m4_m4(gpl->inverse, tmp_mat); gpl->parent = par; @@ -357,7 +357,7 @@ static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char * BLI_strncpy(gpl->parsubstr, substr, sizeof(gpl->parsubstr)); } else { - invert_m4_m4(gpl->inverse, par->obmat); + invert_m4_m4(gpl->inverse, par->object_to_world); gpl->parent = par; gpl->partype |= PAROBJECT; gpl->parsubstr[0] = 0; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 4a36443ca42..320ef169ae5 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -9,11 +9,8 @@ #include <stdlib.h> #include "DNA_armature_types.h" -#include "DNA_brush_types.h" -#include "DNA_cachefile_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" -#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" @@ -21,20 +18,13 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" -#include "BLI_rand.h" +#include "BLI_math_base.h" +#include "BLI_math_rotation.h" #include "BLI_string_utils.h" #include "BLT_translation.h" #include "BKE_animsys.h" -#include "BKE_data_transfer.h" -#include "BKE_dynamicpaint.h" -#include "BKE_effect.h" -#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */ -#include "BKE_mesh_mapping.h" -#include "BKE_mesh_remap.h" -#include "BKE_multires.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index fdd702ac377..9b7534d081d 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -323,7 +323,9 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, PointerRNA rna_object_shapekey_index_get(struct ID *id, int value); int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current); -void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag); +void rna_def_object_type_visibility_flags_common(StructRNA *srna, + int noteflag, + const char *update_func); int rna_object_type_visibility_icon_get_common(int object_type_exclude_viewport, const int *object_type_exclude_select); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 0b0970a835e..865399df9ef 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -12230,7 +12230,7 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Custom Color", "Use custom color for the node"); RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Color", "Custom color of the node body"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 46a89d3a6e0..1d6b3d5d69e 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -356,7 +356,8 @@ static void rna_Object_internal_update_draw(Main *UNUSED(bmain), static void rna_Object_matrix_world_update(Main *bmain, Scene *scene, PointerRNA *ptr) { /* don't use compat so we get predictable rotation */ - BKE_object_apply_mat4((Object *)ptr->owner_id, ((Object *)ptr->owner_id)->obmat, false, true); + BKE_object_apply_mat4( + (Object *)ptr->owner_id, ((Object *)ptr->owner_id)->object_to_world, false, true); rna_Object_internal_update(bmain, scene, ptr); } @@ -407,7 +408,7 @@ static void rna_Object_matrix_local_set(PointerRNA *ptr, const float values[16]) Object *ob = (Object *)ptr->owner_id; float local_mat[4][4]; - /* Localspace matrix is truly relative to the parent, + /* Local-space matrix is truly relative to the parent, * but parameters stored in object are relative to parentinv matrix. * Undo the parent inverse part before applying it as local matrix. */ if (ob->parent) { @@ -3390,7 +3391,7 @@ static void rna_def_object(BlenderRNA *brna) /* matrix */ prop = RNA_def_property(srna, "matrix_world", PROP_FLOAT, PROP_MATRIX); - RNA_def_property_float_sdna(prop, NULL, "obmat"); + RNA_def_property_float_sdna(prop, NULL, "object_to_world"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 07702f3b4b6..02105c7b425 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -471,7 +471,7 @@ static void rna_ParticleSystem_co_hair( if (step >= 0 && step <= max_k) { copy_v3_v3(n_co, (cache + step)->co); mul_m4_v3(particlesystem->imat, n_co); - mul_m4_v3(object->obmat, n_co); + mul_m4_v3(object->object_to_world, n_co); } } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8fc504f192e..fde8fcf651c 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5945,7 +5945,8 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) {AV_CODEC_ID_PNG, "PNG", 0, "PNG", ""}, {AV_CODEC_ID_QTRLE, "QTRLE", 0, "QT rle / QT Animation", ""}, {AV_CODEC_ID_THEORA, "THEORA", 0, "Theora", ""}, - {AV_CODEC_ID_VP9, "WEBM", 0, "WEBM / VP9", ""}, + {AV_CODEC_ID_VP9, "WEBM", 0, "WebM / VP9", ""}, + {AV_CODEC_ID_AV1, "AV1", 0, "AV1", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index b5469a30568..2ac30c44ea8 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1002,6 +1002,13 @@ static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_RegionView3D, regiondata); } +static void rna_SpaceView3D_object_type_visibility_update(Main *UNUSED(bmain), + Scene *scene, + PointerRNA *UNUSED(ptr)) +{ + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); +} + static void rna_SpaceView3D_region_quadviews_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { @@ -5098,7 +5105,8 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_mirror_xr_session_update"); rna_def_object_type_visibility_flags_common(srna, - NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING); + NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, + "rna_SpaceView3D_object_type_visibility_update"); /* Helper for drawing the icon. */ prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index b3896919275..9790a85e1c8 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -119,7 +119,9 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_output(func, parm); } -void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag) +void rna_def_object_type_visibility_flags_common(StructRNA *srna, + int noteflag, + const char *update_func) { PropertyRNA *prop; @@ -173,7 +175,7 @@ void rna_def_object_type_visibility_flags_common(StructRNA *srna, int noteflag) RNA_def_property_boolean_negative_sdna( prop, NULL, view_mask_member[mask_index], info[type_index].type_mask); RNA_def_property_ui_text(prop, info[type_index].name, ""); - RNA_def_property_update(prop, noteflag, NULL); + RNA_def_property_update(prop, noteflag, update_func); } } } diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index c4a11d4e9e0..44df0db9ade 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1640,7 +1640,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna) RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); /* color */ - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index fc68e8421d7..eac29ac5e61 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -1785,6 +1785,10 @@ void RNA_api_ui_layout(StructRNA *srna) parm = RNA_def_pointer(func, "socket", "NodeSocket", "", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + func = RNA_def_function(srna, "template_node_asset_menu_items", "uiTemplateNodeAssetMenuItems"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm = RNA_def_string(func, "catalog_path", NULL, 0, "", ""); + func = RNA_def_function(srna, "template_texture_user", "uiTemplateTextureUser"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 2fed4e3f4a3..72722053a64 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -561,7 +561,7 @@ static void rna_Userdef_disk_cache_dir_update(Main *UNUSED(bmain), { if (U.sequencer_disk_cache_dir[0] != '\0') { BLI_path_abs(U.sequencer_disk_cache_dir, BKE_main_blendfile_path_from_global()); - BLI_path_slash_ensure(U.sequencer_disk_cache_dir); + BLI_path_slash_ensure(U.sequencer_disk_cache_dir, sizeof(U.sequencer_disk_cache_dir)); BLI_path_make_safe(U.sequencer_disk_cache_dir); } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 5b5544120a1..eebe595820e 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -99,13 +99,6 @@ static const EnumPropertyItem event_ndof_type_items[] = { {NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""}, {NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""}, {NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""}, -# if 0 /* Never used (converted to keyboard events by GHOST). */ - /* keyboard emulation */ - {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"}, - {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"}, - {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"}, - {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"}, -# endif /* general-purpose buttons */ {NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""}, {NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""}, @@ -120,6 +113,21 @@ static const EnumPropertyItem event_ndof_type_items[] = { {NDOF_BUTTON_A, "NDOF_BUTTON_A", 0, "Button A", ""}, {NDOF_BUTTON_B, "NDOF_BUTTON_B", 0, "Button B", ""}, {NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""}, + /* View buttons. */ + {NDOF_BUTTON_V1, "NDOF_BUTTON_V1", 0, "View 1", ""}, + {NDOF_BUTTON_V2, "NDOF_BUTTON_V2", 0, "View 2", ""}, + {NDOF_BUTTON_V3, "NDOF_BUTTON_V3", 0, "View 3", ""}, +# if 0 /* Never used (converted to keyboard events by GHOST). */ + /* keyboard emulation */ + {NDOF_BUTTON_ESC, "NDOF_BUTTON_ESC", 0, "Esc"}, + {NDOF_BUTTON_ENTER, "NDOF_BUTTON_ENTER", 0, "Enter"}, + {NDOF_BUTTON_DELETE, "NDOF_BUTTON_DELETE", 0, "Delete"}, + {NDOF_BUTTON_TAB, "NDOF_BUTTON_TAB", 0, "Tab"}, + {NDOF_BUTTON_SPACE, "NDOF_BUTTON_SPACE", 0, "Space"}, + {NDOF_BUTTON_ALT, "NDOF_BUTTON_ALT", 0, "Alt"}, + {NDOF_BUTTON_SHIFT, "NDOF_BUTTON_SHIFT", 0, "Shift"}, + {NDOF_BUTTON_CTRL, "NDOF_BUTTON_CTRL", 0, "Ctrl"}, +# endif {0, NULL, 0, NULL, NULL}, }; #endif /* RNA_RUNTIME */ diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c index dcfa1bbca51..c803e5dc9a8 100644 --- a/source/blender/makesrna/intern/rna_xr.c +++ b/source/blender/makesrna/intern/rna_xr.c @@ -2052,7 +2052,7 @@ static void rna_def_xr_session_settings(BlenderRNA *brna) "Allow the VR tracking origin to be defined independently of the headset location"); RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL); - rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED); + rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED, NULL); /* Helper for drawing the icon. */ prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index bf534b0d586..2d725af7fe4 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -456,13 +456,13 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, float result_mat[4][4]; if (ctx->object) { - invert_m4_m4(obinv, ctx->object->obmat); + invert_m4_m4(obinv, ctx->object->object_to_world); } else { unit_m4(obinv); } - mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); + mul_m4_series(result_mat, offset, obinv, amd->offset_ob->object_to_world); copy_m4_m4(offset, result_mat); } @@ -474,7 +474,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, Object *curve_ob = amd->curve_ob; CurveCache *curve_cache = curve_ob->runtime.curve_cache; if (curve_cache != NULL && curve_cache->anim_path_accum_length != NULL) { - float scale_fac = mat4_to_scale(curve_ob->obmat); + float scale_fac = mat4_to_scale(curve_ob->object_to_world); length = scale_fac * BKE_anim_path_get_length(curve_cache); } } diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 7ad49f43e1b..21f05158e8b 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -139,8 +139,8 @@ static Mesh *get_quick_mesh( float imat[4][4]; float omat[4][4]; - invert_m4_m4(imat, ob_self->obmat); - mul_m4_m4m4(omat, imat, ob_operand_ob->obmat); + invert_m4_m4(imat, ob_self->object_to_world); + mul_m4_m4m4(omat, imat, ob_operand_ob->object_to_world); MutableSpan<MVert> verts = result->verts_for_write(); for (const int i : verts.index_range()) { @@ -227,7 +227,8 @@ static BMesh *BMD_mesh_bm_create( SCOPED_TIMER(__func__); #endif - *r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat)); + *r_is_flip = (is_negative_m4(object->object_to_world) != + is_negative_m4(operand_ob->object_to_world)); const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob); @@ -294,8 +295,8 @@ static void BMD_mesh_intersection(BMesh *bm, float imat[4][4]; float omat[4][4]; - invert_m4_m4(imat, object->obmat); - mul_m4_m4m4(omat, imat, operand_ob->obmat); + invert_m4_m4(imat, object->object_to_world); + mul_m4_m4m4(omat, imat, operand_ob->object_to_world); BMVert *eve; i = 0; @@ -414,7 +415,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } meshes.append(mesh); - obmats.append((float4x4 *)&ctx->object->obmat); + obmats.append((float4x4 *)&ctx->object->object_to_world); material_remaps.append({}); if (mesh->totcol == 0) { /* Necessary for faces using the default material when there are no material slots. */ @@ -431,7 +432,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } BKE_mesh_wrapper_ensure_mdata(mesh_operand); meshes.append(mesh_operand); - obmats.append((float4x4 *)&bmd->object->obmat); + obmats.append((float4x4 *)&bmd->object->object_to_world); material_remaps.append(get_material_remap(*bmd->object, *mesh_operand, materials)); } else if (bmd->flag & eBooleanModifierFlag_Collection) { @@ -446,7 +447,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } BKE_mesh_wrapper_ensure_mdata(collection_mesh); meshes.append(collection_mesh); - obmats.append((float4x4 *)&ob->obmat); + obmats.append((float4x4 *)&ob->object_to_world); material_remaps.append(get_material_remap(*ob, *collection_mesh, materials)); } } @@ -456,14 +457,15 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0; const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0; - Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes, - obmats, - *(float4x4 *)&ctx->object->obmat, - material_remaps, - use_self, - hole_tolerant, - bmd->operation, - nullptr); + Mesh *result = blender::meshintersect::direct_mesh_boolean( + meshes, + obmats, + *(float4x4 *)&ctx->object->object_to_world, + material_remaps, + use_self, + hole_tolerant, + bmd->operation, + nullptr); MEM_SAFE_FREE(result->mat); result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__); result->totcol = materials.size(); diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 30be1d33653..7581b2aa8e5 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -126,13 +126,13 @@ static void sphere_do(CastModifierData *cmd, * we use its location, transformed to ob's local space */ if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, imat, ob->obmat); + invert_m4_m4(imat, ctrl_ob->object_to_world); + mul_m4_m4m4(mat, imat, ob->object_to_world); invert_m4_m4(imat, mat); } - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_v3_m4v3(center, ob->imat, ctrl_ob->object_to_world[3]); } /* now we check which options the user wants */ @@ -275,13 +275,13 @@ static void cuboid_do(CastModifierData *cmd, if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, imat, ob->obmat); + invert_m4_m4(imat, ctrl_ob->object_to_world); + mul_m4_m4m4(mat, imat, ob->object_to_world); invert_m4_m4(imat, mat); } - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_v3_m4v3(center, ob->imat, ctrl_ob->object_to_world[3]); } if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index e38bf96500e..82faf08b349 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -149,7 +149,7 @@ static void deformVerts(ModifierData *md, for (uint i = 0; i < mvert_num; i++) { /* we save global positions */ - mul_m4_v3(ob->obmat, collmd->x[i].co); + mul_m4_v3(ob->object_to_world, collmd->x[i].co); } collmd->xnew = MEM_dupallocN(collmd->x); /* Frame end position. */ @@ -188,7 +188,7 @@ static void deformVerts(ModifierData *md, for (uint i = 0; i < mvert_num; i++) { /* we save global positions */ - mul_m4_v3(ob->obmat, collmd->xnew[i].co); + mul_m4_v3(ob->object_to_world, collmd->xnew[i].co); /* detect motion */ is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co); diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index ad5be57ad68..fc12a9c2aad 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -322,7 +322,7 @@ static void displaceModifier_do(DisplaceModifierData *dmd, } else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && use_global_direction) { - copy_m4_m4(local_mat, ob->obmat); + copy_m4_m4(local_mat, ob->object_to_world); } DisplaceUserdata data = {NULL}; diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index af167bf9b32..96bf836fa4a 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -985,7 +985,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, MTFace *mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname); /* getting back to object space */ - invert_m4_m4(imat, ctx->object->obmat); + invert_m4_m4(imat, ctx->object->object_to_world); psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); @@ -1020,7 +1020,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, psys_get_particle_state(&sim, ed_v2, &state, 1); vertco = explode_verts[v].co; - mul_m4_v3(ctx->object->obmat, vertco); + mul_m4_v3(ctx->object->object_to_world, vertco); sub_v3_v3(vertco, birth.co); diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 11bc9ee9574..6cf2e1538e9 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -338,13 +338,13 @@ static void deformVerts_do(HookModifierData *hmd, /* get world-space matrix of target, corrected for the space the verts are in */ if (hmd->subtarget[0] && pchan) { /* bone target if there's a matching pose-channel */ - mul_m4_m4m4(dmat, ob_target->obmat, pchan->pose_mat); + mul_m4_m4m4(dmat, ob_target->object_to_world, pchan->pose_mat); } else { /* just object target */ - copy_m4_m4(dmat, ob_target->obmat); + copy_m4_m4(dmat, ob_target->object_to_world); } - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); mul_m4_series(hd.mat, ob->imat, dmat, hmd->parentinv); /* --- done with 'hd' init --- */ diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc index cad9fdfe30d..778f12d6745 100644 --- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc +++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc @@ -135,7 +135,7 @@ static Volume *mesh_to_volume(ModifierData *md, BKE_mesh_wrapper_ensure_mdata(mesh); const float4x4 mesh_to_own_object_space_transform = float4x4(ctx->object->imat) * - float4x4(object_to_convert->obmat); + float4x4(object_to_convert->object_to_world); geometry::MeshToVolumeResolution resolution; resolution.mode = (MeshToVolumeModifierResolutionMode)mvmd->resolution_mode; if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) { diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index d7ed346a61f..2aaaee2ccc7 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -358,8 +358,8 @@ static void meshdeformModifier_do(ModifierData *md, } /* compute matrices to go in and out of cage object space */ - invert_m4_m4(imat, ob_target->obmat); - mul_m4_m4m4(cagemat, imat, ob->obmat); + invert_m4_m4(imat, ob_target->object_to_world); + mul_m4_m4m4(cagemat, imat, ob->object_to_world); mul_m4_m4m4(cmat, mmd->bindmat, cagemat); invert_m4_m4(iobmat, cmat); copy_m3_m4(icagemat, iobmat); diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index 43ded18fcc4..7d422826cf8 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -94,8 +94,8 @@ static void generate_vert_coordinates(Mesh *mesh, /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ /* Get ob_center (world) coordinates in ob local coordinates. * No need to take into account ob_center's space here, see T44027. */ - invert_m4_m4(inv_obmat, ob->obmat); - mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]); + invert_m4_m4(inv_obmat, ob->object_to_world); + mul_v3_m4v3(diff, inv_obmat, ob_center->object_to_world[3]); negate_v3(diff); do_diff = true; @@ -383,8 +383,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, /* Get target's center coordinates in ob local coordinates. */ float mat[4][4]; - invert_m4_m4(mat, ob->obmat); - mul_m4_m4m4(mat, mat, ob_target->obmat); + invert_m4_m4(mat, ob->object_to_world); + mul_m4_m4m4(mat, mat, ob_target->object_to_world); copy_v3_v3(target_co, mat[3]); if (use_parallel_normals) { diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index aab48101351..f65f8bc4fb3 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -273,7 +273,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * break; case eParticleInstanceSpace_Local: /* get particle states in the particle object's local space */ - invert_m4_m4(spacemat, pimd->ob->obmat); + invert_m4_m4(spacemat, pimd->ob->object_to_world); break; default: /* should not happen */ diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 91f8947bbc3..afd7f5a2e48 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -274,8 +274,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * if (ob_axis != NULL) { /* Calculate the matrix relative to the axis object. */ - invert_m4_m4(mtx_tmp_a, ctx->object->obmat); - copy_m4_m4(mtx_tx_inv, ob_axis->obmat); + invert_m4_m4(mtx_tmp_a, ctx->object->object_to_world); + copy_m4_m4(mtx_tx_inv, ob_axis->object_to_world); mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); /* Calculate the axis vector. */ diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index c5e117635b5..a34d66f394b 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -154,7 +154,7 @@ static void deformVerts(ModifierData *md, MVert *verts = BKE_mesh_verts_for_write(surmd->mesh); for (i = 0, x = surmd->x, v = surmd->v; i < mesh_verts_num; i++, x++, v++) { float *vec = verts[i].co; - mul_m4_v3(ctx->object->obmat, vec); + mul_m4_v3(ctx->object->object_to_world, vec); if (init) { v->co[0] = v->co[1] = v->co[2] = 0.0f; diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 53bfdc35b31..6a9321a78a2 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1466,8 +1466,8 @@ static void surfacedeformModifier_do(ModifierData *md, ob, md); float tmp_mat[4][4]; - invert_m4_m4(tmp_mat, ob->obmat); - mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->obmat); + invert_m4_m4(tmp_mat, ob->object_to_world); + mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->object_to_world); /* Avoid converting edit-mesh data, binding is an exception. */ BKE_mesh_wrapper_ensure_mdata(target); diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index 589a3d28ad9..a94fc6732a0 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -75,15 +75,15 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd, bPoseChannel *pchan = BKE_pose_channel_find_name(map_object->pose, dmd->map_bone); if (pchan) { float mat_bone_world[4][4]; - mul_m4_m4m4(mat_bone_world, map_object->obmat, pchan->pose_mat); + mul_m4_m4m4(mat_bone_world, map_object->object_to_world, pchan->pose_mat); invert_m4_m4(mapref_imat, mat_bone_world); } else { - invert_m4_m4(mapref_imat, map_object->obmat); + invert_m4_m4(mapref_imat, map_object->object_to_world); } } else { - invert_m4_m4(mapref_imat, map_object->obmat); + invert_m4_m4(mapref_imat, map_object->object_to_world); } } else { /* if there is no map object, default to local */ @@ -138,10 +138,10 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd, copy_v3_v3(*r_texco, cos != nullptr ? *cos : mv->co); break; case MOD_DISP_MAP_GLOBAL: - mul_v3_m4v3(*r_texco, ob->obmat, cos != nullptr ? *cos : mv->co); + mul_v3_m4v3(*r_texco, ob->object_to_world, cos != nullptr ? *cos : mv->co); break; case MOD_DISP_MAP_OBJECT: - mul_v3_m4v3(*r_texco, ob->obmat, cos != nullptr ? *cos : mv->co); + mul_v3_m4v3(*r_texco, ob->object_to_world, cos != nullptr ? *cos : mv->co); mul_m4_v3(mapref_imat, *r_texco); break; } diff --git a/source/blender/modifiers/intern/MOD_uvproject.cc b/source/blender/modifiers/intern/MOD_uvproject.cc index c07b2059b5b..895572d9477 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.cc +++ b/source/blender/modifiers/intern/MOD_uvproject.cc @@ -132,7 +132,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, float offsetmat[4][4]; Camera *cam = nullptr; /* calculate projection matrix */ - invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); + invert_m4_m4(projectors[i].projmat, projectors[i].ob->object_to_world); projectors[i].uci = nullptr; @@ -178,7 +178,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; - mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); + mul_mat3_m4_v3(projectors[i].ob->object_to_world, projectors[i].normal); } polys_num = mesh->totpoly; @@ -192,7 +192,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, /* Convert coords to world-space. */ for (i = 0, co = coords; i < verts_num; i++, co++) { - mul_m4_v3(ob->obmat, *co); + mul_m4_v3(ob->object_to_world, *co); } /* if only one projector, project coords to UVs */ diff --git a/source/blender/modifiers/intern/MOD_uvwarp.cc b/source/blender/modifiers/intern/MOD_uvwarp.cc index 4ec273bcbc6..a96b28b4e2e 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.cc +++ b/source/blender/modifiers/intern/MOD_uvwarp.cc @@ -72,10 +72,10 @@ static void matrix_from_obj_pchan(float mat[4][4], Object *ob, const char *bonen { bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename); if (pchan) { - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat, ob->object_to_world, pchan->pose_mat); } else { - copy_m4_m4(mat, ob->obmat); + copy_m4_m4(mat, ob->object_to_world); } } diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index e66793d7cce..fbd5f27f69a 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -254,14 +254,14 @@ struct DisplaceGridOp { return index_to_object; } case MOD_VOLUME_DISPLACE_MAP_GLOBAL: { - const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->obmat); + const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->object_to_world); return index_to_object * object_to_world; } case MOD_VOLUME_DISPLACE_MAP_OBJECT: { if (vdmd.texture_map_object == nullptr) { return index_to_object; } - const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->obmat); + const openvdb::Mat4s object_to_world = matrix_to_openvdb(ctx.object->object_to_world); const openvdb::Mat4s world_to_texture = matrix_to_openvdb(vdmd.texture_map_object->imat); return index_to_object * object_to_world * world_to_texture; } diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc index 35fd5a4af42..b4ac23b5c61 100644 --- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc +++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc @@ -157,7 +157,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * volume_grid); openvdb::math::Transform::Ptr transform = local_grid->transform().copy(); - transform->postMult(openvdb::Mat4d((float *)vmmd->object->obmat)); + transform->postMult(openvdb::Mat4d((float *)vmmd->object->object_to_world)); openvdb::Mat4d imat = openvdb::Mat4d((float *)ctx->object->imat); /* `imat` had floating point issues and wasn't affine. */ imat.setCol(3, openvdb::Vec4d(0, 0, 0, 1)); diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 3fafbd97fee..791eed28a71 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -93,11 +93,11 @@ static void matrix_from_obj_pchan(float mat[4][4], bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename); if (pchan) { float mat_bone_world[4][4]; - mul_m4_m4m4(mat_bone_world, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(mat_bone_world, ob->object_to_world, pchan->pose_mat); mul_m4_m4m4(mat, obinv, mat_bone_world); } else { - mul_m4_m4m4(mat, obinv, ob->obmat); + mul_m4_m4m4(mat, obinv, ob->object_to_world); } } @@ -215,7 +215,7 @@ static void warpModifier_do(WarpModifierData *wmd, BKE_curvemapping_init(wmd->curfalloff); } - invert_m4_m4(obinv, ob->obmat); + invert_m4_m4(obinv, ob->object_to_world); /* Checks that the objects/bones are available. */ matrix_from_obj_pchan(mat_from, obinv, wmd->object_from, wmd->bone_from); diff --git a/source/blender/modifiers/intern/MOD_wave.cc b/source/blender/modifiers/intern/MOD_wave.cc index 647e0324707..1489927ba34 100644 --- a/source/blender/modifiers/intern/MOD_wave.cc +++ b/source/blender/modifiers/intern/MOD_wave.cc @@ -152,8 +152,8 @@ static void waveModifier_do(WaveModifierData *md, if (wmd->objectcenter != nullptr) { float mat[4][4]; /* get the control object's location in local coordinates */ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); + mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->object_to_world); wmd->startx = mat[3][0]; wmd->starty = mat[3][1]; diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.cc b/source/blender/modifiers/intern/MOD_weightvgproximity.cc index 93052f4215d..e4e03a2cbc9 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.cc +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.cc @@ -223,9 +223,9 @@ static void get_vert2ob_distance( while (i-- > 0) { /* Get world-coordinates of the vertex (constraints and anim included). */ - mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]); + mul_v3_m4v3(v_wco, ob->object_to_world, v_cos[i]); /* Return distance between both coordinates. */ - dist[i] = len_v3v3(v_wco, obr->obmat[3]); + dist[i] = len_v3v3(v_wco, obr->object_to_world[3]); } } @@ -235,7 +235,7 @@ static void get_vert2ob_distance( */ static float get_ob2ob_distance(const Object *ob, const Object *obr) { - return len_v3v3(ob->obmat[3], obr->obmat[3]); + return len_v3v3(ob->object_to_world[3], obr->object_to_world[3]); } /** diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc index 21765825468..34fd63e5805 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc @@ -5,7 +5,9 @@ * \ingroup cmpnodes */ +#include "COM_algorithm_parallel_reduction.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -15,19 +17,60 @@ namespace blender::nodes::node_composite_normalize_cc { static void cmp_node_normalize_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f); + b.add_input<decl::Float>(N_("Value")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .compositor_domain_priority(0); b.add_output<decl::Float>(N_("Value")); } using namespace blender::realtime_compositor; class NormalizeOperation : public NodeOperation { + private: + /* The normalize operation is specifically designed to normalize Z Depth information. But since Z + * Depth can contain near infinite values, normalization is limited to [-range_, range], meaning + * that values outside of that range will be ignored when computing the maximum and minimum for + * normalization and will eventually be 0 or 1 if they are less than or larger than the range + * respectively. */ + constexpr static float range_ = 10000.0f; + public: using NodeOperation::NodeOperation; void execute() override { - get_input("Value").pass_through(get_result("Value")); + Result &input_image = get_input("Value"); + Result &output_image = get_result("Value"); + if (input_image.is_single_value()) { + input_image.pass_through(output_image); + return; + } + + const float maximum = maximum_float_in_range( + context(), input_image.texture(), -range_, range_); + const float minimum = minimum_float_in_range( + context(), input_image.texture(), -range_, range_); + const float scale = (maximum != minimum) ? (1.0f / (maximum - minimum)) : 0.0f; + + GPUShader *shader = shader_manager().get("compositor_normalize"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "minimum", minimum); + GPU_shader_uniform_1f(shader, "scale", scale); + + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc index 2e06ad99df1..d26a01bb3c9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc +++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc @@ -5,20 +5,35 @@ * \ingroup cmpnodes */ +#include <cmath> + +#include "BLI_assert.h" +#include "BLI_math_base.hh" +#include "BLI_math_vec_types.hh" +#include "BLI_math_vector.hh" + #include "RNA_access.h" #include "UI_interface.h" #include "UI_resources.h" +#include "IMB_colormanagement.h" + +#include "COM_algorithm_parallel_reduction.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" namespace blender::nodes::node_composite_tonemap_cc { +NODE_STORAGE_FUNCS(NodeTonemap) + static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); } @@ -68,7 +83,236 @@ class ToneMapOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); + Result &input_image = get_input("Image"); + Result &output_image = get_result("Image"); + if (input_image.is_single_value()) { + input_image.pass_through(output_image); + return; + } + + switch (get_type()) { + case CMP_NODE_TONE_MAP_SIMPLE: + execute_simple(); + return; + case CMP_NODE_TONE_MAP_PHOTORECEPTOR: + execute_photoreceptor(); + return; + default: + BLI_assert_unreachable(); + return; + } + } + + /* Tone mapping based on equation (3) from Reinhard, Erik, et al. "Photographic tone reproduction + * for digital images." Proceedings of the 29th annual conference on Computer graphics and + * interactive techniques. 2002. */ + void execute_simple() + { + const float luminance_scale = compute_luminance_scale(); + const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor(); + const float gamma = node_storage(bnode()).gamma; + const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f; + + GPUShader *shader = shader_manager().get("compositor_tone_map_simple"); + GPU_shader_bind(shader); + + GPU_shader_uniform_1f(shader, "luminance_scale", luminance_scale); + GPU_shader_uniform_1f(shader, "luminance_scale_blend_factor", luminance_scale_blend_factor); + GPU_shader_uniform_1f(shader, "inverse_gamma", inverse_gamma); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + } + + /* Computes the scaling factor in equation (2) from Reinhard's 2002 paper. */ + float compute_luminance_scale() + { + const float geometric_mean = compute_geometric_mean_of_luminance(); + return geometric_mean != 0.0 ? node_storage(bnode()).key / geometric_mean : 0.0f; + } + + /* Computes equation (1) from Reinhard's 2002 paper. However, note that the equation in the paper + * is most likely wrong, and the intention is actually to compute the geometric mean through a + * logscale arithmetic mean, that is, the division should happen inside the exponential function, + * not outside of it. That's because the sum of the log luminance will be a very large negative + * number, whose exponential will almost always be zero, which is unexpected and useless. */ + float compute_geometric_mean_of_luminance() + { + return std::exp(compute_average_log_luminance()); + } + + /* Equation (3) from Reinhard's 2002 paper blends between high luminance scaling for high + * luminance values and low luminance scaling for low luminance values. This is done by adding 1 + * to the denominator, since for low luminance values, the denominator will be close to 1 and for + * high luminance values, the 1 in the denominator will be relatively insignificant. But the + * response of such function is not always ideal, so in this implementation, the 1 was exposed as + * a parameter to the user for more flexibility. */ + float compute_luminance_scale_blend_factor() + { + return node_storage(bnode()).offset; + } + + /* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and + * (7) from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor + * physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */ + void execute_photoreceptor() + { + const float4 global_adaptation_level = compute_global_adaptation_level(); + const float contrast = compute_contrast(); + const float intensity = compute_intensity(); + const float chromatic_adaptation = get_chromatic_adaptation(); + const float light_adaptation = get_light_adaptation(); + + GPUShader *shader = shader_manager().get("compositor_tone_map_photoreceptor"); + GPU_shader_bind(shader); + + GPU_shader_uniform_4fv(shader, "global_adaptation_level", global_adaptation_level); + GPU_shader_uniform_1f(shader, "contrast", contrast); + GPU_shader_uniform_1f(shader, "intensity", intensity); + GPU_shader_uniform_1f(shader, "chromatic_adaptation", chromatic_adaptation); + GPU_shader_uniform_1f(shader, "light_adaptation", light_adaptation); + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients); + + const Result &input_image = get_input("Image"); + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); + } + + /* Computes the global adaptation level from the trilinear interpolation equations constructed + * from equations (6) and (7) in Reinhard's 2005 paper. */ + float4 compute_global_adaptation_level() + { + const float4 average_color = compute_average_color(); + const float average_luminance = compute_average_luminance(); + const float chromatic_adaptation = get_chromatic_adaptation(); + return math::interpolate(float4(average_luminance), average_color, chromatic_adaptation); + } + + float4 compute_average_color() + { + /* The average color will reduce to zero if chromatic adaptation is zero, so just return zero + * in this case to avoid needlessly computing the average. See the trilinear interpolation + * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */ + if (get_chromatic_adaptation() == 0.0f) { + return float4(0.0f); + } + + const Result &input = get_input("Image"); + return sum_color(context(), input.texture()) / (input.domain().size.x * input.domain().size.y); + } + + float compute_average_luminance() + { + /* The average luminance will reduce to zero if chromatic adaptation is one, so just return + * zero in this case to avoid needlessly computing the average. See the trilinear interpolation + * equations constructed from equations (6) and (7) in Reinhard's 2005 paper. */ + if (get_chromatic_adaptation() == 1.0f) { + return 0.0f; + } + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const Result &input = get_input("Image"); + float sum = sum_luminance(context(), input.texture(), luminance_coefficients); + return sum / (input.domain().size.x * input.domain().size.y); + } + + /* Computes equation (5) from Reinhard's 2005 paper. */ + float compute_intensity() + { + return std::exp(-node_storage(bnode()).f); + } + + /* If the contrast is not zero, return it, otherwise, a zero contrast denote automatic derivation + * of the contrast value based on equations (2) and (4) from Reinhard's 2005 paper. */ + float compute_contrast() + { + if (node_storage(bnode()).m != 0.0f) { + return node_storage(bnode()).m; + } + + const float log_maximum_luminance = compute_log_maximum_luminance(); + const float log_minimum_luminance = compute_log_minimum_luminance(); + + /* This is merely to guard against zero division later. */ + if (log_maximum_luminance == log_minimum_luminance) { + return 1.0f; + } + + const float average_log_luminance = compute_average_log_luminance(); + const float dynamic_range = log_maximum_luminance - log_minimum_luminance; + const float luminance_key = (log_maximum_luminance - average_log_luminance) / (dynamic_range); + + return 0.3f + 0.7f * std::pow(luminance_key, 1.4f); + } + + float compute_average_log_luminance() + { + const Result &input_image = get_input("Image"); + + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float sum_of_log_luminance = sum_log_luminance( + context(), input_image.texture(), luminance_coefficients); + + return sum_of_log_luminance / (input_image.domain().size.x * input_image.domain().size.y); + } + + float compute_log_maximum_luminance() + { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float maximum = maximum_luminance( + context(), get_input("Image").texture(), luminance_coefficients); + return std::log(math::max(maximum, 1e-5f)); + } + + float compute_log_minimum_luminance() + { + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + const float minimum = minimum_luminance( + context(), get_input("Image").texture(), luminance_coefficients); + return std::log(math::max(minimum, 1e-5f)); + } + + float get_chromatic_adaptation() + { + return node_storage(bnode()).c; + } + + float get_light_adaptation() + { + return node_storage(bnode()).a; + } + + CMPNodeToneMapType get_type() + { + return static_cast<CMPNodeToneMapType>(node_storage(bnode()).type); } }; diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index df677e1c399..51393ed8709 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -112,7 +112,7 @@ static void node_geo_exec(GeoNodeExecParams params) else { sub_v3_v3(transform.values[3], collection->instance_offset); } - mul_m4_m4_post(transform.values, child_object->obmat); + mul_m4_m4_post(transform.values, child_object->object_to_world); } entries.append({handle, &(child_object->id.name[2]), transform}); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc index 0932624bdc3..dabd2a1a9f2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc @@ -310,7 +310,8 @@ static void node_geo_exec(GeoNodeExecParams params) ATTR_DOMAIN_CORNER); const VArraySpan<float3> rest_positions = mesh_attributes_eval.lookup<float3>(rest_position_name, ATTR_DOMAIN_POINT); - const Span<float2> surface_uv_coords = curves.surface_uv_coords(); + const VArraySpan<float2> surface_uv_coords = curves.attributes().lookup_or_default( + "surface_uv_coordinate", ATTR_DOMAIN_CURVE, float2(0)); const Span<MLoopTri> looptris_orig = surface_mesh_orig->looptris(); const Span<MLoopTri> looptris_eval = surface_mesh_eval->looptris(); @@ -379,7 +380,8 @@ static void node_geo_exec(GeoNodeExecParams params) invalid_uv_count); /* Then also deform edit curve information for use in sculpt mode. */ const CurvesGeometry &curves_orig = CurvesGeometry::wrap(edit_hints->curves_id_orig.geometry); - const Span<float2> surface_uv_coords_orig = curves_orig.surface_uv_coords(); + const VArraySpan<float2> surface_uv_coords_orig = curves_orig.attributes().lookup_or_default( + "surface_uv_coordinate", ATTR_DOMAIN_CURVE, float2(0)); if (!surface_uv_coords_orig.is_empty()) { deform_curves(curves_orig, *surface_mesh_orig, diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index a433a0df9b0..3e48a9fd923 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -4,6 +4,7 @@ #include "UI_resources.h" #include "BLI_array.hh" +#include "BLI_array_utils.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -23,15 +24,9 @@ namespace blender::nodes::node_geo_delete_geometry_cc { using blender::bke::CustomDataAttributes; template<typename T> -static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask) -{ - for (const int i_out : mask.index_range()) { - r_data[i_out] = data[mask[i_out]]; - } -} - -template<typename T> -static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map) +static void copy_data_based_on_map(const Span<T> src, + const Span<int> index_map, + MutableSpan<T> dst) { for (const int i_src : index_map.index_range()) { const int i_dst = index_map[i_src]; @@ -55,26 +50,17 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (!domains.contains(attribute.domain)) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - out_span.copy_from(span); - }); + attribute.varray.materialize(result_attribute.span.data()); result_attribute.finish(); } } @@ -95,26 +81,19 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArraySpan<T> span{attribute.varray.typed<T>()}; - MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_mask(span, out_span, mask); - }); + array_utils::gather(attribute.varray, mask, result_attribute.span); + result_attribute.finish(); } } @@ -131,16 +110,13 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind if (!attribute) { continue; } - /* Only copy if it is on a domain we want. */ if (domain != attribute.domain) { continue; } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, attribute.domain, data_type); - if (!result_attribute) { continue; } @@ -149,7 +125,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind using T = decltype(dummy); VArraySpan<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.span.typed<T>(); - copy_data_based_on_map(span, out_span, index_map); + copy_data_based_on_map(span, index_map, out_span); }); result_attribute.finish(); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc index 091337c28cf..95173bd23a5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc @@ -15,6 +15,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "DEG_depsgraph_query.h" + #include "node_geometry_util.hh" namespace blender::nodes { @@ -208,6 +210,7 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) } const VolumeComponent *component = geometry_set.get_component_for_read<VolumeComponent>(); const Volume *volume = component->get_for_read(); + BKE_volume_load(volume, DEG_get_bmain(params.depsgraph())); Vector<float3> positions; diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 84e63845b84..9b1c13bf563 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_task.hh" #include "DNA_mesh_types.h" @@ -105,18 +106,6 @@ static void copy_data_based_on_pairs(Span<T> data, } } -/* Copy using the map. */ -template<typename T> -static void copy_data_based_on_new_to_old_map(Span<T> data, - MutableSpan<T> r_data, - const Span<int> new_to_old_map) -{ - for (const int i : r_data.index_range()) { - const int old_i = new_to_old_map[i]; - r_data[i] = data[old_i]; - } -} - /** * Transfers the attributes from the original mesh to the new mesh using the following logic: * - If the attribute was on the face domain it is now on the point domain, and this is true @@ -168,7 +157,6 @@ static void transfer_attributes( src_attribute.varray.type()); GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, out_domain, data_type); - if (!dst_attribute) { continue; } @@ -177,20 +165,24 @@ static void transfer_attributes( using T = decltype(dummy); VArraySpan<T> span{src_attribute.varray.typed<T>()}; MutableSpan<T> dst_span = dst_attribute.span.typed<T>(); - if (src_attribute.domain == ATTR_DOMAIN_FACE) { - dst_span.take_front(span.size()).copy_from(span); - if (keep_boundaries) { - copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); - } - } - else if (src_attribute.domain == ATTR_DOMAIN_POINT) { - copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); - } - else if (src_attribute.domain == ATTR_DOMAIN_EDGE) { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map); - } - else { - copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map); + switch (src_attribute.domain) { + case ATTR_DOMAIN_POINT: + copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries); + break; + case ATTR_DOMAIN_EDGE: + array_utils::gather(span, new_to_old_edges_map, dst_span); + break; + case ATTR_DOMAIN_FACE: + dst_span.take_front(span.size()).copy_from(span); + if (keep_boundaries) { + copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map); + } + break; + case ATTR_DOMAIN_CORNER: + array_utils::gather(span, new_to_old_face_corners_map, dst_span); + break; + default: + BLI_assert_unreachable(); } }); dst_attribute.finish(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 70583625a7a..486f900aca5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_map.hh" #include "BLI_noise.hh" #include "BLI_span.hh" @@ -105,16 +106,6 @@ static void threaded_slice_fill(Span<int> offsets, }); } -template<typename T> -static void threaded_mapped_copy(const Span<int> mapping, const Span<T> src, MutableSpan<T> dst) -{ - threading::parallel_for(mapping.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - dst[i] = src[mapping[i]]; - } - }); -} - static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst) { for (const int i : src.index_range()) { @@ -440,17 +431,17 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, MutableSpan<T> dst = dst_attribute.span.typed<T>(); switch (out_domain) { - case ATTR_DOMAIN_FACE: - threaded_slice_fill<T>(offsets, selection, src, dst); + case ATTR_DOMAIN_POINT: + array_utils::gather(src, vert_mapping, dst); break; case ATTR_DOMAIN_EDGE: - threaded_mapped_copy<T>(edge_mapping, src, dst); + array_utils::gather(src, edge_mapping, dst); break; - case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(vert_mapping, src, dst); + case ATTR_DOMAIN_FACE: + threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_CORNER: - threaded_mapped_copy<T>(loop_mapping, src, dst); + array_utils::gather(src, loop_mapping, dst); break; default: break; @@ -653,7 +644,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, threaded_slice_fill<T>(offsets, selection, src, dst); break; case ATTR_DOMAIN_POINT: - threaded_mapped_copy<T>(point_mapping, src, dst); + array_utils::gather(src, point_mapping, dst); break; default: break; diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 1d8c9d6312c..151ba3e59cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BLI_array_utils.hh" #include "BLI_disjoint_set.hh" #include "BLI_task.hh" #include "BLI_vector_set.hh" @@ -175,24 +176,6 @@ static MPoly new_poly(const int loopstart, const int totloop) return poly; } -template<typename T> void copy_with_indices(MutableSpan<T> dst, Span<T> src, Span<int> indices) -{ - BLI_assert(dst.size() == indices.size()); - for (const int i : dst.index_range()) { - dst[i] = src[indices[i]]; - } -} - -template<typename T> void copy_with_mask(MutableSpan<T> dst, Span<T> src, IndexMask mask) -{ - BLI_assert(dst.size() == mask.size()); - threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) { - for (const int i : range) { - dst[i] = src[mask[i]]; - } - }); -} - /** * \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every * result point. @@ -260,28 +243,29 @@ static void extrude_mesh_vertices(Mesh &mesh, if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); - attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { - using T = decltype(dummy); - MutableSpan<T> data = attribute.span.typed<T>(); - switch (attribute.domain) { - case ATTR_DOMAIN_POINT: { - /* New vertices copy the attribute values from their source vertex. */ - copy_with_mask(data.slice(new_vert_range), data.as_span(), selection); - break; - } - case ATTR_DOMAIN_EDGE: { + switch (attribute.domain) { + case ATTR_DOMAIN_POINT: + /* New vertices copy the attribute values from their source vertex. */ + array_utils::gather(attribute.span, selection, attribute.span.slice(new_vert_range)); + break; + case ATTR_DOMAIN_EDGE: + attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { + using T = decltype(dummy); + MutableSpan<T> data = attribute.span.typed<T>(); /* New edge values are mixed from of all the edges connected to the source vertex. */ copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) { return vert_to_edge_map[selection[i]].as_span(); }); - break; - } - default: - BLI_assert_unreachable(); - } - }); + }); + break; + default: + BLI_assert_unreachable(); + } attribute.finish(); return true; @@ -506,6 +490,9 @@ static void extrude_mesh_edges(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { @@ -518,13 +505,14 @@ static void extrude_mesh_edges(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attribute values from their source vertex. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range); - copy_with_mask(duplicate_data, data.as_span(), edge_selection); + array_utils::gather(data.as_span(), edge_selection, duplicate_data); /* Edges connected to original vertices mix values of selected connected edges. */ MutableSpan<T> connect_data = data.slice(connect_edge_range); @@ -889,6 +877,9 @@ static void extrude_mesh_face_regions(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { @@ -901,17 +892,18 @@ static void extrude_mesh_face_regions(Mesh &mesh, switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attributes from their original vertices. */ - copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); + array_utils::gather( + data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range)); break; } case ATTR_DOMAIN_EDGE: { /* Edges parallel to original edges copy the edge attributes from the original edges. */ MutableSpan<T> boundary_data = data.slice(boundary_edge_range); - copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices); + array_utils::gather(data.as_span(), boundary_edge_indices.as_span(), boundary_data); /* Edges inside of face regions also just duplicate their source data. */ MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range); - copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices); + array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data); /* Edges connected to original vertices mix values of selected connected edges. */ MutableSpan<T> connect_data = data.slice(connect_edge_range); @@ -923,8 +915,8 @@ static void extrude_mesh_face_regions(Mesh &mesh, case ATTR_DOMAIN_FACE: { /* New faces on the side of extrusions get the values from the corresponding selected * face. */ - copy_with_indices( - data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices); + array_utils::gather( + data.as_span(), edge_extruded_face_indices.as_span(), data.slice(side_poly_range)); break; } case ATTR_DOMAIN_CORNER: { @@ -1143,6 +1135,9 @@ static void extrude_individual_mesh_faces(Mesh &mesh, MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc index 613425716d4..95a0013a9e1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc @@ -47,6 +47,9 @@ static void mesh_flip_faces(Mesh &mesh, const Field<bool> &selection_field) MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all( [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } if (meta_data.domain == ATTR_DOMAIN_CORNER) { GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type); diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index affeb43e33b..64546684186 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -2,6 +2,7 @@ #include "DNA_collection_types.h" +#include "BLI_array_utils.hh" #include "BLI_hash.h" #include "BLI_task.hh" @@ -172,18 +173,7 @@ static void add_instances_from_component( dst_attribute_opt = instance_attributes.get_for_write(attribute_id); } BLI_assert(dst_attribute_opt); - const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len); - threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { - attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { - using T = decltype(dummy); - VArray<T> src = src_attribute.typed<T>(); - MutableSpan<T> dst = dst_attribute.typed<T>(); - for (const int range_i : selection_range) { - const int i = selection[range_i]; - dst[range_i] = src[i]; - } - }); - }); + array_utils::gather(src_attribute, selection, dst_attribute_opt->slice(start_len, select_len)); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index ec9b9faf4ec..ea2646a9786 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -31,6 +31,9 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info( if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) { return true; } + if (meta_data.data_type == CD_PROP_STRING) { + return true; + } info.add_or_modify( attribute_id, [&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; }, diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index bf064c6fcbe..dc35607fe45 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -45,7 +45,7 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - const float4x4 &object_matrix = object->obmat; + const float4x4 &object_matrix = object->object_to_world; const float4x4 transform = float4x4(self_object->imat) * object_matrix; if (transform_space_relative) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc index 44851a0ade5..95bf7199d63 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc @@ -240,7 +240,11 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_default_remaining_outputs(); return; } - if (mesh->totpoly == 0 && mesh->totvert != 0) { + if (mesh->totvert == 0) { + params.set_default_remaining_outputs(); + return; + } + if (mesh->totpoly == 0) { params.error_message_add(NodeWarningType::Error, TIP_("The source mesh must have faces")); params.set_default_remaining_outputs(); return; diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 5bf245f1832..197f0997160 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -604,6 +604,7 @@ class LazyFunctionForGroupNode : public LazyFunction { private: const bNode &group_node_; bool has_many_nodes_ = false; + bool use_fallback_outputs_ = false; std::optional<GeometryNodesLazyFunctionLogger> lf_logger_; std::optional<GeometryNodesLazyFunctionSideEffectProvider> lf_side_effect_provider_; std::optional<lf::GraphExecutor> graph_executor_; @@ -640,6 +641,9 @@ class LazyFunctionForGroupNode : public LazyFunction { } } } + else { + use_fallback_outputs_ = true; + } lf_logger_.emplace(lf_graph_info); lf_side_effect_provider_.emplace(); @@ -660,6 +664,11 @@ class LazyFunctionForGroupNode : public LazyFunction { * if every individual node is very small. */ lazy_threading::send_hint(); } + if (use_fallback_outputs_) { + /* The node group itself does not have an output node, so use default values as outputs. + * The group should still be executed in case it has side effects. */ + params.set_default_remaining_outputs(); + } /* The compute context changes when entering a node group. */ bke::NodeGroupComputeContext compute_context{user_data->compute_context, group_node_.name}; diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc index 724d6f1a1e1..af783ca391f 100644 --- a/source/blender/nodes/intern/node_exec.cc +++ b/source/blender/nodes/intern/node_exec.cc @@ -162,7 +162,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, /* XXX could let callbacks do this for specialized data */ exec = MEM_cnew<bNodeTreeExec>("node tree execution data"); - /* backpointer to node tree */ + /* Back-pointer to node tree. */ exec->nodetree = ntree; /* set stack indices */ diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index dc07f52e23f..55bf409444e 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -27,7 +27,7 @@ struct bNodeTree; /* Node execution data */ typedef struct bNodeExec { - /** Backpointer to node. */ + /** Back-pointer to node. */ struct bNode *node; bNodeExecData data; @@ -37,7 +37,7 @@ typedef struct bNodeExec { /* Execution Data for each instance of node tree execution */ typedef struct bNodeTreeExec { - struct bNodeTree *nodetree; /* backpointer to node tree */ + struct bNodeTree *nodetree; /* Back-pointer to node tree. */ int totnodes; /* total node count */ struct bNodeExec *nodeexec; /* per-node execution data */ diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index 52edf68b3ff..f177fc95ef8 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -1126,7 +1126,8 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec) bNodeTree *ntree = exec->nodetree; ntreeShaderEndExecTree_internal(exec); - /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */ + /* XXX: clear node-tree back-pointer to exec data, + * same problem as noted in #ntreeBeginExecTree. */ ntree->execdata = nullptr; } } diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt index 77db71d4b1a..2d704ac2228 100644 --- a/source/blender/nodes/texture/CMakeLists.txt +++ b/source/blender/nodes/texture/CMakeLists.txt @@ -2,7 +2,7 @@ set(INC . - ../ + .. ../intern ../../editors/include ../../blenkernel diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 81d0b0fbc84..99146f1a25c 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -308,7 +308,8 @@ void ntreeTexEndExecTree(bNodeTreeExec *exec) bNodeTree *ntree = exec->nodetree; ntreeTexEndExecTree_internal(exec); - /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */ + /* XXX: clear node-tree back-pointer to exec data, + * same problem as noted in #ntreeBeginExecTree. */ ntree->execdata = NULL; } } diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c index b877e3ceb98..c6e964405fa 100644 --- a/source/blender/python/gpu/gpu_py_platform.c +++ b/source/blender/python/gpu/gpu_py_platform.c @@ -11,6 +11,7 @@ #include "BLI_utildefines.h" +#include "GPU_context.h" #include "GPU_platform.h" #include "gpu_py_platform.h" /* Own include. */ @@ -83,6 +84,30 @@ static PyObject *pygpu_platform_device_type_get(PyObject *UNUSED(self)) return PyUnicode_FromString("UNKNOWN"); } +PyDoc_STRVAR(pygpu_platform_backend_type_get_doc, + ".. function:: backend_type_get()\n" + "\n" + " Get actuve GPU backend.\n" + "\n" + " :return: Backend type ('OPENGL', 'VULKAN', 'METAL', 'NONE', 'UNKNOWN').\n" + " :rtype: str\n"); +static PyObject *pygpu_platform_backend_type_get(PyObject *UNUSED(self)) +{ + switch (GPU_backend_get_type()) { + case GPU_BACKEND_VULKAN: + return PyUnicode_FromString("VULKAN"); + case GPU_BACKEND_METAL: + return PyUnicode_FromString("METAL"); + case GPU_BACKEND_NONE: + return PyUnicode_FromString("NONE"); + case GPU_BACKEND_OPENGL: + return PyUnicode_FromString("OPENGL"); + case GPU_BACKEND_ANY: + break; + } + return PyUnicode_FromString("UNKNOWN"); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -106,6 +131,10 @@ static struct PyMethodDef pygpu_platform__tp_methods[] = { (PyCFunction)pygpu_platform_device_type_get, METH_NOARGS, pygpu_platform_device_type_get_doc}, + {"backend_type_get", + (PyCFunction)pygpu_platform_backend_type_get, + METH_NOARGS, + pygpu_platform_backend_type_get_doc}, {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/python/intern/bpy_gizmo_wrap.h b/source/blender/python/intern/bpy_gizmo_wrap.h index 6a876747e22..7d5edebed0f 100644 --- a/source/blender/python/intern/bpy_gizmo_wrap.h +++ b/source/blender/python/intern/bpy_gizmo_wrap.h @@ -13,7 +13,7 @@ struct wmGizmoType; extern "C" { #endif -/* exposed to rna/wm api */ +/* Exposed to RNA/WM API. */ void BPY_RNA_gizmo_wrapper(struct wmGizmoType *gzt, void *userdata); void BPY_RNA_gizmogroup_wrapper(struct wmGizmoGroupType *gzgt, void *userdata); diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h index de3779332da..4b8ceba5f0c 100644 --- a/source/blender/python/intern/bpy_operator_wrap.h +++ b/source/blender/python/intern/bpy_operator_wrap.h @@ -12,10 +12,11 @@ struct wmOperatorType; extern "C" { #endif -/* these are used for operator methods, used by bpy_operator.c */ +/** These are used for operator methods, used by `bpy_operator.c`. */ PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args); -/* exposed to rna/wm api */ +/* Exposed to RNA/WM API. */ + /** * Generic function used by all Python defined operators * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration. diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 0eaa5d6b6c7..02f7e16e805 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -380,10 +380,10 @@ static short pyrna_rotation_euler_order_get(PointerRNA *ptr, const short order_fallback, PropertyRNA **r_prop_eul_order); -/* bpyrna vector/euler/quat callbacks. */ +/* `bpyrna` vector/euler/quaternion callbacks. */ static uchar mathutils_rna_array_cb_index = -1; /* Index for our callbacks. */ -/* Subtype not used much yet. */ +/* Sub-type not used much yet. */ # define MATHUTILS_CB_SUBTYPE_EUL 0 # define MATHUTILS_CB_SUBTYPE_VEC 1 # define MATHUTILS_CB_SUBTYPE_QUAT 2 diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c index 3a3297f27f7..3c564142160 100644 --- a/source/blender/python/mathutils/mathutils_noise.c +++ b/source/blender/python/mathutils/mathutils_noise.c @@ -40,7 +40,7 @@ * * Any feedback is very welcome. * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html - * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space). */ + * email: `m-mat @ math.sci.hiroshima-u.ac.jp` (remove space). */ /* Period parameters */ #define N 624 @@ -120,7 +120,7 @@ static void setRndSeed(int seed) } } -/* float number in range [0, 1) using the mersenne twister rng */ +/* Float number in range [0, 1) using the mersenne twister random number generator. */ static float frand(void) { ulong y; diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c index 8fd62f7ec34..9b56e18bb26 100644 --- a/source/blender/render/intern/bake.c +++ b/source/blender/render/intern/bake.c @@ -967,7 +967,7 @@ void RE_bake_normal_world_to_object(const BakePixel pixel_array[], size_t i; float iobmat[4][4]; - invert_m4_m4(iobmat, ob->obmat); + invert_m4_m4(iobmat, ob->object_to_world); for (i = 0; i < pixels_num; i++) { size_t offset; diff --git a/source/blender/render/intern/engine.cc b/source/blender/render/intern/engine.cc index 5eb4db6faa4..b8757d33580 100644 --- a/source/blender/render/intern/engine.cc +++ b/source/blender/render/intern/engine.cc @@ -969,6 +969,40 @@ static void engine_render_view_layer(Render *re, engine_depsgraph_exit(engine); } +/* Callback function for engine_render_create_result to add all render passes to the result. */ +static void engine_render_add_result_pass_cb(void *user_data, + struct Scene *UNUSED(scene), + struct ViewLayer *view_layer, + const char *name, + int channels, + const char *chanid, + eNodeSocketDatatype UNUSED(type)) +{ + RenderResult *rr = (RenderResult *)user_data; + RE_create_render_pass(rr, name, channels, chanid, view_layer->name, RR_ALL_VIEWS, false); +} + +static RenderResult *engine_render_create_result(Render *re) +{ + RenderResult *rr = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS); + if (rr == nullptr) { + return nullptr; + } + + FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) { + RE_engine_update_render_passes( + re->engine, re->scene, view_layer, engine_render_add_result_pass_cb, rr); + } + FOREACH_VIEW_LAYER_TO_RENDER_END; + + /* Preview does not support deferred render result allocation. */ + if (re->r.scemode & R_BUTS_PREVIEW) { + render_result_passes_allocated_ensure(rr); + } + + return rr; +} + bool RE_engine_render(Render *re, bool do_all) { RenderEngineType *type = RE_engines_find(re->r.engine); @@ -1008,6 +1042,14 @@ bool RE_engine_render(Render *re, bool do_all) render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers); } + /* Create engine. */ + RenderEngine *engine = re->engine; + + if (!engine) { + engine = RE_engine_create(type); + re->engine = engine; + } + /* create render result */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); if (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW)) { @@ -1015,7 +1057,7 @@ bool RE_engine_render(Render *re, bool do_all) render_result_free(re->result); } - re->result = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = engine_render_create_result(re); } BLI_rw_mutex_unlock(&re->resultmutex); @@ -1024,6 +1066,9 @@ bool RE_engine_render(Render *re, bool do_all) if (re->draw_lock) { re->draw_lock(re->dlh, false); } + /* Free engine. */ + RE_engine_free(engine); + re->engine = nullptr; /* Too small image is handled earlier, here it could only happen if * there was no sufficient memory to allocate all passes. */ @@ -1036,14 +1081,6 @@ bool RE_engine_render(Render *re, bool do_all) re->i.cfra = re->scene->r.cfra; BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name)); - /* render */ - RenderEngine *engine = re->engine; - - if (!engine) { - engine = RE_engine_create(type); - re->engine = engine; - } - engine->flag |= RE_ENGINE_RENDERING; /* TODO: actually link to a parent which shouldn't happen */ diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index bd5c6a0f5c4..94f6e2f1509 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -262,7 +262,7 @@ RenderResult *render_result_new(Render *re, render_result_views_new(rr, &re->r); - /* check renderdata for amount of layers */ + /* Check render-data for amount of layers. */ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) { if (layername && layername[0]) { if (!STREQ(view_layer->name, layername)) { @@ -290,90 +290,8 @@ RenderResult *render_result_new(Render *re, } } -#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, name, viewname, chan_id) \ - do { \ - if (render_layer_add_pass(rr, rl, channels, name, viewname, chan_id, false) == nullptr) { \ - render_result_free(rr); \ - return nullptr; \ - } \ - } while (false) - /* A render-layer should always have a "Combined" pass. */ render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA", false); - - if (view_layer->passflag & SCE_PASS_Z) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z"); - } - if (view_layer->passflag & SCE_PASS_VECTOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_VECTOR, view, "XYZW"); - } - if (view_layer->passflag & SCE_PASS_NORMAL) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_NORMAL, view, "XYZ"); - } - if (view_layer->passflag & SCE_PASS_POSITION) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_POSITION, view, "XYZ"); - } - if (view_layer->passflag & SCE_PASS_UV) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_UV, view, "UVA"); - } - if (view_layer->passflag & SCE_PASS_EMIT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_EMIT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_AO) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_AO, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_ENVIRONMENT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_ENVIRONMENT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SHADOW) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SHADOW, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_INDEXOB) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXOB, view, "X"); - } - if (view_layer->passflag & SCE_PASS_INDEXMA) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXMA, view, "X"); - } - if (view_layer->passflag & SCE_PASS_MIST) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_MIST, view, "Z"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_DIFFUSE_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_GLOSSY_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_TRANSM_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_COLOR, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_DIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_INDIRECT, view, "RGB"); - } - if (view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) { - RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB"); - } -#undef RENDER_LAYER_ADD_PASS_SAFE } } FOREACH_VIEW_LAYER_TO_RENDER_END; @@ -411,11 +329,6 @@ RenderResult *render_result_new(Render *re, rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2); rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2); - /* Preview does not support deferred render result allocation. */ - if (re->r.scemode & R_BUTS_PREVIEW) { - render_result_passes_allocated_ensure(rr); - } - return rr; } diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c index 2a2b62be1f0..b285bbd1459 100644 --- a/source/blender/render/intern/texture_pointdensity.c +++ b/source/blender/render/intern/texture_pointdensity.c @@ -175,7 +175,7 @@ static void pointdensity_cache_psys( sim.psmd = psys_get_modifier(ob, psys); /* in case ob->imat isn't up-to-date */ - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob->imat, ob->object_to_world); total_particles = psys->totpart + psys->totchild; psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); @@ -399,12 +399,12 @@ static void pointdensity_cache_object(PointDensity *pd, Object *ob) case TEX_PD_OBJECTSPACE: break; case TEX_PD_OBJECTLOC: - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); sub_v3_v3(co, ob->loc); break; case TEX_PD_WORLDSPACE: default: - mul_m4_v3(ob->obmat, co); + mul_m4_v3(ob->object_to_world, co); break; } @@ -778,7 +778,7 @@ static void particle_system_minmax(Depsgraph *depsgraph, sim.psys = psys; sim.psmd = psys_get_modifier(object, psys); - invert_m4_m4(imat, object->obmat); + invert_m4_m4(imat, object->object_to_world); total_particles = psys->totpart + psys->totchild; psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c index 1f52d2ea41b..596a28201cc 100644 --- a/source/blender/sequencer/intern/disk_cache.c +++ b/source/blender/sequencer/intern/disk_cache.c @@ -182,7 +182,7 @@ static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path) if (is_dir && !FILENAME_IS_CURRPAR(file)) { char subpath[FILE_MAX]; BLI_strncpy(subpath, fl->path, sizeof(subpath)); - BLI_path_slash_ensure(subpath); + BLI_path_slash_ensure(subpath, sizeof(sizeof(subpath))); seq_disk_cache_get_files(disk_cache, subpath); } @@ -291,8 +291,8 @@ static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, /* Use suffix, so that the cache directory name does not conflict with the bmain's blend file. */ const char *suffix = "_seq_cache"; strncat(cache_dir, suffix, sizeof(cache_dir) - strlen(cache_dir) - 1); - BLI_strncpy(path, seq_disk_cache_base_dir(), path_len); - BLI_path_append(path, path_len, cache_dir); + + BLI_path_join(path, path_len, seq_disk_cache_base_dir(), cache_dir); } static void seq_disk_cache_get_dir( @@ -307,9 +307,8 @@ static void seq_disk_cache_get_dir( BLI_strncpy(seq_name, seq->name, sizeof(seq_name)); BLI_filename_make_safe(scene_name); BLI_filename_make_safe(seq_name); - BLI_strncpy(path, project_dir, path_len); - BLI_path_append(path, path_len, scene_name); - BLI_path_append(path, path_len, seq_name); + + BLI_path_join(path, path_len, project_dir, scene_name, seq_name); } static void seq_disk_cache_get_file_path(SeqDiskCache *disk_cache, @@ -350,8 +349,7 @@ static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache) int version = 0; seq_disk_cache_get_project_dir(disk_cache, filepath, sizeof(filepath)); - BLI_strncpy(path_version_file, filepath, sizeof(path_version_file)); - BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version"); + BLI_path_join(path_version_file, sizeof(path_version_file), filepath, "cache_version"); if (BLI_exists(filepath) && BLI_is_dir(filepath)) { FILE *file = BLI_fopen(path_version_file, "r"); @@ -384,7 +382,7 @@ static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache, DiskCacheFile *next_file, *cache_file = disk_cache->files.first; char cache_dir[FILE_MAX]; seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir)); - BLI_path_slash_ensure(cache_dir); + BLI_path_slash_ensure(cache_dir, sizeof(cache_dir)); while (cache_file) { next_file = cache_file->next; diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index 9f08db2aa45..fc1df4dc3ac 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -585,8 +585,7 @@ void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir) char fname[FILE_MAXFILE]; IMB_anim_get_fname(anim, fname, FILE_MAXFILE); - BLI_strncpy(dir, base_dir, sizeof(dir)); - BLI_path_append(dir, sizeof(dir), fname); + BLI_path_join(dir, sizeof(dir), base_dir, fname); IMB_anim_set_index_dir(anim, dir); } diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index dbbece73695..e3fd9216842 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -1026,6 +1026,15 @@ static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *cont return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE); } +static IMB_Timecode_Type seq_render_movie_strip_timecode_get(Sequence *seq) +{ + bool use_timecodes = (seq->flag & SEQ_USE_PROXY) != 0; + if (!use_timecodes) { + return IMB_TC_NONE; + } + return seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_NONE; +} + /** * Render individual view for multi-view or single (default view) for mono-view. */ @@ -1049,7 +1058,7 @@ static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context, else { ibuf = IMB_anim_absolute(sanim->anim, frame_index + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + seq_render_movie_strip_timecode_get(seq), psize); } @@ -1062,7 +1071,7 @@ static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context, if (ibuf == NULL) { ibuf = IMB_anim_absolute(sanim->anim, frame_index + seq->anim_startofs, - seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, + seq_render_movie_strip_timecode_get(seq), IMB_PROXY_NONE); } if (ibuf == NULL) { diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 9a664456b9c..038438ff151 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -361,7 +361,7 @@ typedef struct wmNotifier { /* data type, 256 entries is enough, it can overlap */ #define NOTE_DATA 0x00FF0000 -/* NC_WM windowmanager */ +/* NC_WM (window-manager). */ #define ND_FILEREAD (1 << 16) #define ND_FILESAVE (2 << 16) #define ND_DATACHANGED (3 << 16) diff --git a/source/blender/windowmanager/intern/wm_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc index 0896daec561..fb63abed9e9 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.cc +++ b/source/blender/windowmanager/intern/wm_dragdrop.cc @@ -853,7 +853,8 @@ static void wm_drag_draw_icon(bContext * /*C*/, wmWindow * /*win*/, wmDrag *drag y = xy[1] - 2 * UI_DPI_FAC; const uchar text_col[] = {255, 255, 255, 255}; - UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); + UI_icon_draw_ex( + x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } } diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index affe0bcf45a..181ec89cabd 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -5620,7 +5620,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case GHOST_kEventNDOFButton: { GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata); - event.type = NDOF_BUTTON_NONE + e->button; + event.type = NDOF_BUTTON_INDEX_AS_EVENT(e->button); switch (e->action) { case GHOST_kPress: diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index bf793ee41a0..3e5399a6f56 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -59,6 +59,8 @@ #include "DEG_depsgraph.h" +#include "wm_window_private.h" + #include "WM_api.h" /* only for WM_main_playanim */ #ifdef WITH_AUDASPACE @@ -1340,6 +1342,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey) { GHOST_GLSettings glsettings = {0}; + const eGPUBackendType gpu_backend = GPU_backend_type_selection_get(); + glsettings.context_type = wm_ghost_drawing_context_type(gpu_backend); uint32_t scr_w, scr_h; GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h); @@ -1356,7 +1360,6 @@ static void playanim_window_open(const char *title, int posx, int posy, int size /* Could optionally start full-screen. */ GHOST_kWindowStateNormal, false, - GHOST_kDrawingContextTypeOpenGL, glsettings); } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 30fbb855871..292d58b80d1 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -574,6 +574,9 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, glSettings.flags |= GHOST_glDebugContext; } + eGPUBackendType gpu_backend = GPU_backend_type_selection_get(); + glSettings.context_type = wm_ghost_drawing_context_type(gpu_backend); + int scr_w, scr_h; wm_get_desktopsize(&scr_w, &scr_h); int posy = (scr_h - win->posy - win->sizey); @@ -591,7 +594,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, win->sizey, (GHOST_TWindowState)win->windowstate, is_dialog, - GHOST_kDrawingContextTypeOpenGL, glSettings); if (ghostwin) { @@ -1662,6 +1664,32 @@ const char *WM_ghost_backend(void) #endif } +GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend) +{ + switch (gpu_backend) { + case GPU_BACKEND_NONE: + return GHOST_kDrawingContextTypeNone; + case GPU_BACKEND_ANY: + case GPU_BACKEND_OPENGL: + return GHOST_kDrawingContextTypeOpenGL; + case GPU_BACKEND_VULKAN: + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; + case GPU_BACKEND_METAL: +#ifdef WITH_METAL_BACKEND + return GHOST_kDrawingContextTypeMetal; +#else + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; +#endif + } + + /* Avoid control reaches end of non-void function compilation warning, which could be promoted + * to error. */ + BLI_assert_unreachable(); + return GHOST_kDrawingContextTypeNone; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h index f68d4e3e693..dad3e749817 100644 --- a/source/blender/windowmanager/intern/wm_window_private.h +++ b/source/blender/windowmanager/intern/wm_window_private.h @@ -7,8 +7,11 @@ #pragma once #include "BLI_sys_types.h" + #include "GHOST_Types.h" +#include "GPU_context.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 @@ -21,3 +24,5 @@ void WM_ghost_show_message_box(const char *title, const char *continue_label, const char *link, GHOST_DialogOptions dialog_options); + +GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend); diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 0b54560c56a..0a27b9c1cfd 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -45,12 +45,12 @@ extern void wm_close_and_free_all(bContext *C, ListBase *); extern void wm_add_default(struct Main *bmain, bContext *C); extern void wm_clear_default_size(bContext *C); -/* register to windowmanager for redo or macro */ +/* Register to window-manager for redo or macro. */ /** * Called on event handling by `event_system.c`. * - * All operations get registered in the windowmanager here. + * All operations get registered in the window-manager here. */ void wm_operator_register(bContext *C, wmOperator *op); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 405b7225bd5..c36c57a12ae 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -252,8 +252,6 @@ enum { #define _NDOF_MIN NDOF_MOTION #define _NDOF_BUTTON_MIN NDOF_BUTTON_MENU - /* used internally, never sent */ - NDOF_BUTTON_NONE = NDOF_MOTION, /* these two are available from any 3Dconnexion device */ NDOF_BUTTON_MENU = 0x0191, /* 401 */ @@ -281,35 +279,42 @@ enum { NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */ NDOF_BUTTON_PLUS = 0x01a4, /* 420 */ NDOF_BUTTON_MINUS = 0x01a5, /* 421 */ + /* General-purpose buttons. */ + NDOF_BUTTON_1 = 0x01a6, /* 422 */ + NDOF_BUTTON_2 = 0x01a7, /* 423 */ + NDOF_BUTTON_3 = 0x01a8, /* 424 */ + NDOF_BUTTON_4 = 0x01a9, /* 425 */ + NDOF_BUTTON_5 = 0x01aa, /* 426 */ + NDOF_BUTTON_6 = 0x01ab, /* 427 */ + NDOF_BUTTON_7 = 0x01ac, /* 428 */ + NDOF_BUTTON_8 = 0x01ad, /* 429 */ + NDOF_BUTTON_9 = 0x01ae, /* 430 */ + NDOF_BUTTON_10 = 0x01af, /* 431 */ + /* more general-purpose buttons */ + NDOF_BUTTON_A = 0x01b0, /* 432 */ + NDOF_BUTTON_B = 0x01b1, /* 433 */ + NDOF_BUTTON_C = 0x01b2, /* 434 */ + /* Store/restore views. */ + NDOF_BUTTON_V1 = 0x01b3, /* 435 */ + NDOF_BUTTON_V2 = 0x01b4, /* 436 */ + NDOF_BUTTON_V3 = 0x01b5, /* 437 */ /* Disabled as GHOST converts these to keyboard events * which use regular keyboard event handling logic. */ #if 0 /* keyboard emulation */ - NDOF_BUTTON_ESC = 0x01a6, /* 422 */ - NDOF_BUTTON_ALT = 0x01a7, /* 423 */ - NDOF_BUTTON_SHIFT = 0x01a8, /* 424 */ - NDOF_BUTTON_CTRL = 0x01a9, /* 425 */ + NDOF_BUTTON_ESC = 0x01b6, /* 438 */ + NDOF_BUTTON_ENTER = 0x01b7, /* 439 */ + NDOF_BUTTON_DELETE = 0x01b8, /* 440 */ + NDOF_BUTTON_TAB = 0x01b9, /* 441 */ + NDOF_BUTTON_SPACE = 0x01ba, /* 442 */ + NDOF_BUTTON_ALT = 0x01bb, /* 443 */ + NDOF_BUTTON_SHIFT = 0x01bc, /* 444 */ + NDOF_BUTTON_CTRL = 0x01bd, /* 445 */ #endif - /* general-purpose buttons */ - NDOF_BUTTON_1 = 0x01aa, /* 426 */ - NDOF_BUTTON_2 = 0x01ab, /* 427 */ - NDOF_BUTTON_3 = 0x01ac, /* 428 */ - NDOF_BUTTON_4 = 0x01ad, /* 429 */ - NDOF_BUTTON_5 = 0x01ae, /* 430 */ - NDOF_BUTTON_6 = 0x01af, /* 431 */ - NDOF_BUTTON_7 = 0x01b0, /* 432 */ - NDOF_BUTTON_8 = 0x01b1, /* 433 */ - NDOF_BUTTON_9 = 0x01b2, /* 434 */ - NDOF_BUTTON_10 = 0x01b3, /* 435 */ - /* more general-purpose buttons */ - NDOF_BUTTON_A = 0x01b4, /* 436 */ - NDOF_BUTTON_B = 0x01b5, /* 437 */ - NDOF_BUTTON_C = 0x01b6, /* 438 */ - -#define _NDOF_MAX NDOF_BUTTON_C -#define _NDOF_BUTTON_MAX NDOF_BUTTON_C +#define _NDOF_MAX NDOF_BUTTON_V3 +#define _NDOF_BUTTON_MAX NDOF_BUTTON_V3 /* ********** End of Input devices. ********** */ @@ -449,6 +454,8 @@ enum eEventType_Mask { (EVT_TYPE_MASK_KEYBOARD | EVT_TYPE_MASK_MOUSE | EVT_TYPE_MASK_NDOF) #define EVT_TYPE_MASK_HOTKEY_EXCLUDE EVT_TYPE_MASK_KEYBOARD_MODIFIER +#define NDOF_BUTTON_INDEX_AS_EVENT(i) (_NDOF_BUTTON_MIN + (i)) + bool WM_event_type_mask_test(int event_type, enum eEventType_Mask mask); /** \} */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index abc41833de6..aefc3afff66 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -178,7 +178,7 @@ static void wm_xr_session_base_pose_calc(const Scene *scene, float tmp_quat[4]; float tmp_eul[3]; - mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat); + mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->object_to_world); /* Only use rotation around Z-axis to align view with floor. */ quat_to_eul(tmp_eul, tmp_quat); diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index caaffa283ba..bb9e73c0895 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1077,6 +1077,13 @@ elseif(WIN32) ) endif() + if(WITH_PYTHON_MODULE AND TARGETDIR_BPY) + install( + TARGETS blender + LIBRARY DESTINATION ${TARGETDIR_BPY} + ) + endif() + if(PLATFORM_BUNDLED_LIBRARIES) install( FILES ${PLATFORM_BUNDLED_LIBRARIES} diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 06b898587bf..2ebdcdb35ba 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -42,6 +42,8 @@ # include "BKE_scene.h" # include "BKE_sound.h" +# include "GPU_context.h" + # ifdef WITH_FFMPEG # include "IMB_imbuf.h" # endif @@ -1111,6 +1113,52 @@ static int arg_handle_debug_gpu_set(int UNUSED(argc), return 0; } +static const char arg_handle_gpu_backend_set_doc[] = + "\n" + "\tForce to use a specific GPU backend. Valid options: " +# ifdef WITH_VULKAN_BACKEND + "'vulkan', " +# endif +# ifdef WITH_METAL_BACKEND + "'metal', " +# endif + "'opengl'."; +static int arg_handle_gpu_backend_set(int argc, const char **argv, void *UNUSED(data)) +{ + if (argc == 0) { + printf("\nError: GPU backend must follow '--gpu-backend'.\n"); + return 0; + } + + eGPUBackendType gpu_backend = GPU_BACKEND_NONE; + + if (STREQ(argv[1], "opengl")) { + gpu_backend = GPU_BACKEND_OPENGL; + } +# ifdef WITH_VULKAN_BACKEND + else if (STREQ(argv[1], "vulkan")) { + gpu_backend = GPU_BACKEND_VULKAN; + } +# endif +# ifdef WITH_METAL_BACKEND + else if (STREQ(argv[1], "metal")) { + gpu_backend = GPU_BACKEND_METAL; + } +# endif + else { + printf("\nError: Unrecognized GPU backend for '--gpu-backend'.\n"); + return 0; + } + + GPU_backend_type_selection_set(gpu_backend); + if (!GPU_backend_supported()) { + printf("\nError: GPU backend not supported.\n"); + return 0; + } + + return 1; +} + static const char arg_handle_debug_fpe_set_doc[] = "\n\t" "Enable floating-point exceptions."; @@ -2074,6 +2122,10 @@ void main_args_setup(bContext *C, bArgs *ba) BLI_args_add(ba, NULL, "--log-show-timestamp", CB(arg_handle_log_show_timestamp_set), ba); BLI_args_add(ba, NULL, "--log-file", CB(arg_handle_log_file_set), ba); + /* GPU backend selection should be part of ARG_PASS_ENVIRONMENT for correct GPU context selection + * for anim player. */ + BLI_args_add(ba, NULL, "--gpu-backend", CB(arg_handle_gpu_backend_set), NULL); + /* Pass: Background Mode & Settings * * Also and commands that exit after usage. */ |