Compare commits
114 Commits
tmp-T95052
...
temp-T9490
Author | SHA1 | Date | |
---|---|---|---|
e94cd5eeed | |||
1bf6a880ab | |||
![]() |
a21bca0e20 | ||
b3bf46b78d | |||
0cb5eae9d0 | |||
1758dcd423 | |||
9338126ecc | |||
46ae083113 | |||
b06fff4737 | |||
94d2a611ec | |||
37e555d2fe | |||
086f191169 | |||
4c951bfa82 | |||
4530449317 | |||
c4bedeb018 | |||
83094d9a0d | |||
c1b5cea63a | |||
b45e71e22c | |||
597eaeaa11 | |||
52b2769b9c | |||
c847122096 | |||
1687903fb8 | |||
c89d6b0953 | |||
2637f94358 | |||
3e2591c83e | |||
0ec94d5359 | |||
932d8dba52 | |||
ec1b0c2014 | |||
97a023a0d5 | |||
e2a36a6e45 | |||
f26c36c96b | |||
c813a1b358 | |||
eab066cbf2 | |||
![]() |
2ed73fc97e | ||
a18bd403bf | |||
96667e3391 | |||
6c25aabddf | |||
0477ca75f0 | |||
![]() |
14f6afb090 | ||
368bfa80f9 | |||
460e0a1347 | |||
33ba298b5d | |||
![]() |
948211679f | ||
![]() |
3f42417cd4 | ||
196da819ba | |||
31296f6f9d | |||
0f89bcdbeb | |||
c5980ada4f | |||
![]() |
17b0c06946 | ||
a000de7c2a | |||
a54142f3f1 | |||
1b1693d43f | |||
2e9b8689e4 | |||
a2301b1d91 | |||
114b06b3cb | |||
2bf519d211 | |||
4d799db72f | |||
5a0c5912a4 | |||
083de503ce | |||
04c3b08518 | |||
263f862ba5 | |||
e2337b5342 | |||
90d61600fc | |||
![]() |
e673cfc2d7 | ||
25fa5792e6 | |||
a215d7e230 | |||
0928fe8710 | |||
4c617c06e9 | |||
796ef560b4 | |||
578baf95e0 | |||
e774f2c901 | |||
7708a848c9 | |||
4b1f243e4d | |||
f9b6a257bd | |||
95981c9876 | |||
46475b8e11 | |||
43e3a33082 | |||
c69a581c0b | |||
abf30007ab | |||
38c7378949 | |||
807c58aae4 | |||
889712927f | |||
5c4a5fd40d | |||
6cd977b903 | |||
dde997086c | |||
579e8ebe79 | |||
5ae76fae90 | |||
e88d966737 | |||
25c99e72cd | |||
b7878a4d45 | |||
![]() |
9350005d8b | ||
1f026a3db9 | |||
![]() |
45d038181a | ||
d590e223da | |||
68aa35ae74 | |||
294ab84909 | |||
1c23a06706 | |||
e07b217669 | |||
32ceb0b807 | |||
4f9be46526 | |||
54d69a2fd1 | |||
9d274a609c | |||
58f8eb54a3 | |||
![]() |
5b90c046d5 | ||
c20f209b1c | |||
59fc95bf97 | |||
d034b85f33 | |||
![]() |
c39d514a4e | ||
4251455dcd | |||
87c5423c5e | |||
![]() |
d68ce0e475 | ||
5e51a5e8a4 | |||
93065a67c6 | |||
f6888b530a |
@@ -273,11 +273,13 @@ endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(WITH_SYSTEM_GLEW "Use GLEW OpenGL wrapper library provided by the operating system" OFF)
|
||||
option(WITH_SYSTEM_GLES "Use OpenGL ES library provided by the operating system" ON)
|
||||
option(WITH_SYSTEM_GLEW "Use GLEW OpenGL wrapper library provided by the operating system" OFF)
|
||||
option(WITH_SYSTEM_FREETYPE "Use the freetype library provided by the operating system" OFF)
|
||||
else()
|
||||
# not an option for other OS's
|
||||
set(WITH_SYSTEM_GLEW OFF)
|
||||
set(WITH_SYSTEM_GLES OFF)
|
||||
set(WITH_SYSTEM_FREETYPE OFF)
|
||||
endif()
|
||||
|
||||
|
||||
|
@@ -63,6 +63,7 @@ include(cmake/jpeg.cmake)
|
||||
include(cmake/blosc.cmake)
|
||||
include(cmake/pthreads.cmake)
|
||||
include(cmake/openexr.cmake)
|
||||
include(cmake/brotli.cmake)
|
||||
include(cmake/freetype.cmake)
|
||||
include(cmake/freeglut.cmake)
|
||||
include(cmake/glew.cmake)
|
||||
|
@@ -25,8 +25,13 @@ else()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(BOOST_TOOLSET toolset=msvc-14.1)
|
||||
set(BOOST_COMPILER_STRING -vc141)
|
||||
if(MSVC_VERSION GREATER_EQUAL 1920) # 2019
|
||||
set(BOOST_TOOLSET toolset=msvc-14.2)
|
||||
set(BOOST_COMPILER_STRING -vc142)
|
||||
else() # 2017
|
||||
set(BOOST_TOOLSET toolset=msvc-14.1)
|
||||
set(BOOST_COMPILER_STRING -vc141)
|
||||
endif()
|
||||
|
||||
set(BOOST_CONFIGURE_COMMAND bootstrap.bat)
|
||||
set(BOOST_BUILD_COMMAND b2)
|
||||
|
38
build_files/build_environment/cmake/brotli.cmake
Normal file
38
build_files/build_environment/cmake/brotli.cmake
Normal file
@@ -0,0 +1,38 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
set(BROTLI_EXTRA_ARGS
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_brotli
|
||||
URL file://${PACKAGE_DIR}/${BROTLI_FILE}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
URL_HASH ${BROTLI_HASH_TYPE}=${BROTLI_HASH}
|
||||
PREFIX ${BUILD_DIR}/brotli
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/brotli ${DEFAULT_CMAKE_FLAGS} ${BROTLI_EXTRA_ARGS}
|
||||
INSTALL_DIR ${LIBDIR}/brotli
|
||||
)
|
||||
|
||||
if(BUILD_MODE STREQUAL Release AND WIN32)
|
||||
ExternalProject_Add_Step(external_brotli after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/brotli/include ${HARVEST_TARGET}/brotli/include
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/brotli/lib/brotlidec-static${LIBEXT} ${HARVEST_TARGET}/brotli/lib/brotlidec-static${LIBEXT}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/brotli/lib/brotlicommon-static${LIBEXT} ${HARVEST_TARGET}/brotli/lib/brotlicommon-static${LIBEXT}
|
||||
DEPENDEES install
|
||||
)
|
||||
endif()
|
@@ -94,3 +94,4 @@ download_source(POTRACE)
|
||||
download_source(HARU)
|
||||
download_source(ZSTD)
|
||||
download_source(FLEX)
|
||||
download_source(BROTLI)
|
||||
|
@@ -23,9 +23,12 @@ set(FREETYPE_EXTRA_ARGS
|
||||
-DWITH_HarfBuzz=OFF
|
||||
-DFT_WITH_HARFBUZZ=OFF
|
||||
-DFT_WITH_BZIP2=OFF
|
||||
-DFT_WITH_BROTLI=ON
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_HarfBuzz=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_BZip2=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec=TRUE)
|
||||
-DPC_BROTLIDEC_INCLUDEDIR=${LIBDIR}/brotli/include
|
||||
-DPC_BROTLIDEC_LIBDIR=${LIBDIR}/brotli/lib
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_freetype
|
||||
URL file://${PACKAGE_DIR}/${FREETYPE_FILE}
|
||||
@@ -36,6 +39,11 @@ ExternalProject_Add(external_freetype
|
||||
INSTALL_DIR ${LIBDIR}/freetype
|
||||
)
|
||||
|
||||
add_dependencies(
|
||||
external_freetype
|
||||
external_brotli
|
||||
)
|
||||
|
||||
if(BUILD_MODE STREQUAL Release AND WIN32)
|
||||
ExternalProject_Add_Step(external_freetype after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/freetype ${HARVEST_TARGET}/freetype
|
||||
|
@@ -79,6 +79,8 @@ endfunction()
|
||||
harvest(alembic/include alembic/include "*.h")
|
||||
harvest(alembic/lib/libAlembic.a alembic/lib/libAlembic.a)
|
||||
harvest(alembic/bin alembic/bin "*")
|
||||
harvest(brotli/include brotli/include "*.h")
|
||||
harvest(brotli/lib brotli/lib "*.a")
|
||||
harvest(boost/include boost/include "*")
|
||||
harvest(boost/lib boost/lib "*.a")
|
||||
harvest(ffmpeg/include ffmpeg/include "*.h")
|
||||
|
@@ -83,9 +83,9 @@ else()
|
||||
set(OPENEXR_VERSION_POSTFIX)
|
||||
endif()
|
||||
|
||||
set(FREETYPE_VERSION 2.10.2)
|
||||
set(FREETYPE_VERSION 2.11.0)
|
||||
set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz)
|
||||
set(FREETYPE_HASH b1cb620e4c875cd4d1bfa04945400945)
|
||||
set(FREETYPE_HASH cf09172322f6b50cf8f568bf8fe14bde)
|
||||
set(FREETYPE_HASH_TYPE MD5)
|
||||
set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz)
|
||||
|
||||
@@ -500,3 +500,9 @@ set(ZSTD_FILE zstd-${ZSTD_VERSION}.tar.gz)
|
||||
|
||||
set(SSE2NEON_GIT https://github.com/DLTcollab/sse2neon.git)
|
||||
set(SSE2NEON_GIT_HASH fe5ff00bb8d19b327714a3c290f3e2ce81ba3525)
|
||||
|
||||
set(BROTLI_VERSION v1.0.9)
|
||||
set(BROTLI_URI https://github.com/google/brotli/archive/refs/tags/${BROTLI_VERSION}.tar.gz)
|
||||
set(BROTLI_HASH f9e8d81d0405ba66d181529af42a3354f838c939095ff99930da6aa9cdf6fe46)
|
||||
set(BROTLI_HASH_TYPE SHA256)
|
||||
set(BROTLI_FILE brotli-${BROTLI_VERSION}.tar.gz)
|
||||
|
@@ -1,64 +1,39 @@
|
||||
@echo off
|
||||
if NOT "%1" == "" (
|
||||
if "%1" == "2013" (
|
||||
echo "Building for VS2013"
|
||||
set VSVER=12.0
|
||||
set VSVER_SHORT=12
|
||||
set BuildDir=VS12
|
||||
goto par2
|
||||
)
|
||||
if "%1" == "2015" (
|
||||
echo "Building for VS2015"
|
||||
set VSVER=14.0
|
||||
set VSVER_SHORT=14
|
||||
set BuildDir=VS14
|
||||
goto par2
|
||||
)
|
||||
if "%1" == "2017" (
|
||||
echo "Building for VS2017"
|
||||
set VSVER=15.0
|
||||
set VSVER_SHORT=15
|
||||
set BuildDir=VS15
|
||||
goto par2
|
||||
)
|
||||
if "%1" == "2019" (
|
||||
echo "Building for VS2019"
|
||||
set VSVER=15.0
|
||||
set VSVER_SHORT=15
|
||||
set BuildDir=VS15
|
||||
goto par2
|
||||
)
|
||||
|
||||
)
|
||||
:usage
|
||||
|
||||
Echo Usage build_deps 2013/2015/2017 x64/x86
|
||||
Echo Usage build_deps 2017/2019 x64
|
||||
goto exit
|
||||
:par2
|
||||
if NOT "%2" == "" (
|
||||
if "%2" == "x86" (
|
||||
echo "Building for x86"
|
||||
set HARVESTROOT=Windows_vc
|
||||
set ARCH=86
|
||||
if "%1" == "2013" (
|
||||
set CMAKE_BUILDER=Visual Studio 12 2013
|
||||
)
|
||||
if "%1" == "2015" (
|
||||
set CMAKE_BUILDER=Visual Studio 14 2015
|
||||
)
|
||||
if "%1" == "2017" (
|
||||
set CMAKE_BUILDER=Visual Studio 15 2017
|
||||
)
|
||||
|
||||
goto start
|
||||
)
|
||||
if "%2" == "x64" (
|
||||
echo "Building for x64"
|
||||
set HARVESTROOT=Win64_vc
|
||||
set ARCH=64
|
||||
if "%1" == "2013" (
|
||||
set CMAKE_BUILDER=Visual Studio 12 2013 Win64
|
||||
)
|
||||
if "%1" == "2015" (
|
||||
set CMAKE_BUILDER=Visual Studio 14 2015 Win64
|
||||
if "%1" == "2019" (
|
||||
set CMAKE_BUILDER=Visual Studio 16 2019
|
||||
set CMAKE_BUILD_ARCH=-A x64
|
||||
)
|
||||
if "%1" == "2017" (
|
||||
set CMAKE_BUILDER=Visual Studio 15 2017 Win64
|
||||
set CMAKE_BUILD_ARCH=
|
||||
)
|
||||
|
||||
goto start
|
||||
)
|
||||
)
|
||||
@@ -120,7 +95,7 @@ set path=%BUILD_DIR%\downloads\mingw\mingw64\msys\1.0\bin\;%BUILD_DIR%\downloads
|
||||
mkdir %STAGING%\%BuildDir%%ARCH%R
|
||||
cd %Staging%\%BuildDir%%ARCH%R
|
||||
echo %DATE% %TIME% : Start > %StatusFile%
|
||||
cmake -G "%CMAKE_BUILDER%" -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DBUILD_MODE=Release -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/
|
||||
cmake -G "%CMAKE_BUILDER%" %CMAKE_BUILD_ARCH% -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DBUILD_MODE=Release -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/
|
||||
echo %DATE% %TIME% : Release Configuration done >> %StatusFile%
|
||||
if "%dobuild%" == "1" (
|
||||
msbuild /m "ll.vcxproj" /p:Configuration=Release /fl /flp:logfile=BlenderDeps_llvm.log;Verbosity=normal
|
||||
@@ -133,7 +108,7 @@ if "%NODEBUG%" == "1" goto exit
|
||||
cd %BUILD_DIR%
|
||||
mkdir %STAGING%\%BuildDir%%ARCH%D
|
||||
cd %Staging%\%BuildDir%%ARCH%D
|
||||
cmake -G "%CMAKE_BUILDER%" -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DCMAKE_BUILD_TYPE=Debug -DBUILD_MODE=Debug -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ %CMAKE_DEBUG_OPTIONS%
|
||||
cmake -G "%CMAKE_BUILDER%" %CMAKE_BUILD_ARCH% -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DCMAKE_BUILD_TYPE=Debug -DBUILD_MODE=Debug -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ %CMAKE_DEBUG_OPTIONS%
|
||||
echo %DATE% %TIME% : Debug Configuration done >> %StatusFile%
|
||||
if "%dobuild%" == "1" (
|
||||
msbuild /m "ll.vcxproj" /p:Configuration=Debug /fl /flp:logfile=BlenderDeps_llvm.log;;Verbosity=normal
|
||||
|
83
build_files/cmake/Modules/FindBrotli.cmake
Normal file
83
build_files/cmake/Modules/FindBrotli.cmake
Normal file
@@ -0,0 +1,83 @@
|
||||
# - Find Brotli library (compression for freetype/woff2).
|
||||
# This module defines
|
||||
# BROTLI_INCLUDE_DIRS, where to find Brotli headers, Set when
|
||||
# BROTLI_INCLUDE_DIR is found.
|
||||
# BROTLI_LIBRARIES, libraries to link against to use Brotli.
|
||||
# BROTLI_ROOT_DIR, The base directory to search for Brotli.
|
||||
# This can also be an environment variable.
|
||||
# BROTLI_FOUND, If false, do not try to use Brotli.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2022 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD 3-Clause License,
|
||||
# see accompanying file BSD-3-Clause-license.txt for details.
|
||||
#=============================================================================
|
||||
|
||||
# If BROTLI_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT BROTLI_ROOT_DIR AND NOT $ENV{BROTLI_ROOT_DIR} STREQUAL "")
|
||||
SET(BROTLI_ROOT_DIR $ENV{BROTLI_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_BROTLI_SEARCH_DIRS
|
||||
${BROTLI_ROOT_DIR}
|
||||
)
|
||||
|
||||
FIND_PATH(BROTLI_INCLUDE_DIR
|
||||
NAMES
|
||||
brotli/decode.h
|
||||
HINTS
|
||||
${_BROTLI_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
DOC "Brotli header files"
|
||||
)
|
||||
|
||||
FIND_LIBRARY(BROTLI_LIBRARY_COMMON
|
||||
NAMES
|
||||
# Some builds use a special `-static` postfix in their static libraries names.
|
||||
brotlicommon-static
|
||||
brotlicommon
|
||||
HINTS
|
||||
${_BROTLI_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib lib/static
|
||||
DOC "Brotli static common library"
|
||||
)
|
||||
FIND_LIBRARY(BROTLI_LIBRARY_DEC
|
||||
NAMES
|
||||
# Some builds use a special `-static` postfix in their static libraries names.
|
||||
brotlidec-static
|
||||
brotlidec
|
||||
HINTS
|
||||
${_BROTLI_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib lib/static
|
||||
DOC "Brotli static decode library"
|
||||
)
|
||||
|
||||
|
||||
IF(${BROTLI_LIBRARY_COMMON_NOTFOUND} or ${BROTLI_LIBRARY_DEC_NOTFOUND})
|
||||
set(BROTLI_FOUND FALSE)
|
||||
ELSE()
|
||||
# handle the QUIETLY and REQUIRED arguments and set BROTLI_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Brotli DEFAULT_MSG BROTLI_LIBRARY_COMMON BROTLI_LIBRARY_DEC BROTLI_INCLUDE_DIR)
|
||||
|
||||
IF(BROTLI_FOUND)
|
||||
get_filename_component(BROTLI_LIBRARY_DIR ${BROTLI_LIBRARY_COMMON} DIRECTORY)
|
||||
SET(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
|
||||
SET(BROTLI_LIBRARIES ${BROTLI_LIBRARY_DEC} ${BROTLI_LIBRARY_COMMON})
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
BROTLI_INCLUDE_DIR
|
||||
BROTLI_LIBRARY_COMMON
|
||||
BROTLI_LIBRARY_DEC
|
||||
BROTLI_LIBRARY_DIR
|
||||
)
|
||||
|
||||
UNSET(_BROTLI_SEARCH_DIRS)
|
@@ -166,7 +166,11 @@ if(WITH_FFTW3)
|
||||
find_package(Fftw3)
|
||||
endif()
|
||||
|
||||
# FreeType compiled with Brotli compression for woff2.
|
||||
find_package(Freetype REQUIRED)
|
||||
list(APPEND FREETYPE_LIBRARIES
|
||||
${LIBDIR}/brotli/lib/libbrotlicommon-static.a
|
||||
${LIBDIR}/brotli/lib/libbrotlidec-static.a)
|
||||
|
||||
if(WITH_IMAGE_OPENEXR)
|
||||
find_package(OpenEXR)
|
||||
|
@@ -48,6 +48,9 @@ if(NOT DEFINED LIBDIR)
|
||||
unset(LIBDIR_CENTOS7_ABI)
|
||||
endif()
|
||||
|
||||
# Support restoring this value once pre-compiled libraries have been handled.
|
||||
set(WITH_STATIC_LIBS_INIT ${WITH_STATIC_LIBS})
|
||||
|
||||
if(EXISTS ${LIBDIR})
|
||||
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
|
||||
|
||||
@@ -100,7 +103,22 @@ find_package_wrapper(JPEG REQUIRED)
|
||||
find_package_wrapper(PNG REQUIRED)
|
||||
find_package_wrapper(ZLIB REQUIRED)
|
||||
find_package_wrapper(Zstd REQUIRED)
|
||||
find_package_wrapper(Freetype REQUIRED)
|
||||
|
||||
if(NOT WITH_SYSTEM_FREETYPE)
|
||||
# FreeType compiled with Brotli compression for woff2.
|
||||
find_package_wrapper(Freetype REQUIRED)
|
||||
if(EXISTS ${LIBDIR})
|
||||
find_package_wrapper(Brotli REQUIRED)
|
||||
|
||||
# NOTE: This is done on WIN32 & APPLE but fails on some Linux systems.
|
||||
# See: https://devtalk.blender.org/t/22536
|
||||
# So `BROTLI_LIBRARIES` need to be added `FREETYPE_LIBRARIES`.
|
||||
#
|
||||
# list(APPEND FREETYPE_LIBRARIES
|
||||
# ${BROTLI_LIBRARIES}
|
||||
# )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_PYTHON)
|
||||
# No way to set py35, remove for now.
|
||||
@@ -536,6 +554,21 @@ add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
|
||||
#
|
||||
# Keep last, so indirectly linked libraries don't override our own pre-compiled libs.
|
||||
|
||||
if(EXISTS ${LIBDIR})
|
||||
# Clear the prefix path as it causes the `LIBDIR` to override system locations.
|
||||
unset(CMAKE_PREFIX_PATH)
|
||||
|
||||
# Since the pre-compiled `LIBDIR` directories have been handled, don't prefer static libraries.
|
||||
set(WITH_STATIC_LIBS ${WITH_STATIC_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
if(WITH_SYSTEM_FREETYPE)
|
||||
find_package_wrapper(Freetype)
|
||||
if(NOT FREETYPE_FOUND)
|
||||
message(FATAL_ERROR "Failed finding system FreeType version!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_LZO AND WITH_SYSTEM_LZO)
|
||||
find_package_wrapper(LZO)
|
||||
if(NOT LZO_FOUND)
|
||||
|
@@ -347,7 +347,11 @@ set(FREETYPE_INCLUDE_DIRS
|
||||
${LIBDIR}/freetype/include
|
||||
${LIBDIR}/freetype/include/freetype2
|
||||
)
|
||||
set(FREETYPE_LIBRARY ${LIBDIR}/freetype/lib/freetype2ST.lib)
|
||||
set(FREETYPE_LIBRARIES
|
||||
${LIBDIR}/freetype/lib/freetype2ST.lib
|
||||
${LIBDIR}/brotli/lib/brotlidec-static.lib
|
||||
${LIBDIR}/brotli/lib/brotlicommon-static.lib
|
||||
)
|
||||
windows_find_package(freetype REQUIRED)
|
||||
|
||||
if(WITH_FFTW3)
|
||||
|
@@ -3,7 +3,32 @@ for %%X in (svn.exe) do (set SVN=%%~$PATH:X)
|
||||
for %%X in (cmake.exe) do (set CMAKE=%%~$PATH:X)
|
||||
for %%X in (ctest.exe) do (set CTEST=%%~$PATH:X)
|
||||
for %%X in (git.exe) do (set GIT=%%~$PATH:X)
|
||||
REM For python, default on 39 but if that does not exist also check
|
||||
REM the 310,311 and 312 folders to see if those are there, it checks
|
||||
REM this far ahead to ensure good lib folder compatiblity in the future.
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\39\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\310\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\311\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\312\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
if NOT EXIST %PYTHON% (
|
||||
echo Warning: Python not found, there is likely an issue with the library folder
|
||||
set PYTHON=""
|
||||
)
|
||||
|
||||
:detect_python_done
|
||||
if NOT "%verbose%" == "" (
|
||||
echo svn : "%SVN%"
|
||||
echo cmake : "%CMAKE%"
|
||||
@@ -11,7 +36,3 @@ if NOT "%verbose%" == "" (
|
||||
echo git : "%GIT%"
|
||||
echo python : "%PYTHON%"
|
||||
)
|
||||
if "%CMAKE%" == "" (
|
||||
echo Cmake not found in path, required for building, exiting...
|
||||
exit /b 1
|
||||
)
|
||||
|
@@ -9,17 +9,11 @@ exit /b 1
|
||||
:detect_done
|
||||
echo found clang-format in %CF_PATH%
|
||||
|
||||
if EXIST %PYTHON% (
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\39\bin\python.exe
|
||||
goto detect_python_done
|
||||
if NOT EXIST %PYTHON% (
|
||||
echo python not found, required for this operation
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo python not found in lib folder
|
||||
exit /b 1
|
||||
|
||||
:detect_python_done
|
||||
echo found python (%PYTHON%)
|
||||
|
||||
set FORMAT_PATHS=%BLENDER_DIR%\source\tools\utils_maintenance\clang_format_paths.py
|
||||
|
||||
REM The formatting script expects clang-format to be in the current PATH.
|
||||
|
@@ -1,18 +1,8 @@
|
||||
if EXIST "%PYTHON%" (
|
||||
goto detect_python_done
|
||||
if NOT EXIST %PYTHON% (
|
||||
echo python not found, required for this operation
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\39\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
echo python not found at %PYTHON%
|
||||
exit /b 1
|
||||
|
||||
:detect_python_done
|
||||
echo found python (%PYTHON%)
|
||||
|
||||
call "%~dp0\find_inkscape.cmd"
|
||||
|
||||
if EXIST "%INKSCAPE_BIN%" (
|
||||
|
@@ -1,18 +1,8 @@
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
if NOT EXIST %PYTHON% (
|
||||
echo python not found, required for this operation
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\39\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
echo python not found at %PYTHON%
|
||||
exit /b 1
|
||||
|
||||
:detect_python_done
|
||||
echo found python (%PYTHON%)
|
||||
|
||||
call "%~dp0\find_blender.cmd"
|
||||
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
|
@@ -1,10 +1,7 @@
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
if NOT EXIST %PYTHON% (
|
||||
echo python not found, required for this operation
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo python not found in lib folder
|
||||
exit /b 1
|
||||
|
||||
:detect_python_done
|
||||
|
||||
REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
|
||||
|
@@ -743,7 +743,7 @@ will re-allocate objects data,
|
||||
any references to a meshes vertices/polygons/UVs, armatures bones,
|
||||
curves points, etc. cannot be accessed after switching mode.
|
||||
|
||||
Only the reference to the data its self can be re-accessed, the following example will crash.
|
||||
Only the reference to the data itself can be re-accessed, the following example will crash.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@@ -667,6 +667,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
description="Use special type BVH optimized for hair (uses more ram but renders faster)",
|
||||
default=True,
|
||||
)
|
||||
debug_use_compact_bvh: BoolProperty(
|
||||
name="Use Compact BVH",
|
||||
description="Use compact BVH structure (uses less ram but renders slower)",
|
||||
default=True,
|
||||
)
|
||||
debug_bvh_time_steps: IntProperty(
|
||||
name="BVH Time Steps",
|
||||
description="Split BVH primitives by this number of time steps to speed up render time in cost of memory",
|
||||
@@ -1447,6 +1452,19 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
||||
num += 1
|
||||
return num
|
||||
|
||||
def has_multi_device(self):
|
||||
import _cycles
|
||||
compute_device_type = self.get_compute_device_type()
|
||||
device_list = _cycles.available_devices(compute_device_type)
|
||||
for device in device_list:
|
||||
if device[1] == compute_device_type:
|
||||
continue
|
||||
for dev in self.devices:
|
||||
if dev.use and dev.id == device[2]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def has_active_device(self):
|
||||
return self.get_num_gpu_devices() > 0
|
||||
|
||||
|
@@ -118,6 +118,12 @@ def use_optix(context):
|
||||
|
||||
return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
|
||||
|
||||
def use_multi_device(context):
|
||||
cscene = context.scene.cycles
|
||||
if cscene.device != 'GPU':
|
||||
return False
|
||||
return context.preferences.addons[__package__].preferences.has_multi_device()
|
||||
|
||||
|
||||
def show_device_active(context):
|
||||
cscene = context.scene.cycles
|
||||
@@ -661,6 +667,10 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa
|
||||
bl_label = "Acceleration Structure"
|
||||
bl_parent_id = "CYCLES_RENDER_PT_performance"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not use_optix(context) or has_multi_device(context)
|
||||
|
||||
def draw(self, context):
|
||||
import _cycles
|
||||
|
||||
@@ -673,21 +683,33 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa
|
||||
|
||||
col = layout.column()
|
||||
|
||||
use_embree = False
|
||||
use_embree = _cycles.with_embree
|
||||
|
||||
if use_cpu(context):
|
||||
use_embree = _cycles.with_embree
|
||||
if not use_embree:
|
||||
col.prop(cscene, "debug_use_spatial_splits")
|
||||
if use_embree:
|
||||
col.prop(cscene, "debug_use_compact_bvh")
|
||||
else:
|
||||
sub = col.column()
|
||||
sub.active = not cscene.debug_use_spatial_splits
|
||||
sub.prop(cscene, "debug_bvh_time_steps")
|
||||
|
||||
col.prop(cscene, "debug_use_hair_bvh")
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.label(text="Cycles built without Embree support")
|
||||
sub.label(text="CPU raytracing performance will be poor")
|
||||
else:
|
||||
col.prop(cscene, "debug_use_spatial_splits")
|
||||
sub = col.column()
|
||||
sub.active = not cscene.debug_use_spatial_splits
|
||||
sub.prop(cscene, "debug_bvh_time_steps")
|
||||
|
||||
col.prop(cscene, "debug_use_spatial_splits")
|
||||
sub = col.column()
|
||||
sub.active = not use_embree
|
||||
sub.prop(cscene, "debug_use_hair_bvh")
|
||||
sub = col.column()
|
||||
sub.active = not cscene.debug_use_spatial_splits and not use_embree
|
||||
sub.prop(cscene, "debug_bvh_time_steps")
|
||||
col.prop(cscene, "debug_use_hair_bvh")
|
||||
|
||||
# CPU is used in addition to a GPU
|
||||
if use_multi_device(context) and use_embree:
|
||||
col.prop(cscene, "debug_use_compact_bvh")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel):
|
||||
|
@@ -51,8 +51,6 @@ bool BlenderOutputDriver::read_render_tile(const Tile &tile)
|
||||
|
||||
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||
|
||||
vector<float> pixels(static_cast<size_t>(tile.size.x) * tile.size.y * 4);
|
||||
|
||||
/* Copy each pass.
|
||||
* TODO:copy only the required ones for better performance? */
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
|
@@ -689,6 +689,9 @@ static ShaderNode *add_node(Scene *scene,
|
||||
else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
|
||||
node = graph->create_node<HairInfoNode>();
|
||||
}
|
||||
else if (b_node.is_a(&RNA_ShaderNodePointInfo)) {
|
||||
node = graph->create_node<PointInfoNode>();
|
||||
}
|
||||
else if (b_node.is_a(&RNA_ShaderNodeVolumeInfo)) {
|
||||
node = graph->create_node<VolumeInfoNode>();
|
||||
}
|
||||
|
@@ -787,6 +787,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
|
||||
params.bvh_type = BVH_TYPE_DYNAMIC;
|
||||
|
||||
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
|
||||
params.use_bvh_compact_structure = RNA_boolean_get(&cscene, "debug_use_compact_bvh");
|
||||
params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
|
||||
params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps");
|
||||
|
||||
|
@@ -355,10 +355,12 @@ void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
|
||||
}
|
||||
|
||||
const bool dynamic = params.bvh_type == BVH_TYPE_DYNAMIC;
|
||||
const bool compact = params.use_compact_structure;
|
||||
|
||||
scene = rtcNewScene(rtc_device);
|
||||
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
|
||||
RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
|
||||
(compact ? RTC_SCENE_FLAG_COMPACT : RTC_SCENE_FLAG_NONE) |
|
||||
RTC_SCENE_FLAG_ROBUST;
|
||||
rtcSetSceneFlags(scene, scene_flags);
|
||||
build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
|
||||
(params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
|
||||
|
@@ -97,6 +97,9 @@ class BVHParams {
|
||||
*/
|
||||
bool use_unaligned_nodes;
|
||||
|
||||
/* Use compact acceleration structure (Embree)*/
|
||||
bool use_compact_structure;
|
||||
|
||||
/* Split time range to this number of steps and create leaf node for each
|
||||
* of this time steps.
|
||||
*
|
||||
|
@@ -58,6 +58,11 @@ class BVHMetal : public BVH {
|
||||
id<MTLCommandQueue> queue,
|
||||
Geometry *const geom,
|
||||
bool refit);
|
||||
bool build_BLAS_pointcloud(Progress &progress,
|
||||
id<MTLDevice> device,
|
||||
id<MTLCommandQueue> queue,
|
||||
Geometry *const geom,
|
||||
bool refit);
|
||||
bool build_TLAS(Progress &progress, id<MTLDevice> device, id<MTLCommandQueue> queue, bool refit);
|
||||
};
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
# include "scene/hair.h"
|
||||
# include "scene/mesh.h"
|
||||
# include "scene/object.h"
|
||||
# include "scene/pointcloud.h"
|
||||
|
||||
# include "util/progress.h"
|
||||
|
||||
@@ -475,6 +476,220 @@ bool BVHMetal::build_BLAS_hair(Progress &progress,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BVHMetal::build_BLAS_pointcloud(Progress &progress,
|
||||
id<MTLDevice> device,
|
||||
id<MTLCommandQueue> queue,
|
||||
Geometry *const geom,
|
||||
bool refit)
|
||||
{
|
||||
if (@available(macos 12.0, *)) {
|
||||
/* Build BLAS for point cloud */
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
if (pointcloud->num_points() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*------------------------------------------------*/
|
||||
BVH_status("Building pointcloud BLAS | %7d points | %s",
|
||||
(int)pointcloud->num_points(),
|
||||
geom->name.c_str());
|
||||
/*------------------------------------------------*/
|
||||
|
||||
const size_t num_points = pointcloud->get_points().size();
|
||||
const float3 *points = pointcloud->get_points().data();
|
||||
const float *radius = pointcloud->get_radius().data();
|
||||
|
||||
const bool use_fast_trace_bvh = (params.bvh_type == BVH_TYPE_STATIC);
|
||||
|
||||
size_t num_motion_steps = 1;
|
||||
Attribute *motion_keys = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
if (motion_blur && pointcloud->get_use_motion_blur() && motion_keys) {
|
||||
num_motion_steps = pointcloud->get_motion_steps();
|
||||
}
|
||||
|
||||
const size_t num_aabbs = num_motion_steps;
|
||||
|
||||
MTLResourceOptions storage_mode;
|
||||
if (device.hasUnifiedMemory) {
|
||||
storage_mode = MTLResourceStorageModeShared;
|
||||
}
|
||||
else {
|
||||
storage_mode = MTLResourceStorageModeManaged;
|
||||
}
|
||||
|
||||
/* Allocate a GPU buffer for the AABB data and populate it */
|
||||
id<MTLBuffer> aabbBuf = [device
|
||||
newBufferWithLength:num_aabbs * sizeof(MTLAxisAlignedBoundingBox)
|
||||
options:storage_mode];
|
||||
MTLAxisAlignedBoundingBox *aabb_data = (MTLAxisAlignedBoundingBox *)[aabbBuf contents];
|
||||
|
||||
/* Get AABBs for each motion step */
|
||||
size_t center_step = (num_motion_steps - 1) / 2;
|
||||
for (size_t step = 0; step < num_motion_steps; ++step) {
|
||||
/* The center step for motion vertices is not stored in the attribute */
|
||||
if (step != center_step) {
|
||||
size_t attr_offset = (step > center_step) ? step - 1 : step;
|
||||
points = motion_keys->data_float3() + attr_offset * num_points;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < num_points; ++j) {
|
||||
const PointCloud::Point point = pointcloud->get_point(j);
|
||||
BoundBox bounds = BoundBox::empty;
|
||||
point.bounds_grow(points, radius, bounds);
|
||||
|
||||
const size_t index = step * num_points + j;
|
||||
aabb_data[index].min = (MTLPackedFloat3 &)bounds.min;
|
||||
aabb_data[index].max = (MTLPackedFloat3 &)bounds.max;
|
||||
}
|
||||
}
|
||||
|
||||
if (storage_mode == MTLResourceStorageModeManaged) {
|
||||
[aabbBuf didModifyRange:NSMakeRange(0, aabbBuf.length)];
|
||||
}
|
||||
|
||||
# if 0
|
||||
for (size_t i=0; i<num_aabbs && i < 400; i++) {
|
||||
MTLAxisAlignedBoundingBox& bb = aabb_data[i];
|
||||
printf(" %d: %.1f,%.1f,%.1f -- %.1f,%.1f,%.1f\n", int(i), bb.min.x, bb.min.y, bb.min.z, bb.max.x, bb.max.y, bb.max.z);
|
||||
}
|
||||
# endif
|
||||
|
||||
MTLAccelerationStructureGeometryDescriptor *geomDesc;
|
||||
if (motion_blur) {
|
||||
std::vector<MTLMotionKeyframeData *> aabb_ptrs;
|
||||
aabb_ptrs.reserve(num_motion_steps);
|
||||
for (size_t step = 0; step < num_motion_steps; ++step) {
|
||||
MTLMotionKeyframeData *k = [MTLMotionKeyframeData data];
|
||||
k.buffer = aabbBuf;
|
||||
k.offset = step * num_points * sizeof(MTLAxisAlignedBoundingBox);
|
||||
aabb_ptrs.push_back(k);
|
||||
}
|
||||
|
||||
MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor *geomDescMotion =
|
||||
[MTLAccelerationStructureMotionBoundingBoxGeometryDescriptor descriptor];
|
||||
geomDescMotion.boundingBoxBuffers = [NSArray arrayWithObjects:aabb_ptrs.data()
|
||||
count:aabb_ptrs.size()];
|
||||
geomDescMotion.boundingBoxCount = num_points;
|
||||
geomDescMotion.boundingBoxStride = sizeof(aabb_data[0]);
|
||||
geomDescMotion.intersectionFunctionTableOffset = 2;
|
||||
|
||||
/* Force a single any-hit call, so shadow record-all behavior works correctly */
|
||||
/* (Match optix behavior: unsigned int build_flags =
|
||||
* OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
|
||||
geomDescMotion.allowDuplicateIntersectionFunctionInvocation = false;
|
||||
geomDescMotion.opaque = true;
|
||||
geomDesc = geomDescMotion;
|
||||
}
|
||||
else {
|
||||
MTLAccelerationStructureBoundingBoxGeometryDescriptor *geomDescNoMotion =
|
||||
[MTLAccelerationStructureBoundingBoxGeometryDescriptor descriptor];
|
||||
geomDescNoMotion.boundingBoxBuffer = aabbBuf;
|
||||
geomDescNoMotion.boundingBoxBufferOffset = 0;
|
||||
geomDescNoMotion.boundingBoxCount = int(num_aabbs);
|
||||
geomDescNoMotion.boundingBoxStride = sizeof(aabb_data[0]);
|
||||
geomDescNoMotion.intersectionFunctionTableOffset = 2;
|
||||
|
||||
/* Force a single any-hit call, so shadow record-all behavior works correctly */
|
||||
/* (Match optix behavior: unsigned int build_flags =
|
||||
* OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL;) */
|
||||
geomDescNoMotion.allowDuplicateIntersectionFunctionInvocation = false;
|
||||
geomDescNoMotion.opaque = true;
|
||||
geomDesc = geomDescNoMotion;
|
||||
}
|
||||
|
||||
MTLPrimitiveAccelerationStructureDescriptor *accelDesc =
|
||||
[MTLPrimitiveAccelerationStructureDescriptor descriptor];
|
||||
accelDesc.geometryDescriptors = @[ geomDesc ];
|
||||
|
||||
if (motion_blur) {
|
||||
accelDesc.motionStartTime = 0.0f;
|
||||
accelDesc.motionEndTime = 1.0f;
|
||||
accelDesc.motionStartBorderMode = MTLMotionBorderModeVanish;
|
||||
accelDesc.motionEndBorderMode = MTLMotionBorderModeVanish;
|
||||
accelDesc.motionKeyframeCount = num_motion_steps;
|
||||
}
|
||||
|
||||
if (!use_fast_trace_bvh) {
|
||||
accelDesc.usage |= (MTLAccelerationStructureUsageRefit |
|
||||
MTLAccelerationStructureUsagePreferFastBuild);
|
||||
}
|
||||
|
||||
MTLAccelerationStructureSizes accelSizes = [device
|
||||
accelerationStructureSizesWithDescriptor:accelDesc];
|
||||
id<MTLAccelerationStructure> accel_uncompressed = [device
|
||||
newAccelerationStructureWithSize:accelSizes.accelerationStructureSize];
|
||||
id<MTLBuffer> scratchBuf = [device newBufferWithLength:accelSizes.buildScratchBufferSize
|
||||
options:MTLResourceStorageModePrivate];
|
||||
id<MTLBuffer> sizeBuf = [device newBufferWithLength:8 options:MTLResourceStorageModeShared];
|
||||
id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
|
||||
id<MTLAccelerationStructureCommandEncoder> accelEnc =
|
||||
[accelCommands accelerationStructureCommandEncoder];
|
||||
if (refit) {
|
||||
[accelEnc refitAccelerationStructure:accel_struct
|
||||
descriptor:accelDesc
|
||||
destination:accel_uncompressed
|
||||
scratchBuffer:scratchBuf
|
||||
scratchBufferOffset:0];
|
||||
}
|
||||
else {
|
||||
[accelEnc buildAccelerationStructure:accel_uncompressed
|
||||
descriptor:accelDesc
|
||||
scratchBuffer:scratchBuf
|
||||
scratchBufferOffset:0];
|
||||
}
|
||||
if (use_fast_trace_bvh) {
|
||||
[accelEnc writeCompactedAccelerationStructureSize:accel_uncompressed
|
||||
toBuffer:sizeBuf
|
||||
offset:0
|
||||
sizeDataType:MTLDataTypeULong];
|
||||
}
|
||||
[accelEnc endEncoding];
|
||||
[accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
|
||||
/* free temp resources */
|
||||
[scratchBuf release];
|
||||
[aabbBuf release];
|
||||
|
||||
if (use_fast_trace_bvh) {
|
||||
/* Compact the accel structure */
|
||||
uint64_t compressed_size = *(uint64_t *)sizeBuf.contents;
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
id<MTLCommandBuffer> accelCommands = [queue commandBuffer];
|
||||
id<MTLAccelerationStructureCommandEncoder> accelEnc =
|
||||
[accelCommands accelerationStructureCommandEncoder];
|
||||
id<MTLAccelerationStructure> accel = [device
|
||||
newAccelerationStructureWithSize:compressed_size];
|
||||
[accelEnc copyAndCompactAccelerationStructure:accel_uncompressed
|
||||
toAccelerationStructure:accel];
|
||||
[accelEnc endEncoding];
|
||||
[accelCommands addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
|
||||
uint64_t allocated_size = [accel allocatedSize];
|
||||
stats.mem_alloc(allocated_size);
|
||||
accel_struct = accel;
|
||||
[accel_uncompressed release];
|
||||
accel_struct_building = false;
|
||||
}];
|
||||
[accelCommands commit];
|
||||
});
|
||||
}
|
||||
else {
|
||||
/* set our acceleration structure to the uncompressed structure */
|
||||
accel_struct = accel_uncompressed;
|
||||
|
||||
uint64_t allocated_size = [accel_struct allocatedSize];
|
||||
stats.mem_alloc(allocated_size);
|
||||
accel_struct_building = false;
|
||||
}
|
||||
[sizeBuf release];
|
||||
}];
|
||||
|
||||
accel_struct_building = true;
|
||||
[accelCommands commit];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BVHMetal::build_BLAS(Progress &progress,
|
||||
id<MTLDevice> device,
|
||||
id<MTLCommandQueue> queue,
|
||||
@@ -491,6 +706,8 @@ bool BVHMetal::build_BLAS(Progress &progress,
|
||||
return build_BLAS_mesh(progress, device, queue, geom, refit);
|
||||
case Geometry::HAIR:
|
||||
return build_BLAS_hair(progress, device, queue, geom, refit);
|
||||
case Geometry::POINTCLOUD:
|
||||
return build_BLAS_pointcloud(progress, device, queue, geom, refit);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@@ -36,6 +36,8 @@ enum {
|
||||
METALRT_FUNC_CURVE_RIBBON_SHADOW,
|
||||
METALRT_FUNC_CURVE_ALL,
|
||||
METALRT_FUNC_CURVE_ALL_SHADOW,
|
||||
METALRT_FUNC_POINT,
|
||||
METALRT_FUNC_POINT_SHADOW,
|
||||
METALRT_FUNC_NUM
|
||||
};
|
||||
|
||||
|
@@ -358,6 +358,8 @@ bool MetalDeviceKernels::load(MetalDevice *device, int kernel_type)
|
||||
"__intersection__curve_ribbon_shadow",
|
||||
"__intersection__curve_all",
|
||||
"__intersection__curve_all_shadow",
|
||||
"__intersection__point",
|
||||
"__intersection__point_shadow",
|
||||
};
|
||||
assert(sizeof(function_names) / sizeof(function_names[0]) == METALRT_FUNC_NUM);
|
||||
|
||||
@@ -400,36 +402,50 @@ bool MetalDeviceKernels::load(MetalDevice *device, int kernel_type)
|
||||
NSArray *function_list = nil;
|
||||
|
||||
if (device->use_metalrt) {
|
||||
id<MTLFunction> box_intersect_default = nil;
|
||||
id<MTLFunction> box_intersect_shadow = nil;
|
||||
id<MTLFunction> curve_intersect_default = nil;
|
||||
id<MTLFunction> curve_intersect_shadow = nil;
|
||||
id<MTLFunction> point_intersect_default = nil;
|
||||
id<MTLFunction> point_intersect_shadow = nil;
|
||||
if (device->kernel_features & KERNEL_FEATURE_HAIR) {
|
||||
/* Add curve intersection programs. */
|
||||
if (device->kernel_features & KERNEL_FEATURE_HAIR_THICK) {
|
||||
/* Slower programs for thick hair since that also slows down ribbons.
|
||||
* Ideally this should not be needed. */
|
||||
box_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL];
|
||||
box_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL_SHADOW];
|
||||
curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL];
|
||||
curve_intersect_shadow =
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL_SHADOW];
|
||||
}
|
||||
else {
|
||||
box_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON];
|
||||
box_intersect_shadow =
|
||||
curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON];
|
||||
curve_intersect_shadow =
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON_SHADOW];
|
||||
}
|
||||
}
|
||||
if (device->kernel_features & KERNEL_FEATURE_POINTCLOUD) {
|
||||
point_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT];
|
||||
point_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT_SHADOW];
|
||||
}
|
||||
table_functions[METALRT_TABLE_DEFAULT] = [NSArray
|
||||
arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_TRI],
|
||||
box_intersect_default ?
|
||||
box_intersect_default :
|
||||
curve_intersect_default ?
|
||||
curve_intersect_default :
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX],
|
||||
point_intersect_default ?
|
||||
point_intersect_default :
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX],
|
||||
nil];
|
||||
table_functions[METALRT_TABLE_SHADOW] = [NSArray
|
||||
arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_TRI],
|
||||
box_intersect_shadow ?
|
||||
box_intersect_shadow :
|
||||
curve_intersect_shadow ?
|
||||
curve_intersect_shadow :
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX],
|
||||
point_intersect_shadow ?
|
||||
point_intersect_shadow :
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX],
|
||||
nil];
|
||||
table_functions[METALRT_TABLE_LOCAL] = [NSArray
|
||||
arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_TRI],
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX],
|
||||
rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX],
|
||||
nil];
|
||||
|
||||
|
@@ -820,8 +820,15 @@ void PathTrace::tile_buffer_read()
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read buffers back from device. */
|
||||
tbb::parallel_for_each(path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
|
||||
path_trace_work->copy_render_buffers_from_device();
|
||||
});
|
||||
|
||||
/* Read (subset of) passes from output driver. */
|
||||
PathTraceTile tile(*this);
|
||||
if (output_driver_->read_render_tile(tile)) {
|
||||
/* Copy buffers to device again. */
|
||||
tbb::parallel_for_each(path_trace_works_, [](unique_ptr<PathTraceWork> &path_trace_work) {
|
||||
path_trace_work->copy_render_buffers_to_device();
|
||||
});
|
||||
|
@@ -576,6 +576,150 @@ __intersection__curve_all_shadow(constant KernelParamsMetal &launch_params_metal
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* __HAIR__ */
|
||||
|
||||
#ifdef __POINTCLOUD__
|
||||
ccl_device_inline
|
||||
void metalrt_intersection_point(constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload,
|
||||
const uint object,
|
||||
const uint prim,
|
||||
const uint type,
|
||||
const float3 ray_origin,
|
||||
const float3 ray_direction,
|
||||
float time,
|
||||
const float ray_tmax,
|
||||
thread BoundingBoxIntersectionResult &result)
|
||||
{
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
const uint visibility = payload.visibility;
|
||||
if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
float3 P = ray_origin;
|
||||
float3 dir = ray_direction;
|
||||
|
||||
/* The direction is not normalized by default, but the point intersection routine expects that */
|
||||
float len;
|
||||
dir = normalize_len(dir, &len);
|
||||
|
||||
Intersection isect;
|
||||
isect.t = ray_tmax;
|
||||
/* Transform maximum distance into object space. */
|
||||
if (isect.t != FLT_MAX)
|
||||
isect.t *= len;
|
||||
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
|
||||
result = metalrt_visibility_test<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
|
||||
launch_params_metal, payload, object, prim, isect.u);
|
||||
if (result.accept) {
|
||||
result.distance = isect.t / len;
|
||||
payload.u = isect.u;
|
||||
payload.v = isect.v;
|
||||
payload.prim = prim;
|
||||
payload.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline
|
||||
void metalrt_intersection_point_shadow(constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload,
|
||||
const uint object,
|
||||
const uint prim,
|
||||
const uint type,
|
||||
const float3 ray_origin,
|
||||
const float3 ray_direction,
|
||||
float time,
|
||||
const float ray_tmax,
|
||||
thread BoundingBoxIntersectionResult &result)
|
||||
{
|
||||
const uint visibility = payload.visibility;
|
||||
|
||||
float3 P = ray_origin;
|
||||
float3 dir = ray_direction;
|
||||
|
||||
/* The direction is not normalized by default, but the point intersection routine expects that */
|
||||
float len;
|
||||
dir = normalize_len(dir, &len);
|
||||
|
||||
Intersection isect;
|
||||
isect.t = ray_tmax;
|
||||
/* Transform maximum distance into object space */
|
||||
if (isect.t != FLT_MAX)
|
||||
isect.t *= len;
|
||||
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
|
||||
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_BOUNDING_BOX>(
|
||||
launch_params_metal, payload, object, prim, float2(isect.u, isect.v), ray_tmax);
|
||||
result.accept = !result.continue_search;
|
||||
|
||||
if (result.accept) {
|
||||
result.distance = isect.t / len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
|
||||
BoundingBoxIntersectionResult
|
||||
__intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
|
||||
const uint object [[user_instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const float3 ray_origin [[origin]],
|
||||
const float3 ray_direction [[direction]],
|
||||
const float ray_tmax [[max_distance]])
|
||||
{
|
||||
const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
|
||||
const int type = kernel_tex_fetch(__objects, object).primitive_type;
|
||||
|
||||
BoundingBoxIntersectionResult result;
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
result.distance = ray_tmax;
|
||||
|
||||
metalrt_intersection_point(launch_params_metal, payload, object, prim, type, ray_origin, ray_direction,
|
||||
# if defined(__METALRT_MOTION__)
|
||||
payload.time,
|
||||
# else
|
||||
0.0f,
|
||||
# endif
|
||||
ray_tmax, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(bounding_box, triangle_data, METALRT_TAGS)]]
|
||||
BoundingBoxIntersectionResult
|
||||
__intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
|
||||
const uint object [[user_instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const float3 ray_origin [[origin]],
|
||||
const float3 ray_direction [[direction]],
|
||||
const float ray_tmax [[max_distance]])
|
||||
{
|
||||
const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
|
||||
const int type = kernel_tex_fetch(__objects, object).primitive_type;
|
||||
|
||||
BoundingBoxIntersectionResult result;
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
result.distance = ray_tmax;
|
||||
|
||||
metalrt_intersection_point_shadow(launch_params_metal, payload, object, prim, type, ray_origin, ray_direction,
|
||||
# if defined(__METALRT_MOTION__)
|
||||
payload.time,
|
||||
# else
|
||||
0.0f,
|
||||
# endif
|
||||
ray_tmax, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif /* __POINTCLOUD__ */
|
||||
#endif /* __METALRT__ */
|
||||
|
@@ -226,6 +226,18 @@ ccl_device float curve_thickness(KernelGlobals kg, ccl_private const ShaderData
|
||||
return r * 2.0f;
|
||||
}
|
||||
|
||||
/* Curve random */
|
||||
|
||||
ccl_device float curve_random(KernelGlobals kg, ccl_private const ShaderData *sd)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_CURVE) {
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_CURVE_RANDOM);
|
||||
return (desc.offset != ATTR_STD_NOT_FOUND) ? curve_attribute_float(kg, sd, desc, NULL, NULL) :
|
||||
0.0f;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* Curve location for motion pass, linear interpolation between keys and
|
||||
* ignoring radius because we do the same for the motion keys */
|
||||
|
||||
|
@@ -81,7 +81,7 @@ ccl_device float3 point_attribute_float3(KernelGlobals kg,
|
||||
# endif
|
||||
|
||||
if (desc.element == ATTR_ELEMENT_VERTEX) {
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float4, desc.offset + sd->prim));
|
||||
return kernel_tex_fetch(__attributes_float3, desc.offset + sd->prim);
|
||||
}
|
||||
else {
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
@@ -109,17 +109,59 @@ ccl_device float4 point_attribute_float4(KernelGlobals kg,
|
||||
}
|
||||
}
|
||||
|
||||
/* Point position */
|
||||
|
||||
ccl_device float3 point_position(KernelGlobals kg, ccl_private const ShaderData *sd)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_POINT) {
|
||||
/* World space center. */
|
||||
float3 P = (sd->type & PRIMITIVE_MOTION) ?
|
||||
float4_to_float3(motion_point(kg, sd->object, sd->prim, sd->time)) :
|
||||
float4_to_float3(kernel_tex_fetch(__points, sd->prim));
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_position_transform(kg, sd, &P);
|
||||
}
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
return zero_float3();
|
||||
}
|
||||
|
||||
/* Point radius */
|
||||
|
||||
ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_POINT) {
|
||||
return kernel_tex_fetch(__points, sd->prim).w;
|
||||
/* World space radius. */
|
||||
const float r = kernel_tex_fetch(__points, sd->prim).w;
|
||||
|
||||
if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
float3 dir = make_float3(r, r, r);
|
||||
object_dir_transform(kg, sd, &dir);
|
||||
return average(dir);
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* Point random */
|
||||
|
||||
ccl_device float point_random(KernelGlobals kg, ccl_private const ShaderData *sd)
|
||||
{
|
||||
if (sd->type & PRIMITIVE_POINT) {
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POINT_RANDOM);
|
||||
return (desc.offset != ATTR_STD_NOT_FOUND) ? point_attribute_float(kg, sd, desc, NULL, NULL) :
|
||||
0.0f;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* Point location for motion pass, linear interpolation between keys and
|
||||
* ignoring radius because we do the same for the motion keys */
|
||||
|
||||
|
@@ -116,6 +116,8 @@ ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
|
||||
ustring OSLRenderServices::u_curve_random("geom:curve_random");
|
||||
ustring OSLRenderServices::u_is_point("geom:is_point");
|
||||
ustring OSLRenderServices::u_point_radius("geom:point_radius");
|
||||
ustring OSLRenderServices::u_point_position("geom:point_position");
|
||||
ustring OSLRenderServices::u_point_random("geom:point_random");
|
||||
ustring OSLRenderServices::u_normal_map_normal("geom:normal_map_normal");
|
||||
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
|
||||
ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
|
||||
@@ -999,6 +1001,10 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
|
||||
float3 f = curve_tangent_normal(kg, sd);
|
||||
return set_attribute_float3(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_curve_random) {
|
||||
float f = curve_random(kg, sd);
|
||||
return set_attribute_float(f, type, derivatives, val);
|
||||
}
|
||||
/* point attributes */
|
||||
else if (name == u_is_point) {
|
||||
float f = (sd->type & PRIMITIVE_POINT) != 0;
|
||||
@@ -1008,6 +1014,14 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
|
||||
float f = point_radius(kg, sd);
|
||||
return set_attribute_float(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_point_position) {
|
||||
float3 f = point_position(kg, sd);
|
||||
return set_attribute_float3(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_point_random) {
|
||||
float f = point_random(kg, sd);
|
||||
return set_attribute_float(f, type, derivatives, val);
|
||||
}
|
||||
else if (name == u_normal_map_normal) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
|
@@ -298,7 +298,9 @@ class OSLRenderServices : public OSL::RendererServices {
|
||||
static ustring u_curve_tangent_normal;
|
||||
static ustring u_curve_random;
|
||||
static ustring u_is_point;
|
||||
static ustring u_point_position;
|
||||
static ustring u_point_radius;
|
||||
static ustring u_point_random;
|
||||
static ustring u_normal_map_normal;
|
||||
static ustring u_path_ray_length;
|
||||
static ustring u_path_ray_depth;
|
||||
|
@@ -49,6 +49,7 @@ set(SRC_OSL
|
||||
node_glossy_bsdf.osl
|
||||
node_gradient_texture.osl
|
||||
node_hair_info.osl
|
||||
node_point_info.osl
|
||||
node_scatter_volume.osl
|
||||
node_absorption_volume.osl
|
||||
node_principled_volume.osl
|
||||
|
26
intern/cycles/kernel/osl/shaders/node_point_info.osl
Normal file
26
intern/cycles/kernel/osl/shaders/node_point_info.osl
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2011-2022 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "stdcycles.h"
|
||||
|
||||
shader node_point_info(output point Position = point(0.0, 0.0, 0.0),
|
||||
output float Radius = 0.0,
|
||||
output float Random = 0.0)
|
||||
{
|
||||
getattribute("geom:point_position", Position);
|
||||
getattribute("geom:point_radius", Radius);
|
||||
getattribute("geom:point_random", Random);
|
||||
}
|
@@ -242,13 +242,6 @@ ccl_device_noinline void svm_node_hair_info(KernelGlobals kg,
|
||||
stack_store_float(stack, out_offset, data);
|
||||
break;
|
||||
}
|
||||
# if 0
|
||||
case NODE_INFO_CURVE_FADE: {
|
||||
data = sd->curve_transparency;
|
||||
stack_store_float(stack, out_offset, data);
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
case NODE_INFO_CURVE_TANGENT_NORMAL: {
|
||||
data3 = curve_tangent_normal(kg, sd);
|
||||
stack_store_float3(stack, out_offset, data3);
|
||||
@@ -258,4 +251,28 @@ ccl_device_noinline void svm_node_hair_info(KernelGlobals kg,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __POINTCLOUD__
|
||||
|
||||
/* Point Info */
|
||||
|
||||
ccl_device_noinline void svm_node_point_info(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
uint type,
|
||||
uint out_offset)
|
||||
{
|
||||
switch (type) {
|
||||
case NODE_INFO_POINT_POSITION:
|
||||
stack_store_float3(stack, out_offset, point_position(kg, sd));
|
||||
break;
|
||||
case NODE_INFO_POINT_RADIUS:
|
||||
stack_store_float(stack, out_offset, point_radius(kg, sd));
|
||||
break;
|
||||
case NODE_INFO_POINT_RANDOM:
|
||||
break; /* handled as attribute */
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -454,13 +454,14 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
|
||||
break;
|
||||
#if defined(__HAIR__)
|
||||
case NODE_HAIR_INFO:
|
||||
IF_KERNEL_NODES_FEATURE(HAIR)
|
||||
{
|
||||
svm_node_hair_info(kg, sd, stack, node.y, node.z);
|
||||
}
|
||||
svm_node_hair_info(kg, sd, stack, node.y, node.z);
|
||||
break;
|
||||
#endif
|
||||
#if defined(__POINTCLOUD__)
|
||||
case NODE_POINT_INFO:
|
||||
svm_node_point_info(kg, sd, stack, node.y, node.z);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case NODE_TEXTURE_MAPPING:
|
||||
offset = svm_node_texture_mapping(kg, sd, stack, node.y, node.z, offset);
|
||||
break;
|
||||
|
@@ -81,6 +81,7 @@ typedef enum ShaderNodeType {
|
||||
NODE_OBJECT_INFO,
|
||||
NODE_PARTICLE_INFO,
|
||||
NODE_HAIR_INFO,
|
||||
NODE_POINT_INFO,
|
||||
NODE_TEXTURE_MAPPING,
|
||||
NODE_MAPPING,
|
||||
NODE_MIN_MAX,
|
||||
@@ -176,12 +177,16 @@ typedef enum NodeHairInfo {
|
||||
NODE_INFO_CURVE_INTERCEPT,
|
||||
NODE_INFO_CURVE_LENGTH,
|
||||
NODE_INFO_CURVE_THICKNESS,
|
||||
/* Fade for minimum hair width transiency. */
|
||||
// NODE_INFO_CURVE_FADE,
|
||||
NODE_INFO_CURVE_TANGENT_NORMAL,
|
||||
NODE_INFO_CURVE_RANDOM,
|
||||
} NodeHairInfo;
|
||||
|
||||
typedef enum NodePointInfo {
|
||||
NODE_INFO_POINT_POSITION,
|
||||
NODE_INFO_POINT_RADIUS,
|
||||
NODE_INFO_POINT_RANDOM,
|
||||
} NodePointInfo;
|
||||
|
||||
typedef enum NodeLightPath {
|
||||
NODE_LP_camera = 0,
|
||||
NODE_LP_shadow,
|
||||
|
@@ -1565,21 +1565,21 @@ enum KernelFeatureFlag : uint32_t {
|
||||
KERNEL_FEATURE_NODE_BSDF = (1U << 0U),
|
||||
KERNEL_FEATURE_NODE_EMISSION = (1U << 1U),
|
||||
KERNEL_FEATURE_NODE_VOLUME = (1U << 2U),
|
||||
KERNEL_FEATURE_NODE_HAIR = (1U << 3U),
|
||||
KERNEL_FEATURE_NODE_BUMP = (1U << 4U),
|
||||
KERNEL_FEATURE_NODE_BUMP_STATE = (1U << 5U),
|
||||
KERNEL_FEATURE_NODE_VORONOI_EXTRA = (1U << 6U),
|
||||
KERNEL_FEATURE_NODE_RAYTRACE = (1U << 7U),
|
||||
KERNEL_FEATURE_NODE_AOV = (1U << 8U),
|
||||
KERNEL_FEATURE_NODE_LIGHT_PATH = (1U << 9U),
|
||||
KERNEL_FEATURE_NODE_BUMP = (1U << 3U),
|
||||
KERNEL_FEATURE_NODE_BUMP_STATE = (1U << 4U),
|
||||
KERNEL_FEATURE_NODE_VORONOI_EXTRA = (1U << 5U),
|
||||
KERNEL_FEATURE_NODE_RAYTRACE = (1U << 6U),
|
||||
KERNEL_FEATURE_NODE_AOV = (1U << 7U),
|
||||
KERNEL_FEATURE_NODE_LIGHT_PATH = (1U << 8U),
|
||||
|
||||
/* Use denoising kernels and output denoising passes. */
|
||||
KERNEL_FEATURE_DENOISING = (1U << 10U),
|
||||
KERNEL_FEATURE_DENOISING = (1U << 9U),
|
||||
|
||||
/* Use path tracing kernels. */
|
||||
KERNEL_FEATURE_PATH_TRACING = (1U << 11U),
|
||||
KERNEL_FEATURE_PATH_TRACING = (1U << 10U),
|
||||
|
||||
/* BVH/sampling kernel features. */
|
||||
KERNEL_FEATURE_POINTCLOUD = (1U << 11U),
|
||||
KERNEL_FEATURE_HAIR = (1U << 12U),
|
||||
KERNEL_FEATURE_HAIR_THICK = (1U << 13U),
|
||||
KERNEL_FEATURE_OBJECT_MOTION = (1U << 14U),
|
||||
@@ -1616,9 +1616,6 @@ enum KernelFeatureFlag : uint32_t {
|
||||
KERNEL_FEATURE_AO_PASS = (1U << 25U),
|
||||
KERNEL_FEATURE_AO_ADDITIVE = (1U << 26U),
|
||||
KERNEL_FEATURE_AO = (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE),
|
||||
|
||||
/* Point clouds. */
|
||||
KERNEL_FEATURE_POINTCLOUD = (1U << 27U),
|
||||
};
|
||||
|
||||
/* Shader node feature mask, to specialize shader evaluation for kernels. */
|
||||
@@ -1628,7 +1625,7 @@ enum KernelFeatureFlag : uint32_t {
|
||||
KERNEL_FEATURE_NODE_LIGHT_PATH)
|
||||
#define KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW \
|
||||
(KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | \
|
||||
KERNEL_FEATURE_NODE_HAIR | KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE | \
|
||||
KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE | \
|
||||
KERNEL_FEATURE_NODE_VORONOI_EXTRA | KERNEL_FEATURE_NODE_LIGHT_PATH)
|
||||
#define KERNEL_FEATURE_NODE_MASK_SURFACE \
|
||||
(KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW | KERNEL_FEATURE_NODE_RAYTRACE | \
|
||||
|
@@ -236,6 +236,7 @@ void Geometry::compute_bvh(
|
||||
|
||||
BVHParams bparams;
|
||||
bparams.use_spatial_split = params->use_bvh_spatial_split;
|
||||
bparams.use_compact_structure = params->use_bvh_compact_structure;
|
||||
bparams.bvh_layout = bvh_layout;
|
||||
bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
|
||||
params->use_bvh_unaligned_nodes;
|
||||
|
@@ -891,6 +891,10 @@ void ImageManager::device_free(Device *device)
|
||||
void ImageManager::collect_statistics(RenderStats *stats)
|
||||
{
|
||||
foreach (const Image *image, images) {
|
||||
if (!image) {
|
||||
/* Image may have been freed due to lack of users. */
|
||||
continue;
|
||||
}
|
||||
stats->image.textures.add_entry(
|
||||
NamedSizeEntry(image->loader->name(), image->mem->memory_size()));
|
||||
}
|
||||
|
@@ -570,7 +570,6 @@ static void log_kernel_features(const uint features)
|
||||
<< "\n";
|
||||
VLOG(2) << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION) << "\n";
|
||||
VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n";
|
||||
VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_NODE_HAIR) << "\n";
|
||||
VLOG(2) << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n";
|
||||
VLOG(2) << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA)
|
||||
<< "\n";
|
||||
|
@@ -160,6 +160,7 @@ class SceneParams {
|
||||
|
||||
BVHType bvh_type;
|
||||
bool use_bvh_spatial_split;
|
||||
bool use_bvh_compact_structure;
|
||||
bool use_bvh_unaligned_nodes;
|
||||
int num_bvh_time_steps;
|
||||
int hair_subdivisions;
|
||||
@@ -174,6 +175,7 @@ class SceneParams {
|
||||
bvh_layout = BVH_LAYOUT_BVH2;
|
||||
bvh_type = BVH_TYPE_DYNAMIC;
|
||||
use_bvh_spatial_split = false;
|
||||
use_bvh_compact_structure = true;
|
||||
use_bvh_unaligned_nodes = true;
|
||||
num_bvh_time_steps = 0;
|
||||
hair_subdivisions = 3;
|
||||
@@ -187,6 +189,7 @@ class SceneParams {
|
||||
return !(shadingsystem == params.shadingsystem && bvh_layout == params.bvh_layout &&
|
||||
bvh_type == params.bvh_type &&
|
||||
use_bvh_spatial_split == params.use_bvh_spatial_split &&
|
||||
use_bvh_compact_structure == params.use_bvh_compact_structure &&
|
||||
use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes &&
|
||||
num_bvh_time_steps == params.num_bvh_time_steps &&
|
||||
hair_subdivisions == params.hair_subdivisions && hair_shape == params.hair_shape &&
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "util/color.h"
|
||||
#include "util/foreach.h"
|
||||
#include "util/log.h"
|
||||
#include "util/string.h"
|
||||
#include "util/transform.h"
|
||||
|
||||
#include "kernel/tables.h"
|
||||
@@ -462,8 +463,12 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
|
||||
const ustring known_colorspace = metadata.colorspace;
|
||||
|
||||
if (handle.svm_slot() == -1) {
|
||||
/* OIIO currently does not support <UVTILE> substitutions natively. Replace with a format they
|
||||
* understand. */
|
||||
std::string osl_filename = filename.string();
|
||||
string_replace(osl_filename, "<UVTILE>", "<U>_<V>");
|
||||
compiler.parameter_texture(
|
||||
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
|
||||
"filename", ustring(osl_filename), compress_as_srgb ? u_colorspace_raw : known_colorspace);
|
||||
}
|
||||
else {
|
||||
compiler.parameter_texture("filename", handle.svm_slot());
|
||||
@@ -472,7 +477,8 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
|
||||
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
|
||||
alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
|
||||
alpha_type == IMAGE_ALPHA_IGNORE);
|
||||
const bool is_tiled = (filename.find("<UDIM>") != string::npos);
|
||||
const bool is_tiled = (filename.find("<UDIM>") != string::npos ||
|
||||
filename.find("<UVTILE>") != string::npos);
|
||||
|
||||
compiler.parameter(this, "projection");
|
||||
compiler.parameter(this, "projection_blend");
|
||||
@@ -4388,9 +4394,6 @@ NODE_DEFINE(HairInfoNode)
|
||||
SOCKET_OUT_FLOAT(size, "Length");
|
||||
SOCKET_OUT_FLOAT(thickness, "Thickness");
|
||||
SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal");
|
||||
#if 0 /* Output for minimum hair width transparency - deactivated. */
|
||||
SOCKET_OUT_FLOAT(fade, "Fade");
|
||||
#endif
|
||||
SOCKET_OUT_FLOAT(index, "Random");
|
||||
|
||||
return type;
|
||||
@@ -4448,12 +4451,7 @@ void HairInfoNode::compile(SVMCompiler &compiler)
|
||||
if (!out->links.empty()) {
|
||||
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out));
|
||||
}
|
||||
#if 0
|
||||
out = output("Fade");
|
||||
if(!out->links.empty()) {
|
||||
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out));
|
||||
}
|
||||
#endif
|
||||
|
||||
out = output("Random");
|
||||
if (!out->links.empty()) {
|
||||
int attr = compiler.attribute(ATTR_STD_CURVE_RANDOM);
|
||||
@@ -4466,6 +4464,59 @@ void HairInfoNode::compile(OSLCompiler &compiler)
|
||||
compiler.add(this, "node_hair_info");
|
||||
}
|
||||
|
||||
/* Point Info */
|
||||
|
||||
NODE_DEFINE(PointInfoNode)
|
||||
{
|
||||
NodeType *type = NodeType::add("point_info", create, NodeType::SHADER);
|
||||
|
||||
SOCKET_OUT_POINT(position, "Position");
|
||||
SOCKET_OUT_FLOAT(radius, "Radius");
|
||||
SOCKET_OUT_FLOAT(random, "Random");
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
PointInfoNode::PointInfoNode() : ShaderNode(get_node_type())
|
||||
{
|
||||
}
|
||||
|
||||
void PointInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface_link()) {
|
||||
if (!output("Random")->links.empty())
|
||||
attributes->add(ATTR_STD_POINT_RANDOM);
|
||||
}
|
||||
|
||||
ShaderNode::attributes(shader, attributes);
|
||||
}
|
||||
|
||||
void PointInfoNode::compile(SVMCompiler &compiler)
|
||||
{
|
||||
ShaderOutput *out;
|
||||
|
||||
out = output("Position");
|
||||
if (!out->links.empty()) {
|
||||
compiler.add_node(NODE_POINT_INFO, NODE_INFO_POINT_POSITION, compiler.stack_assign(out));
|
||||
}
|
||||
|
||||
out = output("Radius");
|
||||
if (!out->links.empty()) {
|
||||
compiler.add_node(NODE_POINT_INFO, NODE_INFO_POINT_RADIUS, compiler.stack_assign(out));
|
||||
}
|
||||
|
||||
out = output("Random");
|
||||
if (!out->links.empty()) {
|
||||
int attr = compiler.attribute(ATTR_STD_POINT_RANDOM);
|
||||
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
||||
}
|
||||
}
|
||||
|
||||
void PointInfoNode::compile(OSLCompiler &compiler)
|
||||
{
|
||||
compiler.add(this, "node_point_info");
|
||||
}
|
||||
|
||||
/* Volume Info */
|
||||
|
||||
NODE_DEFINE(VolumeInfoNode)
|
||||
|
@@ -1005,9 +1005,20 @@ class HairInfoNode : public ShaderNode {
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual int get_feature()
|
||||
};
|
||||
|
||||
class PointInfoNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(PointInfoNode)
|
||||
|
||||
void attributes(Shader *shader, AttributeRequestSet *attributes);
|
||||
bool has_attribute_dependency()
|
||||
{
|
||||
return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_HAIR;
|
||||
return true;
|
||||
}
|
||||
bool has_spatial_varying()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -401,7 +401,7 @@ ccl_device_inline float fractf(float x)
|
||||
return x - floorf(x);
|
||||
}
|
||||
|
||||
/* Adapted from godot-engine math_funcs.h. */
|
||||
/* Adapted from `godot-engine` math_funcs.h. */
|
||||
ccl_device_inline float wrapf(float value, float max, float min)
|
||||
{
|
||||
float range = max - min;
|
||||
|
@@ -292,7 +292,7 @@ target_link_libraries(multitest_c
|
||||
guardedalloc_lib
|
||||
wcwidth_lib
|
||||
${OPENGL_gl_LIBRARY}
|
||||
${FREETYPE_LIBRARY}
|
||||
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${CMAKE_DL_LIBS}
|
||||
${PLATFORM_LINKLIBS}
|
||||
|
11
make.bat
11
make.bat
@@ -13,6 +13,9 @@ if errorlevel 1 goto EOF
|
||||
call "%BLENDER_DIR%\build_files\windows\parse_arguments.cmd" %*
|
||||
if errorlevel 1 goto EOF
|
||||
|
||||
call "%BLENDER_DIR%\build_files\windows\find_dependencies.cmd"
|
||||
if errorlevel 1 goto EOF
|
||||
|
||||
REM if it is one of the convenience targets and BLENDER_BIN is set
|
||||
REM skip compiler detection
|
||||
if "%ICONS%%ICONS_GEOM%%DOC_PY%" == "1" (
|
||||
@@ -21,9 +24,6 @@ if "%ICONS%%ICONS_GEOM%%DOC_PY%" == "1" (
|
||||
)
|
||||
)
|
||||
|
||||
call "%BLENDER_DIR%\build_files\windows\find_dependencies.cmd"
|
||||
if errorlevel 1 goto EOF
|
||||
|
||||
if "%BUILD_SHOW_HASHES%" == "1" (
|
||||
call "%BLENDER_DIR%\build_files\windows\show_hashes.cmd"
|
||||
goto EOF
|
||||
@@ -88,6 +88,11 @@ if "%DOC_PY%" == "1" (
|
||||
goto EOF
|
||||
)
|
||||
|
||||
if "%CMAKE%" == "" (
|
||||
echo Cmake not found in path, required for building, exiting...
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Building blender with VS%BUILD_VS_YEAR% for %BUILD_ARCH% in %BUILD_DIR%
|
||||
|
||||
call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"
|
||||
|
Submodule release/scripts/addons updated: 6afec05c32...67f1fbca14
@@ -546,7 +546,7 @@ def unique_name(key, name, name_dict, name_max=-1, clean_func=None, sep="."):
|
||||
|
||||
:arg key: unique item this name belongs to, name_dict[key] will be reused
|
||||
when available.
|
||||
This can be the object, mesh, material, etc instance its self.
|
||||
This can be the object, mesh, material, etc instance itself.
|
||||
:type key: any hashable object associated with the *name*.
|
||||
:arg name: The name used to create a unique value in *name_dict*.
|
||||
:type name: string
|
||||
|
@@ -272,7 +272,7 @@ def autocomplete(context):
|
||||
sc.select_end += ofs
|
||||
except:
|
||||
# unlikely, but this can happen with unicode errors for example.
|
||||
# or if the api attribute access its self causes an error.
|
||||
# or if the api attribute access itself causes an error.
|
||||
import traceback
|
||||
scrollback_error = traceback.format_exc()
|
||||
|
||||
|
@@ -1860,6 +1860,7 @@ url_manual_mapping = (
|
||||
("bpy.types.shadernodeemission*", "render/shader_nodes/shader/emission.html#bpy-types-shadernodeemission"),
|
||||
("bpy.types.shadernodegeometry*", "render/shader_nodes/input/geometry.html#bpy-types-shadernodegeometry"),
|
||||
("bpy.types.shadernodehairinfo*", "render/shader_nodes/input/hair_info.html#bpy-types-shadernodehairinfo"),
|
||||
("bpy.types.shadernodepointinfo*", "render/shader_nodes/input/point_info.html#bpy-types-shadernodepointinfo"),
|
||||
("bpy.types.shadernodemaprange*", "render/shader_nodes/converter/map_range.html#bpy-types-shadernodemaprange"),
|
||||
("bpy.types.shadernodergbcurve*", "modeling/geometry_nodes/color/rgb_curves.html#bpy-types-shadernodergbcurve"),
|
||||
("bpy.types.shadernodeseparate*", "render/shader_nodes/converter/combine_separate.html#bpy-types-shadernodeseparate"),
|
||||
|
@@ -122,7 +122,7 @@ def rna2xml(
|
||||
if issubclass(value_type, skip_classes):
|
||||
return
|
||||
|
||||
# XXX, fixme, pointcache has eternal nested pointer to its self.
|
||||
# XXX, fixme, pointcache has eternal nested pointer to itself.
|
||||
if value == parent:
|
||||
return
|
||||
|
||||
|
@@ -581,7 +581,7 @@ class WM_OT_context_cycle_enum(Operator):
|
||||
|
||||
# Have the info we need, advance to the next item.
|
||||
#
|
||||
# When wrap's disabled we may set the value to its self,
|
||||
# When wrap's disabled we may set the value to itself,
|
||||
# this is done to ensure update callbacks run.
|
||||
if self.reverse:
|
||||
if orig_index == 0:
|
||||
|
@@ -82,6 +82,14 @@ class MESH_MT_shape_key_context_menu(Menu):
|
||||
layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP'
|
||||
layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'
|
||||
|
||||
class MESH_MT_attribute_context_menu(Menu):
|
||||
bl_label = "Attribute Specials"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("geometry.attribute_convert")
|
||||
|
||||
|
||||
class MESH_UL_vgroups(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data_, _active_propname, _index):
|
||||
@@ -615,6 +623,10 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
|
||||
col.operator("geometry.attribute_add", icon='ADD', text="")
|
||||
col.operator("geometry.attribute_remove", icon='REMOVE', text="")
|
||||
|
||||
col.separator()
|
||||
|
||||
col.menu("MESH_MT_attribute_context_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
self.draw_attribute_warnings(context, layout)
|
||||
|
||||
def draw_attribute_warnings(self, context, layout):
|
||||
@@ -652,6 +664,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
|
||||
classes = (
|
||||
MESH_MT_vertex_group_context_menu,
|
||||
MESH_MT_shape_key_context_menu,
|
||||
MESH_MT_attribute_context_menu,
|
||||
MESH_UL_vgroups,
|
||||
MESH_UL_fmaps,
|
||||
MESH_UL_shape_keys,
|
||||
|
@@ -184,24 +184,18 @@ class OBJECT_PT_collections(ObjectButtonsPanel, Panel):
|
||||
row.operator("object.collection_add", text="Add to Collection")
|
||||
row.operator("object.collection_add", text="", icon='ADD')
|
||||
|
||||
obj_name = obj.name
|
||||
for collection in bpy.data.collections:
|
||||
# XXX this is slow and stupid!, we need 2 checks, one that's fast
|
||||
# and another that we can be sure its not a name collision
|
||||
# from linked library data
|
||||
collection_objects = collection.objects
|
||||
if obj_name in collection.objects and obj in collection_objects[:]:
|
||||
col = layout.column(align=True)
|
||||
for collection in obj.users_collection:
|
||||
col = layout.column(align=True)
|
||||
|
||||
col.context_pointer_set("collection", collection)
|
||||
col.context_pointer_set("collection", collection)
|
||||
|
||||
row = col.box().row()
|
||||
row.prop(collection, "name", text="")
|
||||
row.operator("object.collection_remove", text="", icon='X', emboss=False)
|
||||
row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="")
|
||||
row = col.box().row()
|
||||
row.prop(collection, "name", text="")
|
||||
row.operator("object.collection_remove", text="", icon='X', emboss=False)
|
||||
row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
row = col.box().row()
|
||||
row.prop(collection, "instance_offset", text="")
|
||||
row = col.box().row()
|
||||
row.prop(collection, "instance_offset", text="")
|
||||
|
||||
|
||||
class OBJECT_PT_display(ObjectButtonsPanel, Panel):
|
||||
|
@@ -335,6 +335,7 @@ class GRAPH_MT_key_snap(Menu):
|
||||
layout.operator("graph.snap", text="Selection to Nearest Second").type = 'NEAREST_SECOND'
|
||||
layout.operator("graph.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER'
|
||||
layout.operator("graph.snap", text="Flatten Handles").type = 'HORIZONTAL'
|
||||
layout.operator("graph.equalize_handles", text="Equalize Handles").side = 'BOTH'
|
||||
layout.separator()
|
||||
layout.operator("graph.frame_jump", text="Cursor to Selection")
|
||||
layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection")
|
||||
|
@@ -142,6 +142,8 @@ def mesh_node_items(context):
|
||||
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
|
||||
|
||||
yield NodeItem("GeometryNodeDualMesh")
|
||||
yield NodeItem("GeometryNodeExtrudeMesh")
|
||||
yield NodeItem("GeometryNodeFlipFaces")
|
||||
yield NodeItem("GeometryNodeMeshBoolean")
|
||||
yield NodeItem("GeometryNodeMeshToCurve")
|
||||
yield NodeItem("GeometryNodeMeshToPoints")
|
||||
@@ -149,6 +151,7 @@ def mesh_node_items(context):
|
||||
yield NodeItem("GeometryNodeSubdivideMesh")
|
||||
yield NodeItem("GeometryNodeSubdivisionSurface")
|
||||
yield NodeItem("GeometryNodeTriangulate")
|
||||
yield NodeItem("GeometryNodeScaleElements")
|
||||
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
|
||||
yield NodeItem("GeometryNodeInputMeshEdgeAngle")
|
||||
yield NodeItem("GeometryNodeInputMeshEdgeNeighbors")
|
||||
@@ -178,6 +181,7 @@ def geometry_node_items(context):
|
||||
yield NodeItem("GeometryNodeConvexHull")
|
||||
yield NodeItem("GeometryNodeDeleteGeometry")
|
||||
yield NodeItem("GeometryNodeGeometryToInstance")
|
||||
yield NodeItem("GeometryNodeMergeByDistance")
|
||||
yield NodeItem("GeometryNodeProximity")
|
||||
yield NodeItem("GeometryNodeJoinGeometry")
|
||||
yield NodeItem("GeometryNodeRaycast")
|
||||
@@ -387,6 +391,7 @@ shader_node_categories = [
|
||||
NodeItem("ShaderNodeAmbientOcclusion"),
|
||||
NodeItem("ShaderNodeObjectInfo"),
|
||||
NodeItem("ShaderNodeHairInfo"),
|
||||
NodeItem("ShaderNodePointInfo"),
|
||||
NodeItem("ShaderNodeVolumeInfo"),
|
||||
NodeItem("ShaderNodeParticleInfo"),
|
||||
NodeItem("ShaderNodeCameraData"),
|
||||
|
@@ -2,7 +2,7 @@ import bpy
|
||||
|
||||
|
||||
class ModalTimerOperator(bpy.types.Operator):
|
||||
"""Operator which runs its self from a timer"""
|
||||
"""Operator which runs itself from a timer"""
|
||||
bl_idname = "wm.modal_timer_operator"
|
||||
bl_label = "Modal Timer Operator"
|
||||
|
||||
|
@@ -54,7 +54,7 @@ set(LIB
|
||||
bf_gpu
|
||||
bf_intern_guardedalloc
|
||||
|
||||
${FREETYPE_LIBRARY}
|
||||
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
@@ -399,7 +399,6 @@ bool editbmesh_modifier_is_enabled(struct Scene *scene,
|
||||
void makeDerivedMesh(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct Object *ob,
|
||||
struct BMEditMesh *em,
|
||||
const struct CustomData_MeshMasks *dataMask);
|
||||
|
||||
void DM_calc_loop_tangents(DerivedMesh *dm,
|
||||
|
@@ -230,6 +230,43 @@ template<typename T> class SimpleMixer {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixes together booleans with "or" while fitting the same interface as the other
|
||||
* mixers in order to be simpler to use. This mixing method has a few benefits:
|
||||
* - An "average" for selections is relatively meaningless.
|
||||
* - Predictable selection propagation is very super important.
|
||||
* - It's generally easier to remove an element from a selection that is slightly too large than
|
||||
* the opposite.
|
||||
*/
|
||||
class BooleanPropagationMixer {
|
||||
private:
|
||||
MutableSpan<bool> buffer_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \param buffer: Span where the interpolated values should be stored.
|
||||
*/
|
||||
BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer)
|
||||
{
|
||||
buffer_.fill(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix a #value into the element with the given #index.
|
||||
*/
|
||||
void mix_in(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f)
|
||||
{
|
||||
buffer_[index] |= value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not do anything, since the mixing is trivial.
|
||||
*/
|
||||
void finalize()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This mixer accumulates values in a type that is different from the one that is mixed.
|
||||
* Some types cannot encode the floating point weights in their values (e.g. int and bool).
|
||||
@@ -291,7 +328,7 @@ class ColorGeometryMixer {
|
||||
};
|
||||
|
||||
template<typename T> struct DefaultMixerStruct {
|
||||
/* Use void by default. This can be check for in `if constexpr` statements. */
|
||||
/* Use void by default. This can be checked for in `if constexpr` statements. */
|
||||
using type = void;
|
||||
};
|
||||
template<> struct DefaultMixerStruct<float> {
|
||||
@@ -327,6 +364,23 @@ template<> struct DefaultMixerStruct<bool> {
|
||||
using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>;
|
||||
};
|
||||
|
||||
template<typename T> struct DefaultPropatationMixerStruct {
|
||||
/* Use void by default. This can be checked for in `if constexpr` statements. */
|
||||
using type = typename DefaultMixerStruct<T>::type;
|
||||
};
|
||||
|
||||
template<> struct DefaultPropatationMixerStruct<bool> {
|
||||
using type = BooleanPropagationMixer;
|
||||
};
|
||||
|
||||
/**
|
||||
* This mixer is meant for propagating attributes when creating new geometry. A key difference
|
||||
* with the default mixer is that booleans are mixed with "or" instead of "at least half"
|
||||
* (the default mixing for booleans).
|
||||
*/
|
||||
template<typename T>
|
||||
using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type;
|
||||
|
||||
/* Utility to get a good default mixer for a given type. This is `void` when there is no default
|
||||
* mixer for the given type. */
|
||||
template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type;
|
||||
|
@@ -30,8 +30,8 @@ struct LibraryLink_Params;
|
||||
struct Main;
|
||||
struct ReportList;
|
||||
struct Scene;
|
||||
struct ViewLayer;
|
||||
struct View3D;
|
||||
struct ViewLayer;
|
||||
|
||||
typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext;
|
||||
typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem;
|
||||
|
@@ -26,10 +26,12 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct BMEditMesh;
|
||||
struct Depsgraph;
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
struct ReportList;
|
||||
struct Scene;
|
||||
|
||||
/* crazyspace.c */
|
||||
@@ -69,6 +71,31 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
|
||||
float (**deformmats)[3][3],
|
||||
float (**deformcos)[3]);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Crazy-Space API
|
||||
* \{ */
|
||||
|
||||
void BKE_crazyspace_api_eval(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct Object *object,
|
||||
struct ReportList *reports);
|
||||
|
||||
void BKE_crazyspace_api_displacement_to_deformed(struct Object *object,
|
||||
struct ReportList *reports,
|
||||
int vertex_index,
|
||||
float displacement[3],
|
||||
float r_displacement_deformed[3]);
|
||||
|
||||
void BKE_crazyspace_api_displacement_to_original(struct Object *object,
|
||||
struct ReportList *reports,
|
||||
int vertex_index,
|
||||
float displacement_deformed[3],
|
||||
float r_displacement[3]);
|
||||
|
||||
void BKE_crazyspace_api_eval_clear(struct Object *object);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -16,8 +16,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Mesh;
|
||||
struct CurveEval;
|
||||
struct Mesh;
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
|
@@ -27,11 +27,11 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
struct Depsgraph;
|
||||
struct ID;
|
||||
struct ListBase;
|
||||
struct Object;
|
||||
struct ParticleSystem;
|
||||
struct Scene;
|
||||
struct ID;
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
/* Dupli-Geometry */
|
||||
|
@@ -62,14 +62,6 @@ typedef struct BMEditMesh {
|
||||
struct BMLoop *(*looptris)[3];
|
||||
int tottri;
|
||||
|
||||
struct Mesh *mesh_eval_final, *mesh_eval_cage;
|
||||
|
||||
/** Cached cage bounding box of `mesh_eval_cage` for selection. */
|
||||
struct BoundBox *bb_cage;
|
||||
|
||||
/** Evaluated mesh data-mask. */
|
||||
CustomData_MeshMasks lastDataMask;
|
||||
|
||||
/** Selection mode (#SCE_SELECT_VERTEX, #SCE_SELECT_EDGE & #SCE_SELECT_FACE). */
|
||||
short selectmode;
|
||||
/** The active material (assigned to newly created faces). */
|
||||
@@ -121,7 +113,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
|
||||
* don't add NULL data check here. caller must do that
|
||||
*/
|
||||
BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
|
||||
void BKE_editmesh_free_derived_caches(BMEditMesh *em);
|
||||
/**
|
||||
* \note Does not free the #BMEditMesh struct itself.
|
||||
*/
|
||||
@@ -145,7 +136,7 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
|
||||
* If auto-smooth not already set, set it.
|
||||
*/
|
||||
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
|
||||
struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
|
||||
struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -31,11 +31,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct BPathForeachPathData;
|
||||
struct BlendDataReader;
|
||||
struct BlendExpander;
|
||||
struct BlendLibReader;
|
||||
struct BlendWriter;
|
||||
struct BPathForeachPathData;
|
||||
struct ID;
|
||||
struct LibraryForeachIDData;
|
||||
struct Main;
|
||||
|
@@ -157,6 +157,14 @@ int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct La
|
||||
void BKE_layer_collection_resync_forbid(void);
|
||||
void BKE_layer_collection_resync_allow(void);
|
||||
|
||||
/**
|
||||
* Helper to fix older pre-2.80 blend-files.
|
||||
*
|
||||
* Ensures the given `view_layer` as a valid first-level layer collection, i.e. a single one
|
||||
* matching the scene's master collection. This is a requirement for `BKE_layer_collection_sync`.
|
||||
*/
|
||||
void BKE_layer_collection_doversion_2_80(const struct Scene *scene, struct ViewLayer *view_layer);
|
||||
|
||||
void BKE_main_collection_sync(const struct Main *bmain);
|
||||
void BKE_scene_collection_sync(const struct Scene *scene);
|
||||
/**
|
||||
|
@@ -382,6 +382,16 @@ enum {
|
||||
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to decide whether given `id` can be directly made local, or needs to be copied.
|
||||
* `r_force_local` and `r_force_copy` cannot be true together. But both can be false, in case no
|
||||
* action should be performed.
|
||||
*
|
||||
* \note low-level helper to de-duplicate logic between `BKE_lib_id_make_local_generic` and the
|
||||
* specific corner-cases implementations needed for objects and brushes.
|
||||
*/
|
||||
void BKE_lib_id_make_local_generic_action_define(
|
||||
struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy);
|
||||
/**
|
||||
* Generic 'make local' function, works for most of data-block types.
|
||||
*/
|
||||
|
@@ -38,6 +38,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID;
|
||||
struct IDRemapper;
|
||||
|
||||
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
|
||||
|
||||
/* Also IDRemap->flag. */
|
||||
@@ -97,6 +100,19 @@ enum {
|
||||
ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9,
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all references in given Main using the given \a mappings
|
||||
*
|
||||
* \note Is preferred over BKE_libblock_remap_locked due to performance.
|
||||
*/
|
||||
void BKE_libblock_remap_multiple_locked(struct Main *bmain,
|
||||
const struct IDRemapper *mappings,
|
||||
const short remap_flags);
|
||||
|
||||
void BKE_libblock_remap_multiple(struct Main *bmain,
|
||||
const struct IDRemapper *mappings,
|
||||
const short remap_flags);
|
||||
|
||||
/**
|
||||
* Replace all references in given Main to \a old_id by \a new_id
|
||||
* (if \a new_id is NULL, it unlinks \a old_id).
|
||||
@@ -146,12 +162,61 @@ void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, int remap_f
|
||||
ATTR_NONNULL();
|
||||
|
||||
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
|
||||
typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
|
||||
typedef void (*BKE_library_remap_editor_id_reference_cb)(const struct IDRemapper *mappings);
|
||||
|
||||
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
|
||||
void BKE_library_callback_remap_editor_id_reference_set(
|
||||
BKE_library_remap_editor_id_reference_cb func);
|
||||
|
||||
/* IDRemapper */
|
||||
struct IDRemapper;
|
||||
typedef enum IDRemapperApplyResult {
|
||||
/** No remapping rules available for the source. */
|
||||
ID_REMAP_RESULT_SOURCE_UNAVAILABLE,
|
||||
/** Source isn't mappable (e.g. NULL). */
|
||||
ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE,
|
||||
/** Source has been remapped to a new pointer. */
|
||||
ID_REMAP_RESULT_SOURCE_REMAPPED,
|
||||
/** Source has been set to NULL. */
|
||||
ID_REMAP_RESULT_SOURCE_UNASSIGNED,
|
||||
} IDRemapperApplyResult;
|
||||
|
||||
typedef enum IDRemapperApplyOptions {
|
||||
ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),
|
||||
ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),
|
||||
|
||||
ID_REMAP_APPLY_DEFAULT = 0,
|
||||
} IDRemapperApplyOptions;
|
||||
|
||||
typedef void (*IDRemapperIterFunction)(struct ID *old_id, struct ID *new_id, void *user_data);
|
||||
|
||||
/**
|
||||
* Create a new ID Remapper.
|
||||
*
|
||||
* An ID remapper stores multiple remapping rules.
|
||||
*/
|
||||
struct IDRemapper *BKE_id_remapper_create(void);
|
||||
|
||||
void BKE_id_remapper_clear(struct IDRemapper *id_remapper);
|
||||
bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper);
|
||||
/** Free the given ID Remapper. */
|
||||
void BKE_id_remapper_free(struct IDRemapper *id_remapper);
|
||||
/** Add a new remapping. */
|
||||
void BKE_id_remapper_add(struct IDRemapper *id_remapper, struct ID *old_id, struct ID *new_id);
|
||||
|
||||
/**
|
||||
* Apply a remapping.
|
||||
*
|
||||
* Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
|
||||
*/
|
||||
IDRemapperApplyResult BKE_id_remapper_apply(const struct IDRemapper *id_remapper,
|
||||
struct ID **r_id_ptr,
|
||||
IDRemapperApplyOptions options);
|
||||
bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter);
|
||||
void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
|
||||
IDRemapperIterFunction func,
|
||||
void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -119,6 +119,9 @@ void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
|
||||
void BKE_mesh_free_data_for_undo(struct Mesh *me);
|
||||
void BKE_mesh_clear_geometry(struct Mesh *me);
|
||||
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
|
||||
|
||||
void BKE_mesh_free_editmesh(struct Mesh *mesh);
|
||||
|
||||
/**
|
||||
* A version of #BKE_mesh_copy_parameters that is intended for evaluated output
|
||||
* (the modifier stack for example).
|
||||
|
@@ -1178,30 +1178,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
#define SH_NODE_OUTPUT_AOV 707
|
||||
#define SH_NODE_VECTOR_ROTATE 708
|
||||
#define SH_NODE_CURVE_FLOAT 709
|
||||
|
||||
/* API */
|
||||
|
||||
struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
|
||||
void ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
|
||||
/**
|
||||
Find an output node of the shader tree.
|
||||
*
|
||||
* \note it will only return output which is NOT in the group, which isn't how
|
||||
* render engines works but it's how the GPU shader compilation works. This we
|
||||
* can change in the future and make it a generic function, but for now it stays
|
||||
* private here.
|
||||
*/
|
||||
struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
|
||||
/**
|
||||
* This one needs to work on a local tree.
|
||||
*
|
||||
* TODO: This is *not* part of `blenkernel`, it's defined under "source/blender/nodes/".
|
||||
* This declaration should be moved out of BKE.
|
||||
*/
|
||||
void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
|
||||
struct GPUMaterial *mat,
|
||||
bool *has_surface_output,
|
||||
bool *has_volume_output);
|
||||
#define SH_NODE_POINT_INFO 710
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -1352,75 +1329,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
|
||||
#define CMP_DEFAULT_SMAA_CONTRAST_LIMIT 0.2f
|
||||
#define CMP_DEFAULT_SMAA_CORNER_ROUNDING 0.25f
|
||||
|
||||
/* API */
|
||||
void ntreeCompositExecTree(struct Scene *scene,
|
||||
struct bNodeTree *ntree,
|
||||
struct RenderData *rd,
|
||||
int rendering,
|
||||
int do_previews,
|
||||
const struct ColorManagedViewSettings *view_settings,
|
||||
const struct ColorManagedDisplaySettings *display_settings,
|
||||
const char *view_name);
|
||||
|
||||
/**
|
||||
* Called from render pipeline, to tag render input and output.
|
||||
* need to do all scenes, to prevent errors when you re-render 1 scene.
|
||||
*/
|
||||
void ntreeCompositTagRender(struct Scene *scene);
|
||||
/**
|
||||
* Update the outputs of the render layer nodes.
|
||||
* Since the outputs depend on the render engine, this part is a bit complex:
|
||||
* - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
|
||||
* - Each render layer node calls the update function of the
|
||||
* render engine that's used for its scene.
|
||||
* - The render engine calls RE_engine_register_pass for each pass.
|
||||
* - #RE_engine_register_pass calls #node_cmp_rlayers_register_pass.
|
||||
*
|
||||
* TODO: This is *not* part of `blenkernel`, it's defined under "source/blender/nodes/".
|
||||
* This declaration should be moved out of BKE.
|
||||
*/
|
||||
void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
|
||||
void ntreeCompositClearTags(struct bNodeTree *ntree);
|
||||
|
||||
struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree,
|
||||
struct bNode *node,
|
||||
const char *name,
|
||||
struct ImageFormatData *im_format);
|
||||
int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node);
|
||||
void ntreeCompositOutputFileSetPath(struct bNode *node,
|
||||
struct bNodeSocket *sock,
|
||||
const char *name);
|
||||
void ntreeCompositOutputFileSetLayer(struct bNode *node,
|
||||
struct bNodeSocket *sock,
|
||||
const char *name);
|
||||
/* needed in do_versions */
|
||||
void ntreeCompositOutputFileUniquePath(struct ListBase *list,
|
||||
struct bNodeSocket *sock,
|
||||
const char defname[],
|
||||
char delim);
|
||||
void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
|
||||
struct bNodeSocket *sock,
|
||||
const char defname[],
|
||||
char delim);
|
||||
|
||||
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
|
||||
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
|
||||
|
||||
void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node);
|
||||
void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
|
||||
bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
|
||||
int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
|
||||
void ntreeCompositCryptomatteLayerPrefix(const Scene *scene,
|
||||
const bNode *node,
|
||||
char *r_prefix,
|
||||
size_t prefix_len);
|
||||
/**
|
||||
* Update the runtime layer names with the crypto-matte layer names of the references render layer
|
||||
* or image.
|
||||
*/
|
||||
void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
|
||||
struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -1457,24 +1365,6 @@ struct TexResult;
|
||||
#define TEX_NODE_PROC 500
|
||||
#define TEX_NODE_PROC_MAX 600
|
||||
|
||||
/* API */
|
||||
void ntreeTexCheckCyclics(struct bNodeTree *ntree);
|
||||
|
||||
struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
|
||||
void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
|
||||
int ntreeTexExecTree(struct bNodeTree *ntree,
|
||||
struct TexResult *target,
|
||||
const float co[3],
|
||||
float dxt[3],
|
||||
float dyt[3],
|
||||
int osatex,
|
||||
short thread,
|
||||
const struct Tex *tex,
|
||||
short which_output,
|
||||
int cfra,
|
||||
int preview,
|
||||
struct MTex *mtex);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -1630,6 +1520,10 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
||||
#define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147
|
||||
#define GEO_NODE_FIELD_AT_INDEX 1148
|
||||
#define GEO_NODE_CURVE_PRIMITIVE_ARC 1149
|
||||
#define GEO_NODE_FLIP_FACES 1150
|
||||
#define GEO_NODE_SCALE_ELEMENTS 1151
|
||||
#define GEO_NODE_EXTRUDE_MESH 1152
|
||||
#define GEO_NODE_MERGE_BY_DISTANCE 1153
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@@ -20,12 +20,12 @@
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
struct ID;
|
||||
struct Main;
|
||||
struct bNode;
|
||||
struct bNodeLink;
|
||||
struct bNodeSocket;
|
||||
struct bNodeTree;
|
||||
struct bNodeLink;
|
||||
struct Main;
|
||||
struct ID;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@@ -530,6 +530,9 @@ struct Mesh *BKE_object_get_pre_modified_mesh(const struct Object *object);
|
||||
*/
|
||||
struct Mesh *BKE_object_get_original_mesh(const struct Object *object);
|
||||
|
||||
struct Mesh *BKE_object_get_editmesh_eval_final(const struct Object *object);
|
||||
struct Mesh *BKE_object_get_editmesh_eval_cage(const struct Object *object);
|
||||
|
||||
/* Lattice accessors.
|
||||
* These functions return either the regular lattice, or the edit-mode lattice,
|
||||
* whichever is currently in use. */
|
||||
|
@@ -617,10 +617,6 @@ typedef struct SculptSession {
|
||||
float init_pivot_rot[4];
|
||||
float init_pivot_scale[3];
|
||||
|
||||
float prev_pivot_pos[3];
|
||||
float prev_pivot_rot[4];
|
||||
float prev_pivot_scale[3];
|
||||
|
||||
union {
|
||||
struct {
|
||||
struct SculptVertexPaintGeomMap gmap;
|
||||
|
@@ -38,6 +38,7 @@ struct BlendLibReader;
|
||||
struct BlendWriter;
|
||||
struct Header;
|
||||
struct ID;
|
||||
struct IDRemapper;
|
||||
struct LibraryForeachIDData;
|
||||
struct ListBase;
|
||||
struct Menu;
|
||||
@@ -117,10 +118,7 @@ typedef struct SpaceType {
|
||||
bContextDataCallback context;
|
||||
|
||||
/* Used when we want to replace an ID by another (or NULL). */
|
||||
void (*id_remap)(struct ScrArea *area,
|
||||
struct SpaceLink *sl,
|
||||
struct ID *old_id,
|
||||
struct ID *new_id);
|
||||
void (*id_remap)(struct ScrArea *area, struct SpaceLink *sl, const struct IDRemapper *mappings);
|
||||
|
||||
int (*space_subtype_get)(struct ScrArea *area);
|
||||
void (*space_subtype_set)(struct ScrArea *area, int value);
|
||||
|
@@ -47,8 +47,8 @@ struct MDeformVert;
|
||||
struct Mesh;
|
||||
struct ModifierEvalContext;
|
||||
struct Object;
|
||||
struct ShrinkwrapModifierData;
|
||||
struct ShrinkwrapGpencilModifierData;
|
||||
struct ShrinkwrapModifierData;
|
||||
struct SpaceTransform;
|
||||
|
||||
/* Information about boundary edges in the mesh. */
|
||||
|
@@ -30,8 +30,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
struct Mesh;
|
||||
struct Subdiv;
|
||||
struct OpenSubdiv_EvaluatorCache;
|
||||
struct Subdiv;
|
||||
|
||||
typedef enum eSubdivEvaluatorType {
|
||||
SUBDIV_EVALUATOR_TYPE_CPU,
|
||||
|
@@ -179,6 +179,7 @@ set(SRC
|
||||
intern/lib_id.c
|
||||
intern/lib_id_delete.c
|
||||
intern/lib_id_eval.c
|
||||
intern/lib_id_remapper.cc
|
||||
intern/lib_override.c
|
||||
intern/lib_query.c
|
||||
intern/lib_remap.c
|
||||
@@ -522,7 +523,7 @@ set(LIB
|
||||
bf_simulation
|
||||
|
||||
# For `vfontdata_freetype.c`.
|
||||
${FREETYPE_LIBRARY}
|
||||
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
|
||||
)
|
||||
|
||||
if(WITH_BINRELOC)
|
||||
@@ -823,6 +824,7 @@ if(WITH_GTESTS)
|
||||
intern/idprop_serialize_test.cc
|
||||
intern/lattice_deform_test.cc
|
||||
intern/layer_test.cc
|
||||
intern/lib_id_remapper_test.cc
|
||||
intern/lib_id_test.cc
|
||||
intern/lib_remap_test.cc
|
||||
intern/tracking_test.cc
|
||||
|
@@ -1769,17 +1769,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
|
||||
const CustomData_MeshMasks *dataMask,
|
||||
const bool need_mapping)
|
||||
{
|
||||
BLI_assert(ob->type == OB_MESH);
|
||||
|
||||
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
|
||||
* they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
|
||||
BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
|
||||
|
||||
BKE_object_free_derived_caches(ob);
|
||||
if (DEG_is_active(depsgraph)) {
|
||||
BKE_sculpt_update_object_before_eval(ob);
|
||||
}
|
||||
|
||||
#if 0 /* XXX This is already taken care of in mesh_calc_modifiers()... */
|
||||
if (need_mapping) {
|
||||
/* Also add the flag so that it is recorded in lastDataMask. */
|
||||
@@ -1846,15 +1835,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
|
||||
BMEditMesh *em,
|
||||
CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
BLI_assert(obedit->id.tag & LIB_TAG_COPIED_ON_WRITE);
|
||||
|
||||
BKE_object_free_derived_caches(obedit);
|
||||
if (DEG_is_active(depsgraph)) {
|
||||
BKE_sculpt_update_object_before_eval(obedit);
|
||||
}
|
||||
|
||||
BKE_editmesh_free_derived_caches(em);
|
||||
|
||||
Mesh *mesh = static_cast<Mesh *>(obedit->data);
|
||||
Mesh *me_cage;
|
||||
Mesh *me_final;
|
||||
GeometrySet *non_mesh_components;
|
||||
@@ -1862,13 +1843,33 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
|
||||
editbmesh_calc_modifiers(
|
||||
depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components);
|
||||
|
||||
em->mesh_eval_final = me_final;
|
||||
em->mesh_eval_cage = me_cage;
|
||||
/* The modifier stack result is expected to share edit mesh pointer with the input.
|
||||
* This is similar `mesh_calc_finalize()`. */
|
||||
BKE_mesh_free_editmesh(me_final);
|
||||
BKE_mesh_free_editmesh(me_cage);
|
||||
me_final->edit_mesh = me_cage->edit_mesh = em;
|
||||
|
||||
/* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
|
||||
* with is in edit mode).
|
||||
* Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
|
||||
* edit mode. */
|
||||
if (!(obedit->mode & OB_MODE_EDIT)) {
|
||||
BKE_mesh_wrapper_ensure_mdata(me_final);
|
||||
if (me_final != me_cage) {
|
||||
BKE_mesh_wrapper_ensure_mdata(me_cage);
|
||||
}
|
||||
}
|
||||
|
||||
const bool is_mesh_eval_owned = (me_final != mesh->runtime.mesh_eval);
|
||||
BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
|
||||
|
||||
obedit->runtime.editmesh_eval_cage = me_cage;
|
||||
|
||||
obedit->runtime.geometry_set_eval = non_mesh_components;
|
||||
|
||||
BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
|
||||
BKE_object_boundbox_calc_from_mesh(obedit, me_final);
|
||||
|
||||
em->lastDataMask = *dataMask;
|
||||
obedit->runtime.last_data_mask = *dataMask;
|
||||
}
|
||||
|
||||
static void object_get_datamask(const Depsgraph *depsgraph,
|
||||
@@ -1924,9 +1925,25 @@ static void object_get_datamask(const Depsgraph *depsgraph,
|
||||
void makeDerivedMesh(struct Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
Object *ob,
|
||||
BMEditMesh *em,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
BLI_assert(ob->type == OB_MESH);
|
||||
|
||||
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
|
||||
* they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
|
||||
BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
|
||||
|
||||
BKE_object_free_derived_caches(ob);
|
||||
if (DEG_is_active(depsgraph)) {
|
||||
BKE_sculpt_update_object_before_eval(ob);
|
||||
}
|
||||
|
||||
/* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored
|
||||
* to the pre-evaluated state. This is because the evaluated state is not necessarily sharing the
|
||||
* `edit_mesh` pointer with the input. For example, if the object is first evaluated in the
|
||||
* object mode, and then user in another scene moves object to edit mode. */
|
||||
BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
|
||||
|
||||
bool need_mapping;
|
||||
CustomData_MeshMasks cddata_masks = *dataMask;
|
||||
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
|
||||
@@ -1965,8 +1982,9 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
|
||||
!CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
|
||||
(need_mapping && !ob->runtime.last_need_mapping)) {
|
||||
CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
|
||||
mesh_build_data(
|
||||
depsgraph, scene, ob, &cddata_masks, need_mapping || ob->runtime.last_need_mapping);
|
||||
|
||||
makeDerivedMesh(depsgraph, scene, ob, dataMask);
|
||||
|
||||
mesh_eval = BKE_object_get_evaluated_mesh(ob);
|
||||
}
|
||||
|
||||
@@ -1981,6 +1999,15 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
|
||||
Object *ob,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
|
||||
if (em != nullptr) {
|
||||
/* There is no such a concept as deformed mesh in edit mode.
|
||||
* Explicitly disallow this request so that the evaluated result is not modified with evaluated
|
||||
* result from the wrong mode. */
|
||||
BLI_assert_msg(0, "Request of derformed mesh of object which is in edit mode");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* This function isn't thread-safe and can't be used during evaluation. */
|
||||
BLI_assert(DEG_is_evaluating(depsgraph) == false);
|
||||
|
||||
@@ -2055,12 +2082,12 @@ Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
|
||||
*/
|
||||
object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
|
||||
|
||||
if (!em->mesh_eval_cage ||
|
||||
!CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
|
||||
if (!obedit->runtime.editmesh_eval_cage ||
|
||||
!CustomData_MeshMasks_are_matching(&(obedit->runtime.last_data_mask), &cddata_masks)) {
|
||||
editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
|
||||
}
|
||||
|
||||
return em->mesh_eval_cage;
|
||||
return obedit->runtime.editmesh_eval_cage;
|
||||
}
|
||||
|
||||
Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
|
||||
|
@@ -520,7 +520,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
|
||||
"A non-empty .blend file path is required to be able to determine where the "
|
||||
"catalog definition file should be put");
|
||||
|
||||
/* Ask the asset library API for an appropriate location. */
|
||||
/* Ask the asset library API for an appropriate location. */
|
||||
char suitable_root_path[PATH_MAX];
|
||||
const bool asset_lib_root_found = BKE_asset_library_find_suitable_root_path_from_path(
|
||||
blend_file_path.c_str(), suitable_root_path);
|
||||
|
@@ -149,16 +149,9 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
|
||||
|
||||
Brush *brush = (Brush *)id;
|
||||
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
||||
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
|
||||
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
|
||||
BLI_assert(force_copy == false || force_copy != force_local);
|
||||
|
||||
bool is_local = false, is_lib = false;
|
||||
|
||||
/* - only lib users: do nothing (unless force_local is set)
|
||||
* - only local users: set flag
|
||||
* - mixed: make copy
|
||||
*/
|
||||
bool force_local, force_copy;
|
||||
BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
|
||||
|
||||
if (brush->clone.image) {
|
||||
/* Special case: ima always local immediately. Clone image should only have one user anyway. */
|
||||
@@ -171,18 +164,6 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
|
||||
BLI_assert(brush->clone.image->id.lib == NULL && brush->clone.image->id.newid == NULL);
|
||||
}
|
||||
|
||||
if (!force_local && !force_copy) {
|
||||
BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
|
||||
if (lib_local || is_local) {
|
||||
if (!is_lib) {
|
||||
force_local = true;
|
||||
}
|
||||
else {
|
||||
force_copy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (force_local) {
|
||||
BKE_lib_id_clear_library_data(bmain, &brush->id, flags);
|
||||
BKE_lib_id_expand_local(bmain, &brush->id, flags);
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_multires.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
@@ -109,7 +110,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object
|
||||
/* disable subsurf temporal, get mapped cos, and enable it */
|
||||
if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) {
|
||||
/* need to make new derivemesh */
|
||||
makeDerivedMesh(depsgraph, scene_eval, obedit_eval, editmesh_eval, &CD_MASK_BAREMESH);
|
||||
makeDerivedMesh(depsgraph, scene_eval, obedit_eval, &CD_MASK_BAREMESH);
|
||||
}
|
||||
|
||||
/* now get the cage */
|
||||
@@ -516,3 +517,85 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Crazyspace API
|
||||
* \{ */
|
||||
|
||||
void BKE_crazyspace_api_eval(Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
Object *object,
|
||||
struct ReportList *reports)
|
||||
{
|
||||
if (object->runtime.crazyspace_deform_imats != NULL ||
|
||||
object->runtime.crazyspace_deform_cos != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (object->type != OB_MESH) {
|
||||
BKE_report(reports,
|
||||
RPT_ERROR,
|
||||
"Crazyspace transformation is only available for Mesh type of objects");
|
||||
return;
|
||||
}
|
||||
|
||||
const Mesh *mesh = (const Mesh *)object->data;
|
||||
object->runtime.crazyspace_num_verts = mesh->totvert;
|
||||
BKE_crazyspace_build_sculpt(depsgraph,
|
||||
scene,
|
||||
object,
|
||||
&object->runtime.crazyspace_deform_imats,
|
||||
&object->runtime.crazyspace_deform_cos);
|
||||
}
|
||||
|
||||
void BKE_crazyspace_api_displacement_to_deformed(struct Object *object,
|
||||
struct ReportList *reports,
|
||||
int vertex_index,
|
||||
float displacement[3],
|
||||
float r_displacement_deformed[3])
|
||||
{
|
||||
if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Invalid vertex index %d (expected to be within 0 to %d range)",
|
||||
vertex_index,
|
||||
object->runtime.crazyspace_num_verts);
|
||||
return;
|
||||
}
|
||||
|
||||
mul_v3_m3v3(r_displacement_deformed,
|
||||
object->runtime.crazyspace_deform_imats[vertex_index],
|
||||
displacement);
|
||||
}
|
||||
|
||||
void BKE_crazyspace_api_displacement_to_original(struct Object *object,
|
||||
struct ReportList *reports,
|
||||
int vertex_index,
|
||||
float displacement_deformed[3],
|
||||
float r_displacement[3])
|
||||
{
|
||||
if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Invalid vertex index %d (expected to be within 0 to %d range))",
|
||||
vertex_index,
|
||||
object->runtime.crazyspace_num_verts);
|
||||
return;
|
||||
}
|
||||
|
||||
float mat[3][3];
|
||||
if (!invert_m3_m3(mat, object->runtime.crazyspace_deform_imats[vertex_index])) {
|
||||
copy_v3_v3(r_displacement, displacement_deformed);
|
||||
return;
|
||||
}
|
||||
|
||||
mul_v3_m3v3(r_displacement, mat, displacement_deformed);
|
||||
}
|
||||
|
||||
void BKE_crazyspace_api_eval_clear(Object *object)
|
||||
{
|
||||
MEM_SAFE_FREE(object->runtime.crazyspace_deform_imats);
|
||||
MEM_SAFE_FREE(object->runtime.crazyspace_deform_cos);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_endian_switch.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
@@ -67,10 +68,12 @@
|
||||
|
||||
#include "BLO_read_write.h"
|
||||
|
||||
using blender::IndexRange;
|
||||
|
||||
/* globals */
|
||||
|
||||
/* local */
|
||||
static CLG_LogRef LOG = {"bke.curve"};
|
||||
// static CLG_LogRef LOG = {"bke.curve"};
|
||||
|
||||
static void curve_init_data(ID *id)
|
||||
{
|
||||
@@ -1160,81 +1163,34 @@ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
|
||||
|
||||
static void calcknots(float *knots, const int pnts, const short order, const short flag)
|
||||
{
|
||||
/* knots: number of pnts NOT corrected for cyclic */
|
||||
const int pnts_order = pnts + order;
|
||||
float k;
|
||||
int a;
|
||||
const bool is_cyclic = flag & CU_NURB_CYCLIC;
|
||||
const bool is_bezier = flag & CU_NURB_BEZIER && !(flag & CU_NURB_ENDPOINT);
|
||||
const bool is_end_point = flag & CU_NURB_ENDPOINT && !(flag & CU_NURB_BEZIER);
|
||||
/* Inner knots are always repeated once except on Bezier case. */
|
||||
const int repeat_inner = is_bezier ? order - 1 : 1;
|
||||
/* How many times to repeat 0.0 at the beginning of knot. */
|
||||
const int head = is_end_point && !is_cyclic ? order : (is_bezier ? order / 2 : 1);
|
||||
/* Number of knots replicating widths of the starting knots.
|
||||
* Covers both Cyclic and EndPoint cases. */
|
||||
const int tail = is_cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
|
||||
|
||||
switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
|
||||
case CU_NURB_ENDPOINT:
|
||||
k = 0.0;
|
||||
for (a = 1; a <= pnts_order; a++) {
|
||||
knots[a - 1] = k;
|
||||
if (a >= order && a <= pnts) {
|
||||
k += 1.0f;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CU_NURB_BEZIER:
|
||||
/* Warning, the order MUST be 2 or 4,
|
||||
* if this is not enforced, the displist will be corrupt */
|
||||
if (order == 4) {
|
||||
k = 0.34;
|
||||
for (a = 0; a < pnts_order; a++) {
|
||||
knots[a] = floorf(k);
|
||||
k += (1.0f / 3.0f);
|
||||
}
|
||||
}
|
||||
else if (order == 3) {
|
||||
k = 0.6f;
|
||||
for (a = 0; a < pnts_order; a++) {
|
||||
if (a >= order && a <= pnts) {
|
||||
k += 0.5f;
|
||||
}
|
||||
knots[a] = floorf(k);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (a = 0; a < pnts_order; a++) {
|
||||
knots[a] = (float)a;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
const int knot_count = pnts + order + (is_cyclic ? order - 1 : 0);
|
||||
|
||||
static void makecyclicknots(float *knots, int pnts, short order)
|
||||
/* pnts, order: number of pnts NOT corrected for cyclic */
|
||||
{
|
||||
int a, b, order2, c;
|
||||
int r = head;
|
||||
float current = 0.0f;
|
||||
|
||||
if (knots == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
order2 = order - 1;
|
||||
|
||||
/* do first long rows (order -1), remove identical knots at endpoints */
|
||||
if (order > 2) {
|
||||
b = pnts + order2;
|
||||
for (a = 1; a < order2; a++) {
|
||||
if (knots[b] != knots[b - a]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (a == order2) {
|
||||
knots[pnts + order - 2] += 1.0f;
|
||||
for (const int i : IndexRange(knot_count - tail)) {
|
||||
knots[i] = current;
|
||||
r--;
|
||||
if (r == 0) {
|
||||
current += 1.0;
|
||||
r = repeat_inner;
|
||||
}
|
||||
}
|
||||
|
||||
b = order;
|
||||
c = pnts + order + order2;
|
||||
for (a = pnts + order2; a < c; a++) {
|
||||
knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]);
|
||||
b--;
|
||||
const int tail_index = knot_count - tail;
|
||||
for (const int i : IndexRange(tail)) {
|
||||
knots[tail_index + i] = current + (knots[i] - knots[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,13 +1203,7 @@ static void makeknots(Nurb *nu, short uv)
|
||||
}
|
||||
if (BKE_nurb_check_valid_u(nu)) {
|
||||
nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
|
||||
if (nu->flagu & CU_NURB_CYCLIC) {
|
||||
calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
|
||||
makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
|
||||
}
|
||||
else {
|
||||
calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
|
||||
}
|
||||
calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
|
||||
}
|
||||
else {
|
||||
nu->knotsu = nullptr;
|
||||
@@ -1265,13 +1215,7 @@ static void makeknots(Nurb *nu, short uv)
|
||||
}
|
||||
if (BKE_nurb_check_valid_v(nu)) {
|
||||
nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
|
||||
if (nu->flagv & CU_NURB_CYCLIC) {
|
||||
calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
|
||||
makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
|
||||
}
|
||||
else {
|
||||
calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
|
||||
}
|
||||
calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
|
||||
}
|
||||
else {
|
||||
nu->knotsv = nullptr;
|
||||
|
@@ -2209,7 +2209,9 @@ void CustomData_realloc(CustomData *data, int totelem)
|
||||
continue;
|
||||
}
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
|
||||
/* Use calloc to avoid the need to manually initialize new data in layers.
|
||||
* Useful for types like #MDeformVert which contain a pointer. */
|
||||
layer->data = MEM_recallocN(layer->data, (size_t)totelem * typeInfo->size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,8 @@
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
BMEditMesh *BKE_editmesh_create(BMesh *bm)
|
||||
{
|
||||
BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
|
||||
@@ -51,9 +53,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
|
||||
BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
|
||||
*em_copy = *em;
|
||||
|
||||
em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
|
||||
em_copy->bb_cage = NULL;
|
||||
|
||||
em_copy->bm = BM_mesh_copy(em->bm);
|
||||
|
||||
/* The tessellation is NOT calculated on the copy here,
|
||||
@@ -194,22 +193,8 @@ void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
|
||||
});
|
||||
}
|
||||
|
||||
void BKE_editmesh_free_derived_caches(BMEditMesh *em)
|
||||
{
|
||||
if (em->mesh_eval_cage) {
|
||||
BKE_id_free(NULL, em->mesh_eval_cage);
|
||||
}
|
||||
if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
|
||||
BKE_id_free(NULL, em->mesh_eval_final);
|
||||
}
|
||||
em->mesh_eval_cage = em->mesh_eval_final = NULL;
|
||||
|
||||
MEM_SAFE_FREE(em->bb_cage);
|
||||
}
|
||||
|
||||
void BKE_editmesh_free_data(BMEditMesh *em)
|
||||
{
|
||||
BKE_editmesh_free_derived_caches(em);
|
||||
|
||||
if (em->looptris) {
|
||||
MEM_freeN(em->looptris);
|
||||
@@ -283,13 +268,15 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
|
||||
*r_is_alloc = false;
|
||||
|
||||
Mesh *me = ob->data;
|
||||
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
|
||||
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
|
||||
|
||||
if ((me->runtime.edit_data != NULL) && (me->runtime.edit_data->vertexCos != NULL)) {
|
||||
/* Deformed, and we have deformed coords already. */
|
||||
coords = me->runtime.edit_data->vertexCos;
|
||||
}
|
||||
else if ((em->mesh_eval_final != NULL) &&
|
||||
(em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
|
||||
else if ((editmesh_eval_final != NULL) &&
|
||||
(editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
|
||||
/* If this is an edit-mesh type, leave NULL as we can use the vertex coords. */
|
||||
}
|
||||
else {
|
||||
@@ -334,18 +321,18 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
|
||||
}
|
||||
}
|
||||
|
||||
BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
|
||||
BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *UNUSED(em))
|
||||
{
|
||||
if (em->bb_cage == NULL) {
|
||||
if (object->runtime.editmesh_bb_cage == NULL) {
|
||||
float min[3], max[3];
|
||||
INIT_MINMAX(min, max);
|
||||
if (em->mesh_eval_cage) {
|
||||
BKE_mesh_wrapper_minmax(em->mesh_eval_cage, min, max);
|
||||
if (object->runtime.editmesh_eval_cage) {
|
||||
BKE_mesh_wrapper_minmax(object->runtime.editmesh_eval_cage, min, max);
|
||||
}
|
||||
|
||||
em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
|
||||
BKE_boundbox_init_from_minmax(em->bb_cage, min, max);
|
||||
object->runtime.editmesh_bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
|
||||
BKE_boundbox_init_from_minmax(object->runtime.editmesh_bb_cage, min, max);
|
||||
}
|
||||
|
||||
return em->bb_cage;
|
||||
return object->runtime.editmesh_bb_cage;
|
||||
}
|
||||
|
@@ -304,7 +304,7 @@ class IDPStringSerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
|
||||
DictionaryEntryParser &entry_reader) const override
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_STRING);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_STRING);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -344,7 +344,7 @@ class IDPIntSerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
|
||||
DictionaryEntryParser &entry_reader) const override
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_INT);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_INT);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -384,7 +384,7 @@ class IDPFloatSerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
|
||||
DictionaryEntryParser &entry_reader) const override
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_FLOAT);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_FLOAT);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -424,7 +424,7 @@ class IDPDoubleSerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
|
||||
DictionaryEntryParser &entry_reader) const override
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_DOUBLE);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_DOUBLE);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -502,7 +502,7 @@ class IDPArraySerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
|
||||
DictionaryEntryParser &entry_reader) const override
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_ARRAY);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
|
||||
std::optional<eIDPropertyType> property_subtype = entry_reader.get_subtype();
|
||||
if (!property_subtype.has_value()) {
|
||||
return nullptr;
|
||||
@@ -556,8 +556,8 @@ class IDPArraySerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_int_from_value(
|
||||
DictionaryEntryParser &entry_reader) const
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_ARRAY);
|
||||
BLI_assert(entry_reader.get_subtype().value() == IDP_INT);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
|
||||
BLI_assert(*(entry_reader.get_subtype()) == IDP_INT);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -572,8 +572,8 @@ class IDPArraySerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_float_from_value(
|
||||
DictionaryEntryParser &entry_reader) const
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_ARRAY);
|
||||
BLI_assert(entry_reader.get_subtype().value() == IDP_FLOAT);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
|
||||
BLI_assert(*(entry_reader.get_subtype()) == IDP_FLOAT);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -588,8 +588,8 @@ class IDPArraySerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_double_from_value(
|
||||
DictionaryEntryParser &entry_reader) const
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_ARRAY);
|
||||
BLI_assert(entry_reader.get_subtype().value() == IDP_DOUBLE);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
|
||||
BLI_assert(*(entry_reader.get_subtype()) == IDP_DOUBLE);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -639,7 +639,7 @@ class IDPGroupSerializer : public IDPropertySerializer {
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
|
||||
DictionaryEntryParser &entry_reader) const override
|
||||
{
|
||||
BLI_assert(entry_reader.get_type().value() == IDP_GROUP);
|
||||
BLI_assert(*(entry_reader.get_type()) == IDP_GROUP);
|
||||
std::optional<std::string> name = entry_reader.get_name();
|
||||
if (!name.has_value()) {
|
||||
return nullptr;
|
||||
@@ -796,7 +796,7 @@ static IDProperty *idprop_from_value(const DictionaryValue &value)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const IDPropertySerializer &serializer = serializer_for(property_type.value());
|
||||
const IDPropertySerializer &serializer = serializer_for(*property_type);
|
||||
return serializer.entry_to_idprop(entry_reader).release();
|
||||
}
|
||||
|
||||
|
@@ -121,7 +121,7 @@ static void image_init(Image *ima, short source, short type);
|
||||
static void image_free_packedfiles(Image *ima);
|
||||
static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src);
|
||||
|
||||
/* Reset runtime image fields when datablock is being initialized. */
|
||||
/* Reset runtime image fields when data-block is being initialized. */
|
||||
static void image_runtime_reset(struct Image *image)
|
||||
{
|
||||
memset(&image->runtime, 0, sizeof(image->runtime));
|
||||
@@ -129,7 +129,7 @@ static void image_runtime_reset(struct Image *image)
|
||||
BLI_mutex_init(image->runtime.cache_mutex);
|
||||
}
|
||||
|
||||
/* Reset runtime image fields when datablock is being copied. */
|
||||
/* Reset runtime image fields when data-block is being copied. */
|
||||
static void image_runtime_reset_on_copy(struct Image *image)
|
||||
{
|
||||
image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex");
|
||||
@@ -3553,7 +3553,7 @@ static void image_tag_frame_recalc(Image *ima, ID *iuser_id, ImageUser *iuser, v
|
||||
iuser->flag |= IMA_NEED_FRAME_RECALC;
|
||||
|
||||
if (iuser_id) {
|
||||
/* Must copy image user changes to CoW datablock. */
|
||||
/* Must copy image user changes to CoW data-block. */
|
||||
DEG_id_tag_update(iuser_id, ID_RECALC_COPY_ON_WRITE);
|
||||
}
|
||||
}
|
||||
@@ -3568,7 +3568,7 @@ static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *c
|
||||
image_update_views_format(ima, iuser);
|
||||
}
|
||||
if (iuser_id) {
|
||||
/* Must copy image user changes to CoW datablock. */
|
||||
/* Must copy image user changes to CoW data-block. */
|
||||
DEG_id_tag_update(iuser_id, ID_RECALC_COPY_ON_WRITE);
|
||||
}
|
||||
}
|
||||
@@ -5773,7 +5773,7 @@ static void image_user_id_has_animation(Image *ima,
|
||||
bool BKE_image_user_id_has_animation(ID *id)
|
||||
{
|
||||
/* For the dependency graph, this does not consider nested node
|
||||
* trees as these are handled as their own datablock. */
|
||||
* trees as these are handled as their own data-block. */
|
||||
bool has_animation = false;
|
||||
bool skip_nested_nodes = true;
|
||||
image_walk_id_all_users(id, skip_nested_nodes, &has_animation, image_user_id_has_animation);
|
||||
|
@@ -1196,6 +1196,23 @@ static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer)
|
||||
}
|
||||
#endif
|
||||
|
||||
void BKE_layer_collection_doversion_2_80(const Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
LayerCollection *first_layer_collection = view_layer->layer_collections.first;
|
||||
if (BLI_listbase_count_at_most(&view_layer->layer_collections, 2) > 1 ||
|
||||
first_layer_collection->collection != scene->master_collection) {
|
||||
/* In some cases (from older files) we do have a master collection, but no matching layer,
|
||||
* instead all the children of the master collection have their layer collections in the
|
||||
* viewlayer's list. This is not a valid situation, add a layer for the master collection and
|
||||
* add all existing first-level layers as children of that new master layer. */
|
||||
ListBase layer_collections = view_layer->layer_collections;
|
||||
BLI_listbase_clear(&view_layer->layer_collections);
|
||||
LayerCollection *master_layer_collection = layer_collection_add(&view_layer->layer_collections,
|
||||
scene->master_collection);
|
||||
master_layer_collection->layer_collections = layer_collections;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
if (no_resync) {
|
||||
@@ -1208,21 +1225,24 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
|
||||
}
|
||||
|
||||
if (BLI_listbase_is_empty(&view_layer->layer_collections)) {
|
||||
/* In some cases (from older files) we do have a master collection, yet no matching layer.
|
||||
* Create the master one here, so that the rest of the code can work as expected. */
|
||||
/* In some cases (from older files, or when creating a new ViewLayer from
|
||||
* #BKE_view_layer_add), we do have a master collection, yet no matching layer. Create the
|
||||
* master one here, so that the rest of the code can work as expected. */
|
||||
layer_collection_add(&view_layer->layer_collections, scene->master_collection);
|
||||
}
|
||||
else if (BLI_listbase_count_at_most(&view_layer->layer_collections, 2) > 1) {
|
||||
/* In some cases (from older files) we do have a master collection, but no matching layer,
|
||||
* instead all the children of the master collection have their layer collections in the
|
||||
* viewlayer's list. This is not a valid situation, add a layer for the master collection and
|
||||
* add all existing first-level layers as children of that new master layer. */
|
||||
ListBase layer_collections = view_layer->layer_collections;
|
||||
BLI_listbase_clear(&view_layer->layer_collections);
|
||||
LayerCollection *master_layer_collection = layer_collection_add(&view_layer->layer_collections,
|
||||
scene->master_collection);
|
||||
master_layer_collection->layer_collections = layer_collections;
|
||||
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
BLI_assert_msg(BLI_listbase_count_at_most(&view_layer->layer_collections, 2) == 1,
|
||||
"ViewLayer's first level of children layer collections should always have "
|
||||
"exactly one item");
|
||||
|
||||
LayerCollection *first_layer_collection = view_layer->layer_collections.first;
|
||||
BLI_assert_msg(first_layer_collection->collection == scene->master_collection,
|
||||
"ViewLayer's first layer collection should always be the one for the scene's "
|
||||
"master collection");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Free cache. */
|
||||
MEM_SAFE_FREE(view_layer->object_bases_array);
|
||||
|
@@ -454,37 +454,56 @@ static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id,
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_lib_id_make_local_generic_action_define(
|
||||
struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy)
|
||||
{
|
||||
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
|
||||
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
|
||||
BLI_assert(force_copy == false || force_copy != force_local);
|
||||
|
||||
if (force_local || force_copy) {
|
||||
/* Already set by caller code, nothing to do here. */
|
||||
*r_force_local = force_local;
|
||||
*r_force_copy = force_copy;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
||||
bool is_local = false, is_lib = false;
|
||||
|
||||
/* - no user (neither lib nor local): make local (happens e.g. with UI-used only data).
|
||||
* - only lib users: do nothing (unless force_local is set)
|
||||
* - only local users: make local
|
||||
* - mixed: make copy
|
||||
* In case we make a whole lib's content local,
|
||||
* we always want to localize, and we skip remapping (done later).
|
||||
*/
|
||||
|
||||
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
|
||||
if (!lib_local && !is_local && !is_lib) {
|
||||
force_local = true;
|
||||
}
|
||||
else if (lib_local || is_local) {
|
||||
if (!is_lib) {
|
||||
force_local = true;
|
||||
}
|
||||
else {
|
||||
force_copy = true;
|
||||
}
|
||||
}
|
||||
|
||||
*r_force_local = force_local;
|
||||
*r_force_copy = force_copy;
|
||||
}
|
||||
|
||||
void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
|
||||
{
|
||||
if (!ID_IS_LINKED(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
||||
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
|
||||
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
|
||||
BLI_assert(force_copy == false || force_copy != force_local);
|
||||
|
||||
bool is_local = false, is_lib = false;
|
||||
|
||||
/* - only lib users: do nothing (unless force_local is set)
|
||||
* - only local users: set flag
|
||||
* - mixed: make copy
|
||||
* In case we make a whole lib's content local,
|
||||
* we always want to localize, and we skip remapping (done later).
|
||||
*/
|
||||
|
||||
if (!force_copy && !force_local) {
|
||||
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
|
||||
if (lib_local || is_local) {
|
||||
if (!is_lib) {
|
||||
force_local = true;
|
||||
}
|
||||
else {
|
||||
force_copy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool force_local, force_copy;
|
||||
BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
|
||||
|
||||
if (force_local) {
|
||||
BKE_lib_id_clear_library_data(bmain, id, flags);
|
||||
@@ -516,6 +535,7 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
|
||||
}
|
||||
}
|
||||
|
||||
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
||||
if (!lib_local) {
|
||||
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
|
||||
}
|
||||
|
@@ -154,7 +154,10 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
|
||||
}
|
||||
|
||||
if (remap_editor_id_reference_cb) {
|
||||
remap_editor_id_reference_cb(id, NULL);
|
||||
struct IDRemapper *remapper = BKE_id_remapper_create();
|
||||
BKE_id_remapper_add(remapper, id, NULL);
|
||||
remap_editor_id_reference_cb(remapper);
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,32 +295,40 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
|
||||
* 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. */
|
||||
struct IDRemapper *remapper = BKE_id_remapper_create();
|
||||
for (i = 0; i < base_count; i++) {
|
||||
ListBase *lb = lbarray[i];
|
||||
ID *id, *id_next;
|
||||
BKE_id_remapper_clear(remapper);
|
||||
|
||||
for (id = lb->first; id; id = id_next) {
|
||||
id_next = id->next;
|
||||
/* NOTE: in case we delete a library, we also delete all its datablocks! */
|
||||
if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
|
||||
id->tag |= tag;
|
||||
|
||||
/* Will tag 'never NULL' users of this ID too.
|
||||
* Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
|
||||
* (and proxy!) 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));
|
||||
BKE_id_remapper_add(remapper, id, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (BKE_id_remapper_is_empty(remapper)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Will tag 'never NULL' users of this ID too.
|
||||
* Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
|
||||
* (and proxy!) 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,
|
||||
remapper,
|
||||
(ID_REMAP_FLAG_NEVER_NULL_USAGE |
|
||||
ID_REMAP_FORCE_NEVER_NULL_USAGE |
|
||||
ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
|
||||
}
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
|
||||
BKE_main_unlock(bmain);
|
||||
|
||||
/* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones,
|
||||
|
175
source/blender/blenkernel/intern/lib_id_remapper.cc
Normal file
175
source/blender/blenkernel/intern/lib_id_remapper.cc
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2022 by Blender Foundation.
|
||||
*/
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_remap.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_map.hh"
|
||||
|
||||
using IDTypeFilter = uint64_t;
|
||||
|
||||
namespace blender::bke::id::remapper {
|
||||
struct IDRemapper {
|
||||
private:
|
||||
Map<ID *, ID *> mappings;
|
||||
IDTypeFilter source_types = 0;
|
||||
|
||||
public:
|
||||
void clear()
|
||||
{
|
||||
mappings.clear();
|
||||
source_types = 0;
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
{
|
||||
return mappings.is_empty();
|
||||
}
|
||||
|
||||
void add(ID *old_id, ID *new_id)
|
||||
{
|
||||
BLI_assert(old_id != nullptr);
|
||||
BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
|
||||
mappings.add(old_id, new_id);
|
||||
source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
|
||||
}
|
||||
|
||||
bool contains_mappings_for_any(IDTypeFilter filter) const
|
||||
{
|
||||
return (source_types & filter) != 0;
|
||||
}
|
||||
|
||||
IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options) const
|
||||
{
|
||||
BLI_assert(r_id_ptr != nullptr);
|
||||
if (*r_id_ptr == nullptr) {
|
||||
return ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE;
|
||||
}
|
||||
|
||||
if (!mappings.contains(*r_id_ptr)) {
|
||||
return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
|
||||
id_us_min(*r_id_ptr);
|
||||
}
|
||||
|
||||
*r_id_ptr = mappings.lookup(*r_id_ptr);
|
||||
if (*r_id_ptr == nullptr) {
|
||||
return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
|
||||
}
|
||||
|
||||
if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
|
||||
id_us_plus(*r_id_ptr);
|
||||
}
|
||||
|
||||
if (options & ID_REMAP_APPLY_ENSURE_REAL) {
|
||||
id_us_ensure_real(*r_id_ptr);
|
||||
}
|
||||
return ID_REMAP_RESULT_SOURCE_REMAPPED;
|
||||
}
|
||||
|
||||
void iter(IDRemapperIterFunction func, void *user_data) const
|
||||
{
|
||||
for (auto item : mappings.items()) {
|
||||
func(item.key, item.value, user_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::bke::id::remapper
|
||||
|
||||
/** \brief wrap CPP IDRemapper to a C handle. */
|
||||
static IDRemapper *wrap(blender::bke::id::remapper::IDRemapper *remapper)
|
||||
{
|
||||
return static_cast<IDRemapper *>(static_cast<void *>(remapper));
|
||||
}
|
||||
|
||||
/** \brief wrap C handle to a CPP IDRemapper. */
|
||||
static blender::bke::id::remapper::IDRemapper *unwrap(IDRemapper *remapper)
|
||||
{
|
||||
return static_cast<blender::bke::id::remapper::IDRemapper *>(static_cast<void *>(remapper));
|
||||
}
|
||||
|
||||
/** \brief wrap C handle to a CPP IDRemapper. */
|
||||
static const blender::bke::id::remapper::IDRemapper *unwrap(const IDRemapper *remapper)
|
||||
{
|
||||
return static_cast<const blender::bke::id::remapper::IDRemapper *>(
|
||||
static_cast<const void *>(remapper));
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
IDRemapper *BKE_id_remapper_create(void)
|
||||
{
|
||||
blender::bke::id::remapper::IDRemapper *remapper =
|
||||
MEM_new<blender::bke::id::remapper::IDRemapper>(__func__);
|
||||
return wrap(remapper);
|
||||
}
|
||||
|
||||
void BKE_id_remapper_free(IDRemapper *id_remapper)
|
||||
{
|
||||
blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
|
||||
MEM_delete<blender::bke::id::remapper::IDRemapper>(remapper);
|
||||
}
|
||||
|
||||
void BKE_id_remapper_clear(struct IDRemapper *id_remapper)
|
||||
{
|
||||
blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
|
||||
remapper->clear();
|
||||
}
|
||||
|
||||
bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper)
|
||||
{
|
||||
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
|
||||
return remapper->is_empty();
|
||||
}
|
||||
|
||||
void BKE_id_remapper_add(IDRemapper *id_remapper, ID *old_id, ID *new_id)
|
||||
{
|
||||
blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
|
||||
remapper->add(old_id, new_id);
|
||||
}
|
||||
|
||||
bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter)
|
||||
{
|
||||
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
|
||||
return remapper->contains_mappings_for_any(type_filter);
|
||||
}
|
||||
|
||||
IDRemapperApplyResult BKE_id_remapper_apply(const IDRemapper *id_remapper,
|
||||
ID **r_id_ptr,
|
||||
const IDRemapperApplyOptions options)
|
||||
{
|
||||
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
|
||||
return remapper->apply(r_id_ptr, options);
|
||||
}
|
||||
|
||||
void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
|
||||
IDRemapperIterFunction func,
|
||||
void *user_data)
|
||||
{
|
||||
const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
|
||||
remapper->iter(func, user_data);
|
||||
}
|
||||
}
|
83
source/blender/blenkernel/intern/lib_id_remapper_test.cc
Normal file
83
source/blender/blenkernel/intern/lib_id_remapper_test.cc
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2022 by Blender Foundation.
|
||||
*/
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "BKE_lib_remap.h"
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
namespace blender::bke::id::remapper::tests {
|
||||
|
||||
TEST(lib_id_remapper, unavailable)
|
||||
{
|
||||
ID id1;
|
||||
ID *idp = &id1;
|
||||
|
||||
IDRemapper *remapper = BKE_id_remapper_create();
|
||||
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
|
||||
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNAVAILABLE);
|
||||
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
|
||||
TEST(lib_id_remapper, not_mappable)
|
||||
{
|
||||
ID *idp = nullptr;
|
||||
|
||||
IDRemapper *remapper = BKE_id_remapper_create();
|
||||
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
|
||||
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE);
|
||||
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
|
||||
TEST(lib_id_remapper, mapped)
|
||||
{
|
||||
ID id1;
|
||||
ID id2;
|
||||
ID *idp = &id1;
|
||||
BLI_strncpy(id1.name, "OB1", sizeof(id1.name));
|
||||
BLI_strncpy(id2.name, "OB2", sizeof(id2.name));
|
||||
|
||||
IDRemapper *remapper = BKE_id_remapper_create();
|
||||
BKE_id_remapper_add(remapper, &id1, &id2);
|
||||
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
|
||||
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_REMAPPED);
|
||||
EXPECT_EQ(idp, &id2);
|
||||
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
|
||||
TEST(lib_id_remapper, unassigned)
|
||||
{
|
||||
ID id1;
|
||||
ID *idp = &id1;
|
||||
|
||||
IDRemapper *remapper = BKE_id_remapper_create();
|
||||
BKE_id_remapper_add(remapper, &id1, nullptr);
|
||||
IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
|
||||
EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNASSIGNED);
|
||||
EXPECT_EQ(idp, nullptr);
|
||||
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::id::remapper::tests
|
@@ -1121,6 +1121,45 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor
|
||||
}
|
||||
}
|
||||
|
||||
static void lib_override_library_remap(Main *bmain,
|
||||
const ID *id_root_reference,
|
||||
GHash *linkedref_to_old_override)
|
||||
{
|
||||
ID *id;
|
||||
struct IDRemapper *remapper = BKE_id_remapper_create();
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
|
||||
if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
|
||||
ID *id_override_new = id->newid;
|
||||
ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
|
||||
if (id_override_old == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BKE_id_remapper_add(remapper, id_override_old, id_override_new);
|
||||
/* Remap no-main override IDs we just created too. */
|
||||
GHashIterator linkedref_to_old_override_iter;
|
||||
GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
|
||||
ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
|
||||
if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BKE_libblock_relink_ex(bmain,
|
||||
id_override_old_iter,
|
||||
id_override_old,
|
||||
id_override_new,
|
||||
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
|
||||
/* Remap all IDs to use the new override. */
|
||||
BKE_libblock_remap_multiple(bmain, remapper, 0);
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
|
||||
static bool lib_override_library_resync(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
@@ -1312,32 +1351,9 @@ static bool lib_override_library_resync(Main *bmain,
|
||||
}
|
||||
FOREACH_MAIN_LISTBASE_END;
|
||||
|
||||
/* We need to remap old to new override usages in a separate loop, after all new overrides have
|
||||
/* We remap old to new override usages in a separate loop, after all new overrides have
|
||||
* been added to Main. */
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
|
||||
ID *id_override_new = id->newid;
|
||||
ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
|
||||
|
||||
if (id_override_old != NULL) {
|
||||
/* Remap all IDs to use the new override. */
|
||||
BKE_libblock_remap(bmain, id_override_old, id_override_new, 0);
|
||||
/* Remap no-main override IDs we just created too. */
|
||||
GHashIterator linkedref_to_old_override_iter;
|
||||
GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
|
||||
ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
|
||||
if (id_override_old_iter->tag & LIB_TAG_NO_MAIN) {
|
||||
BKE_libblock_relink_ex(bmain,
|
||||
id_override_old_iter,
|
||||
id_override_old,
|
||||
id_override_new,
|
||||
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
lib_override_library_remap(bmain, id_root_reference, linkedref_to_old_override);
|
||||
|
||||
BKE_main_collection_sync(bmain);
|
||||
|
||||
|
@@ -510,11 +510,18 @@ static void libblock_remap_data(
|
||||
#endif
|
||||
}
|
||||
|
||||
void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
|
||||
typedef struct LibblockRemapMultipleUserData {
|
||||
Main *bmain;
|
||||
short remap_flags;
|
||||
} LibBlockRemapMultipleUserData;
|
||||
|
||||
static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_data)
|
||||
{
|
||||
LibBlockRemapMultipleUserData *data = user_data;
|
||||
Main *bmain = data->bmain;
|
||||
const short remap_flags = data->remap_flags;
|
||||
|
||||
IDRemap id_remap_data;
|
||||
ID *old_id = old_idv;
|
||||
ID *new_id = new_idv;
|
||||
int skipped_direct, skipped_refcounted;
|
||||
|
||||
BLI_assert(old_id != NULL);
|
||||
@@ -527,13 +534,6 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
|
||||
free_notifier_reference_cb(old_id);
|
||||
}
|
||||
|
||||
/* We assume editors do not hold references to their IDs... This is false in some cases
|
||||
* (Image is especially tricky here),
|
||||
* editors' code is to handle refcount (id->us) itself then. */
|
||||
if (remap_editor_id_reference_cb) {
|
||||
remap_editor_id_reference_cb(old_id, new_id);
|
||||
}
|
||||
|
||||
skipped_direct = id_remap_data.skipped_direct;
|
||||
skipped_refcounted = id_remap_data.skipped_refcounted;
|
||||
|
||||
@@ -606,6 +606,41 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
|
||||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
void BKE_libblock_remap_multiple_locked(Main *bmain,
|
||||
const struct IDRemapper *mappings,
|
||||
const short remap_flags)
|
||||
{
|
||||
if (BKE_id_remapper_is_empty(mappings)) {
|
||||
/* Early exit nothing to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
LibBlockRemapMultipleUserData user_data;
|
||||
user_data.bmain = bmain;
|
||||
user_data.remap_flags = remap_flags;
|
||||
BKE_id_remapper_iter(mappings, libblock_remap_foreach_idpair_cb, &user_data);
|
||||
|
||||
/* We assume editors do not hold references to their IDs... This is false in some cases
|
||||
* (Image is especially tricky here),
|
||||
* editors' code is to handle refcount (id->us) itself then. */
|
||||
if (remap_editor_id_reference_cb) {
|
||||
remap_editor_id_reference_cb(mappings);
|
||||
}
|
||||
|
||||
/* Full rebuild of DEG! */
|
||||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
|
||||
{
|
||||
struct IDRemapper *remapper = BKE_id_remapper_create();
|
||||
ID *old_id = old_idv;
|
||||
ID *new_id = new_idv;
|
||||
BKE_id_remapper_add(remapper, old_id, new_id);
|
||||
BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags);
|
||||
BKE_id_remapper_free(remapper);
|
||||
}
|
||||
|
||||
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
|
||||
{
|
||||
BKE_main_lock(bmain);
|
||||
@@ -615,6 +650,17 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
|
||||
BKE_main_unlock(bmain);
|
||||
}
|
||||
|
||||
void BKE_libblock_remap_multiple(Main *bmain,
|
||||
const struct IDRemapper *mappings,
|
||||
const short remap_flags)
|
||||
{
|
||||
BKE_main_lock(bmain);
|
||||
|
||||
BKE_libblock_remap_multiple_locked(bmain, mappings, remap_flags);
|
||||
|
||||
BKE_main_unlock(bmain);
|
||||
}
|
||||
|
||||
void BKE_libblock_unlink(Main *bmain,
|
||||
void *idv,
|
||||
const bool do_flag_never_null,
|
||||
|
@@ -304,7 +304,7 @@ TEST(lib_remap, never_null_usage_flag_not_requested_on_delete)
|
||||
EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
|
||||
EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
|
||||
|
||||
/* Never null usage isn't requested so the flag should not be set.*/
|
||||
/* Never null usage isn't requested so the flag should not be set. */
|
||||
BKE_libblock_remap(
|
||||
context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_SKIP_NEVER_NULL_USAGE);
|
||||
EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
|
||||
@@ -339,7 +339,7 @@ TEST(lib_remap, never_null_usage_flag_not_requested_on_remap)
|
||||
EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
|
||||
EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
|
||||
|
||||
/* Never null usage isn't requested so the flag should not be set.*/
|
||||
/* Never null usage isn't requested so the flag should not be set. */
|
||||
BKE_libblock_remap(
|
||||
context.test_data.bmain, context.test_data.mesh, other_mesh, ID_REMAP_SKIP_NEVER_NULL_USAGE);
|
||||
EXPECT_EQ(context.test_data.object->data, other_mesh);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user