Geometry Nodes: add simulation support #104924

Closed
Hans Goudey wants to merge 211 commits from geometry-nodes-simulation into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
140 changed files with 2680 additions and 1969 deletions
Showing only changes of commit ab8d77359b - Show all commits

View File

@ -26,13 +26,13 @@ set(SBOMCONTENTS)
get_cmake_property(_variableNames VARIABLES)
foreach (_variableName ${_variableNames})
if(_variableName MATCHES "CPE$")
string(REPLACE ":" ";" CPE_LIST ${${_variableName}})
string(REPLACE "_CPE" "_ID" CPE_DEPNAME ${_variableName})
list(GET CPE_LIST 3 CPE_VENDOR)
list(GET CPE_LIST 4 CPE_NAME)
list(GET CPE_LIST 5 CPE_VERSION)
set(${CPE_DEPNAME} "${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}")
set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION},,,\n")
string(REPLACE ":" ";" CPE_LIST ${${_variableName}})
string(REPLACE "_CPE" "_ID" CPE_DEPNAME ${_variableName})
list(GET CPE_LIST 3 CPE_VENDOR)
list(GET CPE_LIST 4 CPE_NAME)
list(GET CPE_LIST 5 CPE_VERSION)
set(${CPE_DEPNAME} "${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}")
set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION},,,\n")
endif()
endforeach()
configure_file(${CMAKE_SOURCE_DIR}/cmake/cve_check.csv.in ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv @ONLY)

View File

@ -32,12 +32,13 @@ function(download_source dep)
message("Checking source : ${dep} (${TARGET_FILE})")
if(NOT EXISTS ${TARGET_FILE})
message("Checking source : ${dep} - source not found downloading from ${TARGET_URI}")
file(DOWNLOAD ${TARGET_URI} ${TARGET_FILE}
TIMEOUT 1800 # seconds
EXPECTED_HASH ${TARGET_HASH_TYPE}=${TARGET_HASH}
TLS_VERIFY ON
SHOW_PROGRESS
)
file(
DOWNLOAD ${TARGET_URI} ${TARGET_FILE}
TIMEOUT 1800 # seconds
EXPECTED_HASH ${TARGET_HASH_TYPE}=${TARGET_HASH}
TLS_VERIFY ON
SHOW_PROGRESS
)
endif()
if(EXISTS ${TARGET_FILE})
# Sometimes the download fails, but that is not a

View File

@ -1,9 +1,55 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(FFMPEG_CFLAGS "-I${mingw_LIBDIR}/lame/include -I${mingw_LIBDIR}/openjpeg/include/ -I${mingw_LIBDIR}/ogg/include -I${mingw_LIBDIR}/vorbis/include -I${mingw_LIBDIR}/theora/include -I${mingw_LIBDIR}/opus/include -I${mingw_LIBDIR}/vpx/include -I${mingw_LIBDIR}/x264/include -I${mingw_LIBDIR}/xvidcore/include -I${mingw_LIBDIR}/zlib/include -I${mingw_LIBDIR}/aom/include")
set(FFMPEG_LDFLAGS "-L${mingw_LIBDIR}/lame/lib -L${mingw_LIBDIR}/openjpeg/lib -L${mingw_LIBDIR}/ogg/lib -L${mingw_LIBDIR}/vorbis/lib -L${mingw_LIBDIR}/theora/lib -L${mingw_LIBDIR}/opus/lib -L${mingw_LIBDIR}/vpx/lib -L${mingw_LIBDIR}/x264/lib -L${mingw_LIBDIR}/xvidcore/lib -L${mingw_LIBDIR}/zlib/lib -L${mingw_LIBDIR}/aom/lib")
set(FFMPEG_EXTRA_FLAGS --pkg-config-flags=--static --extra-cflags=${FFMPEG_CFLAGS} --extra-ldflags=${FFMPEG_LDFLAGS})
set(FFMPEG_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/x264/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR}:${mingw_LIBDIR}/vpx/lib/pkgconfig:${mingw_LIBDIR}/theora/lib/pkgconfig:${mingw_LIBDIR}/openjpeg/lib/pkgconfig:${mingw_LIBDIR}/opus/lib/pkgconfig:${mingw_LIBDIR}/aom/lib/pkgconfig:)
if(WIN32)
set(temp_LIBDIR ${mingw_LIBDIR})
else()
set(temp_LIBDIR ${LIBDIR})
endif()
set(FFMPEG_CFLAGS "\
-I${temp_LIBDIR}/lame/include \
-I${temp_LIBDIR}/openjpeg/include/ \
-I${temp_LIBDIR}/ogg/include \
-I${temp_LIBDIR}/vorbis/include \
-I${temp_LIBDIR}/theora/include \
-I${temp_LIBDIR}/opus/include \
-I${temp_LIBDIR}/vpx/include \
-I${temp_LIBDIR}/x264/include \
-I${temp_LIBDIR}/xvidcore/include \
-I${temp_LIBDIR}/zlib/include \
-I${temp_LIBDIR}/aom/include"
)
set(FFMPEG_LDFLAGS "\
-L${temp_LIBDIR}/lame/lib \
-L${temp_LIBDIR}/openjpeg/lib \
-L${temp_LIBDIR}/ogg/lib \
-L${temp_LIBDIR}/vorbis/lib \
-L${temp_LIBDIR}/theora/lib \
-L${temp_LIBDIR}/opus/lib \
-L${temp_LIBDIR}/vpx/lib \
-L${temp_LIBDIR}/x264/lib \
-L${temp_LIBDIR}/xvidcore/lib \
-L${temp_LIBDIR}/zlib/lib \
-L${temp_LIBDIR}/aom/lib"
)
set(FFMPEG_EXTRA_FLAGS
--pkg-config-flags=--static
--extra-cflags=${FFMPEG_CFLAGS}
--extra-ldflags=${FFMPEG_LDFLAGS}
)
set(FFMPEG_ENV "PKG_CONFIG_PATH=\
${temp_LIBDIR}/openjpeg/lib/pkgconfig:\
${temp_LIBDIR}/x264/lib/pkgconfig:\
${temp_LIBDIR}/vorbis/lib/pkgconfig:\
${temp_LIBDIR}/ogg/lib/pkgconfig:\
${temp_LIBDIR}/vpx/lib/pkgconfig:\
${temp_LIBDIR}/theora/lib/pkgconfig:\
${temp_LIBDIR}/openjpeg/lib/pkgconfig:\
${temp_LIBDIR}/opus/lib/pkgconfig:\
${temp_LIBDIR}/aom/lib/pkgconfig"
)
unset(temp_LIBDIR)
if(WIN32)
set(FFMPEG_ENV set ${FFMPEG_ENV} &&)

View File

@ -32,9 +32,10 @@ add_dependencies(
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
# harfbuzz *NEEDS* to find freetype.lib and will not be conviced to take alternative names so just give it
# what it wants.
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/freetype/lib/freetype2st.lib ${LIBDIR}/freetype/lib/freetype.lib
# harfbuzz *NEEDS* to find freetype.lib and will not be conviced to take alternative names so just give it
# what it wants.
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/freetype/lib/freetype2st.lib ${LIBDIR}/freetype/lib/freetype.lib
DEPENDEES install
)
endif()

View File

@ -40,19 +40,21 @@ endif()
if(BUILD_MODE STREQUAL Release AND WIN32)
ExternalProject_Add_Step(external_gmp after_install
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-3.dll.def ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def
COMMAND lib /def:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def /machine:x64 /out:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/gmp/bin/libgmp-10.dll ${HARVEST_TARGET}/gmp/lib/libgmp-10.dll
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib ${HARVEST_TARGET}/gmp/lib/libgmp-10.lib
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/gmp/include ${HARVEST_TARGET}/gmp/include
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-3.dll.def ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def
COMMAND lib /def:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def /machine:x64 /out:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/gmp/bin/libgmp-10.dll ${HARVEST_TARGET}/gmp/lib/libgmp-10.dll
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib ${HARVEST_TARGET}/gmp/lib/libgmp-10.lib
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/gmp/include ${HARVEST_TARGET}/gmp/include
DEPENDEES install
)
endif()
if(BUILD_MODE STREQUAL Debug AND WIN32)
ExternalProject_Add_Step(external_gmp after_install
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-3.dll.def ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def
COMMAND lib /def:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def /machine:x64 /out:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib
ExternalProject_Add_Step(external_gmp after_install
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-3.dll.def ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def
COMMAND lib /def:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def /machine:x64 /out:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib
DEPENDEES install
)
endif()

View File

@ -33,6 +33,7 @@ ExternalProject_Add(external_harfbuzz
add_dependencies(
external_harfbuzz
external_python
external_freetype
# Needed for `MESON`.
external_python_site_packages
)

View File

@ -14,14 +14,14 @@ if(WIN32)
if(BUILD_MODE STREQUAL Release)
add_custom_target(Harvest_Release_Results
COMMAND # jpeg rename libfile + copy include
${CMAKE_COMMAND} -E copy ${LIBDIR}/jpeg/lib/jpeg-static.lib ${HARVEST_TARGET}/jpeg/lib/libjpeg.lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/jpeg/include/ ${HARVEST_TARGET}/jpeg/include/ &&
# png
${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_static.lib ${HARVEST_TARGET}/png/lib/libpng.lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/png/include/ ${HARVEST_TARGET}/png/include/ &&
# freeglut-> opengl
${CMAKE_COMMAND} -E copy ${LIBDIR}/freeglut/lib/freeglut_static.lib ${HARVEST_TARGET}/opengl/lib/freeglut_static.lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/freeglut/include/ ${HARVEST_TARGET}/opengl/include/ &&
${CMAKE_COMMAND} -E copy ${LIBDIR}/jpeg/lib/jpeg-static.lib ${HARVEST_TARGET}/jpeg/lib/libjpeg.lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/jpeg/include/ ${HARVEST_TARGET}/jpeg/include/ &&
# png
${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_static.lib ${HARVEST_TARGET}/png/lib/libpng.lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/png/include/ ${HARVEST_TARGET}/png/include/ &&
# freeglut-> opengl
${CMAKE_COMMAND} -E copy ${LIBDIR}/freeglut/lib/freeglut_static.lib ${HARVEST_TARGET}/opengl/lib/freeglut_static.lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/freeglut/include/ ${HARVEST_TARGET}/opengl/include/ &&
DEPENDS
)
endif()

View File

@ -34,21 +34,21 @@ elseif(UNIX)
endif()
set(ISPC_EXTRA_ARGS
-DISPC_NO_DUMPS=On
-DISPC_INCLUDE_EXAMPLES=Off
-DISPC_INCLUDE_TESTS=Off
-DLLVM_ROOT=${LIBDIR}/llvm/lib/cmake/llvm
-DLLVM_LIBRARY_DIR=${LIBDIR}/llvm/lib
-DCLANG_EXECUTABLE=${LIBDIR}/llvm/bin/clang
-DCLANGPP_EXECUTABLE=${LIBDIR}/llvm/bin/clang++
-DISPC_INCLUDE_TESTS=Off
-DCLANG_LIBRARY_DIR=${LIBDIR}/llvm/lib
-DCLANG_INCLUDE_DIRS=${LIBDIR}/llvm/include
-DPython3_ROOT_DIR=${LIBDIR}/python/
-DPython3_EXECUTABLE=${PYTHON_BINARY}
${ISPC_EXTRA_ARGS_WIN}
${ISPC_EXTRA_ARGS_APPLE}
${ISPC_EXTRA_ARGS_UNIX}
-DISPC_NO_DUMPS=On
-DISPC_INCLUDE_EXAMPLES=Off
-DISPC_INCLUDE_TESTS=Off
-DLLVM_ROOT=${LIBDIR}/llvm/lib/cmake/llvm
-DLLVM_LIBRARY_DIR=${LIBDIR}/llvm/lib
-DCLANG_EXECUTABLE=${LIBDIR}/llvm/bin/clang
-DCLANGPP_EXECUTABLE=${LIBDIR}/llvm/bin/clang++
-DISPC_INCLUDE_TESTS=Off
-DCLANG_LIBRARY_DIR=${LIBDIR}/llvm/lib
-DCLANG_INCLUDE_DIRS=${LIBDIR}/llvm/include
-DPython3_ROOT_DIR=${LIBDIR}/python/
-DPython3_EXECUTABLE=${PYTHON_BINARY}
${ISPC_EXTRA_ARGS_WIN}
${ISPC_EXTRA_ARGS_APPLE}
${ISPC_EXTRA_ARGS_UNIX}
)
ExternalProject_Add(external_ispc

View File

@ -105,10 +105,10 @@ if(WIN32)
)
endif()
else()
ExternalProject_Add_Step(external_opencolorio after_install
COMMAND cp ${LIBDIR}/yamlcpp/lib/libyaml-cpp.a ${LIBDIR}/opencolorio/lib/
COMMAND cp ${LIBDIR}/expat/lib/libexpat.a ${LIBDIR}/opencolorio/lib/
COMMAND cp ${LIBDIR}/pystring/lib/libpystring.a ${LIBDIR}/opencolorio/lib/
DEPENDEES install
)
ExternalProject_Add_Step(external_opencolorio after_install
COMMAND cp ${LIBDIR}/yamlcpp/lib/libyaml-cpp.a ${LIBDIR}/opencolorio/lib/
COMMAND cp ${LIBDIR}/expat/lib/libexpat.a ${LIBDIR}/opencolorio/lib/
COMMAND cp ${LIBDIR}/pystring/lib/libpystring.a ${LIBDIR}/opencolorio/lib/
DEPENDEES install
)
endif()

View File

@ -39,8 +39,10 @@ if(MSVC)
)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_openjpeg_msvc after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openjpeg_msvc/lib ${HARVEST_TARGET}/openjpeg/lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openjpeg_msvc/include ${HARVEST_TARGET}/openjpeg/include
COMMAND
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openjpeg_msvc/lib ${HARVEST_TARGET}/openjpeg/lib &&
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openjpeg_msvc/include ${HARVEST_TARGET}/openjpeg/include
DEPENDEES install
)
endif()

View File

@ -4,10 +4,10 @@
# library itself does not depend on them, so should give no problems.
set(OPENPGL_EXTRA_ARGS
-DOPENPGL_BUILD_STATIC=ON
-DOPENPGL_TBB_ROOT=${LIBDIR}/tbb
-DTBB_ROOT=${LIBDIR}/tbb
-DCMAKE_DEBUG_POSTFIX=_d
-DOPENPGL_BUILD_STATIC=ON
-DOPENPGL_TBB_ROOT=${LIBDIR}/tbb
-DTBB_ROOT=${LIBDIR}/tbb
-DCMAKE_DEBUG_POSTFIX=_d
)
if(TBB_STATIC_LIBRARY)
@ -18,17 +18,17 @@ if(TBB_STATIC_LIBRARY)
endif()
ExternalProject_Add(external_openpgl
URL file://${PACKAGE_DIR}/${OPENPGL_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${OPENPGL_HASH_TYPE}=${OPENPGL_HASH}
PREFIX ${BUILD_DIR}/openpgl
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openpgl ${DEFAULT_CMAKE_FLAGS} ${OPENPGL_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/openpgl
URL file://${PACKAGE_DIR}/${OPENPGL_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${OPENPGL_HASH_TYPE}=${OPENPGL_HASH}
PREFIX ${BUILD_DIR}/openpgl
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openpgl ${DEFAULT_CMAKE_FLAGS} ${OPENPGL_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/openpgl
)
add_dependencies(
external_openpgl
external_tbb
external_openpgl
external_tbb
)
if(WIN32)

View File

@ -15,8 +15,8 @@ if((WIN32 AND BUILD_MODE STREQUAL Release) OR UNIX)
)
if(WIN32)
ExternalProject_Add_Step(external_potrace after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/potrace ${HARVEST_TARGET}/potrace
DEPENDEES install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/potrace ${HARVEST_TARGET}/potrace
DEPENDEES install
)
endif()
endif()

View File

@ -2,37 +2,36 @@
if(WIN32)
if(MSVC14) # vs2015 has timespec
set(PTHREAD_CPPFLAGS "/I. /DHAVE_CONFIG_H /D_TIMESPEC_DEFINED ")
else() # everything before doesn't
set(PTHREAD_CPPFLAGS "/I. /DHAVE_CONFIG_H ")
endif()
if(MSVC14) # vs2015 has timespec
set(PTHREAD_CPPFLAGS "/I. /DHAVE_CONFIG_H /D_TIMESPEC_DEFINED ")
else() # everything before doesn't
set(PTHREAD_CPPFLAGS "/I. /DHAVE_CONFIG_H ")
endif()
set(PTHREADS_BUILD cd ${BUILD_DIR}/pthreads/src/external_pthreads/ && cd && nmake VC-static /e CPPFLAGS=${PTHREAD_CPPFLAGS})
set(PTHREADS_BUILD cd ${BUILD_DIR}/pthreads/src/external_pthreads/ && cd && nmake VC-static /e CPPFLAGS=${PTHREAD_CPPFLAGS})
ExternalProject_Add(external_pthreads
URL file://${PACKAGE_DIR}/${PTHREADS_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${PTHREADS_HASH_TYPE}=${PTHREADS_HASH}
PREFIX ${BUILD_DIR}/pthreads
CONFIGURE_COMMAND echo .
PATCH_COMMAND COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/pthreads/src/external_pthreads < ${PATCH_DIR}/pthreads.diff
BUILD_COMMAND ${PTHREADS_BUILD}
INSTALL_COMMAND COMMAND
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/libpthreadVC3${LIBEXT} ${LIBDIR}/pthreads/lib/pthreadVC3${LIBEXT} &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/pthread.h ${LIBDIR}/pthreads/inc/pthread.h &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/sched.h ${LIBDIR}/pthreads/inc/sched.h &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/semaphore.h ${LIBDIR}/pthreads/inc/semaphore.h &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/_ptw32.h ${LIBDIR}/pthreads/inc/_ptw32.h
INSTALL_DIR ${LIBDIR}/pthreads
ExternalProject_Add(external_pthreads
URL file://${PACKAGE_DIR}/${PTHREADS_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${PTHREADS_HASH_TYPE}=${PTHREADS_HASH}
PREFIX ${BUILD_DIR}/pthreads
CONFIGURE_COMMAND echo .
PATCH_COMMAND COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/pthreads/src/external_pthreads < ${PATCH_DIR}/pthreads.diff
BUILD_COMMAND ${PTHREADS_BUILD}
INSTALL_COMMAND COMMAND
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/libpthreadVC3${LIBEXT} ${LIBDIR}/pthreads/lib/pthreadVC3${LIBEXT} &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/pthread.h ${LIBDIR}/pthreads/inc/pthread.h &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/sched.h ${LIBDIR}/pthreads/inc/sched.h &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/semaphore.h ${LIBDIR}/pthreads/inc/semaphore.h &&
${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/_ptw32.h ${LIBDIR}/pthreads/inc/_ptw32.h
INSTALL_DIR ${LIBDIR}/pthreads
)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_pthreads after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/inc/ ${HARVEST_TARGET}/pthreads/include/
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/lib/ ${HARVEST_TARGET}/pthreads/lib
DEPENDEES install
)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_pthreads after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/inc/ ${HARVEST_TARGET}/pthreads/include/
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/lib/ ${HARVEST_TARGET}/pthreads/lib
DEPENDEES install
)
endif()
endif()
endif()

View File

@ -52,10 +52,10 @@ endif()
if(BUILD_MODE STREQUAL Release AND WIN32)
ExternalProject_Add_Step(external_sndfile after_install
COMMAND lib /def:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.def /machine:x64 /out:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/bin/libsndfile-1.dll ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.dll
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/include/sndfile.h ${HARVEST_TARGET}/sndfile/include/sndfile.h
COMMAND lib /def:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.def /machine:x64 /out:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/bin/libsndfile-1.dll ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.dll
COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/include/sndfile.h ${HARVEST_TARGET}/sndfile/include/sndfile.h
DEPENDEES install
)

View File

@ -5,7 +5,20 @@ ExternalProject_Add(external_spnav
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${SPNAV_HASH_TYPE}=${SPNAV_HASH}
PREFIX ${BUILD_DIR}/spnav
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/spnav/src/external_spnav/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/spnav --disable-shared --enable-static --with-pic
CONFIGURE_COMMAND
${CONFIGURE_ENV} &&
cd ${BUILD_DIR}/spnav/src/external_spnav/ &&
${CONFIGURE_COMMAND}
--prefix=${LIBDIR}/spnav
# X11 is not needed as Blender polls the device as part of the GHOST event loop.
# This is used to support `3dxserv`, however this is no longer supported by 3DCONNEXION.
# Disable so building without X11 is supported (WAYLAND only).
--disable-x11
--disable-shared
--enable-static
--with-pic
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/spnav/src/external_spnav/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/spnav/src/external_spnav/ && make install
INSTALL_DIR ${LIBDIR}/spnav

View File

@ -195,9 +195,12 @@ set(TIFF_HASH_TYPE MD5)
set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz)
set(TIFF_CPE "cpe:2.3:a:libtiff:libtiff:${TIFF_VERSION}:*:*:*:*:*:*:*")
set(OSL_VERSION 1.12.7.1)
set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/v${OSL_VERSION}.tar.gz)
set(OSL_HASH 53211da86c34ba6e0344998c1a6d219c)
# Recent commit from 1.13.0.2 under development, which includes string table
# changes that make the Cycles OptiX implementation work. Official 1.12 OSL
# releases should also build but without OptiX support.
set(OSL_VERSION 1a7670600c8b08c2443a78d03c8c27e9a1149140)
set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/${OSL_VERSION}.tar.gz)
set(OSL_HASH 7b6d6716b05d1addb92a8f47280bf77f)
set(OSL_HASH_TYPE MD5)
set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz)
@ -232,11 +235,11 @@ set(OPENVDB_FILE openvdb-${OPENVDB_VERSION}.tar.gz)
# ------------------------------------------------------------------------------
# Python Modules
# Needed by: TODO.
# Needed by: `requests` module (so the version doesn't change on rebuild).
set(IDNA_VERSION 3.3)
# Needed by: TODO.
# Needed by: `requests` module (so the version doesn't change on rebuild).
set(CHARSET_NORMALIZER_VERSION 2.0.10)
# Needed by: TODO.
# Needed by: `requests` module (so the version doesn't change on rebuild).
set(URLLIB3_VERSION 1.26.8)
set(URLLIB3_CPE "cpe:2.3:a:urllib3:urllib3:${URLLIB3_VERSION}:*:*:*:*:*:*:*")
# Needed by: Python's `requests` module (so add-ons can authenticate against trusted certificates).
@ -366,9 +369,9 @@ set(WEBP_HASH_TYPE MD5)
set(WEBP_FILE libwebp-${WEBP_VERSION}.tar.gz)
set(WEBP_CPE "cpe:2.3:a:webmproject:libwebp:${WEBP_VERSION}:*:*:*:*:*:*:*")
set(SPNAV_VERSION 0.2.3)
set(SPNAV_URI http://downloads.sourceforge.net/project/spacenav/spacenav%20library%20%28SDK%29/libspnav%20${SPNAV_VERSION}/libspnav-${SPNAV_VERSION}.tar.gz)
set(SPNAV_HASH 44d840540d53326d4a119c0f1aa7bf0a)
set(SPNAV_VERSION 1.1)
set(SPNAV_URI https://github.com/FreeSpacenav/libspnav/releases/download/v${SPNAV_VERSION}/libspnav-${SPNAV_VERSION}.tar.gz)
set(SPNAV_HASH 7c0032034672dfba3c4bb9b49a440e70)
set(SPNAV_HASH_TYPE MD5)
set(SPNAV_FILE libspnav-${SPNAV_VERSION}.tar.gz)

View File

@ -10,7 +10,8 @@ if(WIN32)
set(YAMLCPP_EXTRA_ARGS
${YAMLCPP_EXTRA_ARGS}
-DBUILD_GMOCK=OFF
-DYAML_MSVC_SHARED_RT=ON)
-DYAML_MSVC_SHARED_RT=ON
)
endif()
ExternalProject_Add(external_yamlcpp

View File

@ -11,19 +11,25 @@ if [ `id -u` -ne 0 ]; then
exit 1
fi
# Packages `ninja-build` and `meson` are not available unless CBR or PowerTools repositories are enabled.
# See: https://wiki.rockylinux.org/rocky/repo/#notes-on-unlisted-repositories
dnf config-manager --set-enabled powertools
# yum-config-manager does not come in the default minimal install,
# so make sure it is installed and available.
yum -y update
yum -y install yum-utils
# Install all the packages needed for a new toolchain.
# Install all the packages needed for a new tool-chain.
#
# NOTE: Keep this separate from the packages install, since otherwise
# older toolchain will be installed.
# older tool-chain will be installed.
yum -y update
yum -y install epel-release
yum -y install centos-release-scl
yum -y install devtoolset-9
yum -y install scl-utils
yum -y install scl-utils-build
# Currently this is defined by the VFX platform (CY2023), see: https://vfxplatform.com
yum -y install gcc-toolset-11
# Install packages needed for Blender's dependencies.
PACKAGES_FOR_LIBS=(
@ -47,19 +53,12 @@ PACKAGES_FOR_LIBS=(
automake
libtool
# Meta-build system used by various packages.
meson
# TODO: why is this needed?
patchelf
# Builds generated by meson use Ninja for the actual build.
ninja-build
# Required by Blender build option: `WITH_GHOST_X11`.
libXrandr-devel
libXinerama-devel
libXcursor-devel
libXi-devel
libX11-devel
libXt-devel
# Required by Blender build option: `WITH_GHOST_WAYLAND`.
mesa-libEGL-devel
# Required by: Blender & `external_opensubdiv` (probably others).
@ -79,52 +78,45 @@ PACKAGES_FOR_LIBS=(
# Why are both needed?
yasm
# Required by: `meson` (Python based build system).
python36
# Required by: `mako` (Python module used for building `external_mesa`)
python-setuptools
# NOTE(@campbellbarton): while `python39` is available, the default Python version is 3.6.
# This is used for the `python3-mako` package for e.g.
# So use the "default" system Python since it means it's most compatible with other packages.
python3
# Required by: `mesa`.
expat-devel
# Required by: `external_igc` & `external_osl` as a build-time dependency.
bison
# Required by: `external_osl` as a build-time dependency.
flex
# TODO: dependencies build without this, consider removal.
# Required by: `external_ispc`.
ncurses-devel
# Required by: `external_ispc` (when building with CLANG).
libstdc++-static
)
# Additional packages needed for building Blender.
PACKAGES_FOR_BLENDER=(
# Required by Blender build option: `WITH_GHOST_WAYLAND`.
libxkbcommon-devel
# Required by Blender build option: `WITH_GHOST_X11`.
libX11-devel
libXcursor-devel
libXi-devel
libXinerama-devel
libXrandr-devel
libXt-devel
libXxf86vm-devel
)
yum -y install -y ${PACKAGES_FOR_LIBS[@]} ${PACKAGES_FOR_BLENDER[@]}
# Dependencies for Mesa
yum -y install expat-devel
python3 -m pip install mako
# Dependencies for pip (needed for buildbot-worker).
yum -y install python36-pip python36-devel
# Dependencies for pip (needed for buildbot-worker), uses Python3.6.
yum -y install python3 python3-pip python3-devel
# Dependencies for asound.
yum -y install -y \
alsa-lib-devel pulseaudio-libs-devel
alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake 10 \
--slave /usr/local/bin/ctest ctest /usr/bin/ctest \
--slave /usr/local/bin/cpack cpack /usr/bin/cpack \
--slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake \
--family cmake
alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake3 20 \
--slave /usr/local/bin/ctest ctest /usr/bin/ctest3 \
--slave /usr/local/bin/cpack cpack /usr/bin/cpack3 \
--slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake3 \
--family cmake
alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake3 20 \
--slave /usr/local/bin/ctest ctest /usr/bin/ctest3 \
--slave /usr/local/bin/cpack cpack /usr/bin/cpack3 \
--slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake3 \
--family cmake

View File

@ -82,8 +82,8 @@ enum_use_layer_samples = (
)
enum_sampling_pattern = (
('SOBOL', "Sobol-Burley", "Use Sobol-Burley random sampling pattern", 0),
('PROGRESSIVE_MULTI_JITTER', "Progressive Multi-Jitter", "Use Progressive Multi-Jitter random sampling pattern", 1),
('SOBOL_BURLEY', "Sobol-Burley", "Use on-the-fly computed Owen-scrambled Sobol for random sampling", 0),
('TABULATED_SOBOL', "Tabulated Sobol", "Use precomputed tables of Owen-scrambled Sobol for random sampling", 1),
)
enum_emission_sampling = (
@ -412,9 +412,9 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
sampling_pattern: EnumProperty(
name="Sampling Pattern",
description="Random sampling pattern used by the integrator. When adaptive sampling is enabled, Progressive Multi-Jitter is always used instead of Sobol-Burley",
description="Random sampling pattern used by the integrator",
items=enum_sampling_pattern,
default='PROGRESSIVE_MULTI_JITTER',
default='TABULATED_SOBOL',
)
scrambling_distance: FloatProperty(

View File

@ -364,16 +364,13 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
row.prop(cscene, "seed")
row.prop(cscene, "use_animated_seed", text="", icon='TIME')
col = layout.column(align=True)
col.prop(cscene, "sampling_pattern", text="Pattern")
col = layout.column(align=True)
col.prop(cscene, "sample_offset")
layout.separator()
heading = layout.column(align=True, heading="Scrambling Distance")
heading.active = cscene.sampling_pattern != 'SOBOL'
heading.active = cscene.sampling_pattern != 'TABULATED_SOBOL'
heading.prop(cscene, "auto_scrambling_distance", text="Automatic")
heading.prop(cscene, "preview_scrambling_distance", text="Viewport")
heading.prop(cscene, "scrambling_distance", text="Multiplier")
@ -396,11 +393,22 @@ class CYCLES_RENDER_PT_sampling_lights(CyclesButtonsPanel, Panel):
bl_parent_id = "CYCLES_RENDER_PT_sampling"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
def draw(self, context):
layout = self.layout
scene = context.scene
cscene = scene.cycles
col.prop(cscene, "use_light_tree")
sub = col.row()
sub.prop(cscene, "light_sampling_threshold", text="Light Threshold")
sub.active = not cscene.use_light_tree
class CYCLES_RENDER_PT_sampling_debug(CyclesDebugButtonsPanel, Panel):
bl_label = "Debug"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@ -410,10 +418,7 @@ class CYCLES_RENDER_PT_sampling_lights(CyclesButtonsPanel, Panel):
cscene = scene.cycles
col = layout.column(align=True)
col.prop(cscene, "use_light_tree")
sub = col.row()
sub.prop(cscene, "light_sampling_threshold", text="Light Threshold")
sub.active = not cscene.use_light_tree
col.prop(cscene, "sampling_pattern", text="Pattern")
class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel):
@ -2391,6 +2396,7 @@ classes = (
CYCLES_RENDER_PT_sampling_path_guiding_debug,
CYCLES_RENDER_PT_sampling_lights,
CYCLES_RENDER_PT_sampling_advanced,
CYCLES_RENDER_PT_sampling_debug,
CYCLES_RENDER_PT_light_paths,
CYCLES_RENDER_PT_light_paths_max_bounces,
CYCLES_RENDER_PT_light_paths_clamping,

View File

@ -228,7 +228,7 @@ def do_versions(self):
cscene.use_preview_denoising = False
if not cscene.is_property_set("sampling_pattern") or \
cscene.get('sampling_pattern') >= 2:
cscene.sampling_pattern = 'PROGRESSIVE_MULTI_JITTER'
cscene.sampling_pattern = 'TABULATED_SOBOL'
# Removal of square samples.
cscene = scene.cycles
@ -241,6 +241,12 @@ def do_versions(self):
layer.samples *= layer.samples
cscene["use_square_samples"] = False
# Disable light tree for existing scenes.
if version <= (3, 5, 3):
cscene = scene.cycles
if not cscene.is_property_set("use_light_tree"):
cscene.use_light_tree = False
# Lamps
for light in bpy.data.lights:
if light.library not in libraries:

View File

@ -57,7 +57,6 @@ int BlenderDisplayShader::get_tex_coord_attrib_location()
/* TODO move shaders to standalone .glsl file. */
static const char *FALLBACK_VERTEX_SHADER =
"#version 330\n"
"uniform vec2 fullscreen;\n"
"in vec2 texCoord;\n"
"in vec2 pos;\n"
@ -75,7 +74,6 @@ static const char *FALLBACK_VERTEX_SHADER =
"}\n\0";
static const char *FALLBACK_FRAGMENT_SHADER =
"#version 330\n"
"uniform sampler2D image_texture;\n"
"in vec2 texCoord_interp;\n"
"out vec4 fragColor;\n"

View File

@ -367,13 +367,11 @@ static void attr_create_generic(Scene *scene,
{
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
static const ustring u_velocity("velocity");
int attribute_index = 0;
int render_color_index = b_mesh.attributes.render_color_index();
const ustring default_color_name{b_mesh.attributes.default_color_name().c_str()};
for (BL::Attribute &b_attribute : b_mesh.attributes) {
const ustring name{b_attribute.name().c_str()};
const bool is_render_color = (attribute_index++ == render_color_index);
const bool is_render_color = name == default_color_name;
if (need_motion && name == u_velocity) {
attr_create_motion(mesh, b_attribute, motion_scale);

View File

@ -357,7 +357,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
}
SamplingPattern sampling_pattern = (SamplingPattern)get_enum(
cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_PMJ);
cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_TABULATED_SOBOL);
integrator->set_sampling_pattern(sampling_pattern);
int samples = 1;

View File

@ -113,6 +113,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) {
if (mesh.use_auto_smooth()) {
mesh.calc_normals_split();
mesh.split_faces(false);
}

View File

@ -952,6 +952,9 @@ void CUDADevice::tex_alloc(device_texture &mem)
case EXTENSION_CLIP:
address_mode = CU_TR_ADDRESS_MODE_BORDER;
break;
case EXTENSION_MIRROR:
address_mode = CU_TR_ADDRESS_MODE_MIRROR;
break;
default:
assert(0);
break;

View File

@ -909,6 +909,9 @@ void HIPDevice::tex_alloc(device_texture &mem)
* because it's unsupported in HIP. */
address_mode = hipAddressModeClamp;
break;
case EXTENSION_MIRROR:
address_mode = hipAddressModeMirror;
break;
default:
assert(0);
break;

View File

@ -856,7 +856,7 @@ void MetalDevice::tex_alloc(device_texture &mem)
/* sampler_index maps into the GPU's constant 'metal_samplers' array */
uint64_t sampler_index = mem.info.extension;
if (mem.info.interpolation != INTERPOLATION_CLOSEST) {
sampler_index += 3;
sampler_index += 4;
}
/* Image Texture Storage */

View File

@ -299,12 +299,12 @@ set(SRC_KERNEL_LIGHT_HEADERS
)
set(SRC_KERNEL_SAMPLE_HEADERS
sample/jitter.h
sample/lcg.h
sample/mapping.h
sample/mis.h
sample/pattern.h
sample/sobol_burley.h
sample/tabulated_sobol.h
sample/util.h
)

View File

@ -77,7 +77,7 @@ KERNEL_DATA_ARRAY(KernelShader, shaders)
/* lookup tables */
KERNEL_DATA_ARRAY(float, lookup_table)
/* PMJ sample pattern */
/* tabulated Sobol sample pattern */
KERNEL_DATA_ARRAY(float, sample_pattern_lut)
/* image textures */

View File

@ -179,7 +179,8 @@ KERNEL_STRUCT_MEMBER(integrator, float, sample_clamp_indirect)
KERNEL_STRUCT_MEMBER(integrator, int, use_caustics)
/* Sampling pattern. */
KERNEL_STRUCT_MEMBER(integrator, int, sampling_pattern)
KERNEL_STRUCT_MEMBER(integrator, int, pmj_sequence_size)
KERNEL_STRUCT_MEMBER(integrator, int, tabulated_sobol_sequence_size)
KERNEL_STRUCT_MEMBER(integrator, int, sobol_index_mask)
KERNEL_STRUCT_MEMBER(integrator, float, scrambling_distance)
/* Volume render. */
KERNEL_STRUCT_MEMBER(integrator, int, use_volumes)
@ -204,7 +205,6 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_mis_weights)
/* Padding. */
KERNEL_STRUCT_MEMBER(integrator, int, pad1)
KERNEL_STRUCT_MEMBER(integrator, int, pad2)
KERNEL_STRUCT_END(KernelIntegrator)
/* SVM. For shader specialization. */

View File

@ -202,6 +202,14 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
return clamp(x, 0, width - 1);
}
static ccl_always_inline int wrap_mirror(int x, int width)
{
const int m = abs(x + (x < 0)) % (2 * width);
if (m >= width)
return 2 * width - m - 1;
return m;
}
/* ******** 2D interpolation ******** */
static ccl_always_inline OutT interp_closest(const TextureInfo &info, float x, float y)
@ -226,6 +234,10 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
case EXTENSION_MIRROR:
ix = wrap_mirror(ix, width);
iy = wrap_mirror(iy, height);
break;
default:
kernel_assert(0);
return zero();
@ -268,6 +280,12 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
niy = wrap_clamp(iy + 1, height);
iy = wrap_clamp(iy, height);
break;
case EXTENSION_MIRROR:
nix = wrap_mirror(ix + 1, width);
ix = wrap_mirror(ix, width);
niy = wrap_mirror(iy + 1, height);
iy = wrap_mirror(iy, height);
break;
default:
kernel_assert(0);
return zero();
@ -331,6 +349,17 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
nniy = wrap_clamp(iy + 2, height);
iy = wrap_clamp(iy, height);
break;
case EXTENSION_MIRROR:
pix = wrap_mirror(ix - 1, width);
nix = wrap_mirror(ix + 1, width);
nnix = wrap_mirror(ix + 2, width);
ix = wrap_mirror(ix, width);
piy = wrap_mirror(iy - 1, height);
niy = wrap_mirror(iy + 1, height);
nniy = wrap_mirror(iy + 2, height);
iy = wrap_mirror(iy, height);
break;
default:
kernel_assert(0);
return zero();
@ -403,6 +432,11 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
iy = wrap_clamp(iy, height);
iz = wrap_clamp(iz, depth);
break;
case EXTENSION_MIRROR:
ix = wrap_mirror(ix, width);
iy = wrap_mirror(iy, height);
iz = wrap_mirror(iz, depth);
break;
default:
kernel_assert(0);
return zero();
@ -480,6 +514,16 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
niz = wrap_clamp(iz + 1, depth);
iz = wrap_clamp(iz, depth);
break;
case EXTENSION_MIRROR:
nix = wrap_mirror(ix + 1, width);
ix = wrap_mirror(ix, width);
niy = wrap_mirror(iy + 1, height);
iy = wrap_mirror(iy, height);
niz = wrap_mirror(iz + 1, depth);
iz = wrap_mirror(iz, depth);
break;
default:
kernel_assert(0);
return zero();
@ -595,6 +639,22 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
nniz = wrap_clamp(iz + 2, depth);
iz = wrap_clamp(iz, depth);
break;
case EXTENSION_MIRROR:
pix = wrap_mirror(ix - 1, width);
nix = wrap_mirror(ix + 1, width);
nnix = wrap_mirror(ix + 2, width);
ix = wrap_mirror(ix, width);
piy = wrap_mirror(iy - 1, height);
niy = wrap_mirror(iy + 1, height);
nniy = wrap_mirror(iy + 2, height);
iy = wrap_mirror(iy, height);
piz = wrap_mirror(iz - 1, depth);
niz = wrap_mirror(iz + 1, depth);
nniz = wrap_mirror(iz + 2, depth);
iz = wrap_mirror(iz, depth);
break;
default:
kernel_assert(0);
return zero();

View File

@ -301,10 +301,12 @@ enum SamplerType {
SamplerFilterNearest_AddressRepeat,
SamplerFilterNearest_AddressClampEdge,
SamplerFilterNearest_AddressClampZero,
SamplerFilterNearest_AddressMirroredRepeat,
SamplerFilterLinear_AddressRepeat,
SamplerFilterLinear_AddressClampEdge,
SamplerFilterLinear_AddressClampZero,
SamplerFilterLinear_AddressMirroredRepeat,
SamplerCount
};
@ -313,7 +315,9 @@ constant constexpr array<sampler, SamplerCount> metal_samplers = {
sampler(address::repeat, filter::nearest),
sampler(address::clamp_to_edge, filter::nearest),
sampler(address::clamp_to_zero, filter::nearest),
sampler(address::mirrored_repeat, filter::nearest),
sampler(address::repeat, filter::linear),
sampler(address::clamp_to_edge, filter::linear),
sampler(address::clamp_to_zero, filter::linear),
sampler(address::mirrored_repeat, filter::linear),
};

View File

@ -47,9 +47,11 @@ class MetalKernelContext {
case 0: return texture_array[tid].tex.sample(sampler(address::repeat, filter::nearest), coords);
case 1: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::nearest), coords);
case 2: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::nearest), coords);
case 3: return texture_array[tid].tex.sample(sampler(address::repeat, filter::linear), coords);
case 4: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::linear), coords);
case 5: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::linear), coords);
case 3: return texture_array[tid].tex.sample(sampler(address::mirrored_repeat, filter::nearest), coords);
case 4: return texture_array[tid].tex.sample(sampler(address::repeat, filter::linear), coords);
case 5: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::linear), coords);
case 6: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::linear), coords);
case 7: return texture_array[tid].tex.sample(sampler(address::mirrored_repeat, filter::linear), coords);
}
}
#endif

View File

@ -24,6 +24,14 @@ ccl_device_inline int svm_image_texture_wrap_clamp(int x, int width)
return clamp(x, 0, width - 1);
}
ccl_device_inline int svm_image_texture_wrap_mirror(int x, int width)
{
const int m = abs(x + (x < 0)) % (2 * width);
if (m >= width)
return 2 * width - m - 1;
return m;
}
ccl_device_inline float4 svm_image_texture_read(const TextureInfo &info, int x, int y, int z)
{
const int data_offset = x + info.width * y + info.width * info.height * z;
@ -85,6 +93,10 @@ ccl_device_inline float4 svm_image_texture_read_2d(int id, int x, int y)
x = svm_image_texture_wrap_clamp(x, info.width);
y = svm_image_texture_wrap_clamp(y, info.height);
}
else if (info.extension == EXTENSION_MIRROR) {
x = svm_image_texture_wrap_mirror(x, info.width);
y = svm_image_texture_wrap_mirror(y, info.height);
}
else {
if (x < 0 || x >= info.width || y < 0 || y >= info.height) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@ -109,6 +121,11 @@ ccl_device_inline float4 svm_image_texture_read_3d(int id, int x, int y, int z)
y = svm_image_texture_wrap_clamp(y, info.height);
z = svm_image_texture_wrap_clamp(z, info.depth);
}
else if (info.extension == EXTENSION_MIRROR) {
x = svm_image_texture_wrap_mirror(x, info.width);
y = svm_image_texture_wrap_mirror(y, info.height);
z = svm_image_texture_wrap_mirror(z, info.depth);
}
else {
if (x < 0 || x >= info.width || y < 0 || y >= info.height || z < 0 || z >= info.depth) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -26,18 +26,22 @@ ccl_device_inline void integrate_camera_sample(KernelGlobals kg,
const float2 rand_filter = (sample == 0) ? make_float2(0.5f, 0.5f) :
path_rng_2D(kg, rng_hash, sample, PRNG_FILTER);
/* Depth of field sampling. */
const float2 rand_lens = (kernel_data.cam.aperturesize > 0.0f) ?
path_rng_2D(kg, rng_hash, sample, PRNG_LENS) :
zero_float2();
/* Motion blur time sampling. */
const float rand_time = (kernel_data.cam.shuttertime != -1.0f) ?
path_rng_1D(kg, rng_hash, sample, PRNG_TIME) :
0.0f;
/* Motion blur (time) and depth of field (lens) sampling. (time, lens_x, lens_y) */
const float3 rand_time_lens = (kernel_data.cam.shuttertime != -1.0f ||
kernel_data.cam.aperturesize > 0.0f) ?
path_rng_3D(kg, rng_hash, sample, PRNG_LENS_TIME) :
zero_float3();
/* Generate camera ray. */
camera_sample(kg, x, y, rand_filter.x, rand_filter.y, rand_lens.x, rand_lens.y, rand_time, ray);
camera_sample(kg,
x,
y,
rand_filter.x,
rand_filter.y,
rand_time_lens.y,
rand_time_lens.z,
rand_time_lens.x,
ray);
}
/* Return false to indicate that this pixel is finished.

View File

@ -336,6 +336,14 @@ ccl_device_inline float2 path_state_rng_2D(KernelGlobals kg,
kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension);
}
ccl_device_inline float3 path_state_rng_3D(KernelGlobals kg,
ccl_private const RNGState *rng_state,
const int dimension)
{
return path_rng_3D(
kg, rng_state->rng_hash, rng_state->sample, rng_state->rng_offset + dimension);
}
ccl_device_inline float path_branched_rng_1D(KernelGlobals kg,
ccl_private const RNGState *rng_state,
const int branch,
@ -360,6 +368,18 @@ ccl_device_inline float2 path_branched_rng_2D(KernelGlobals kg,
rng_state->rng_offset + dimension);
}
ccl_device_inline float3 path_branched_rng_3D(KernelGlobals kg,
ccl_private const RNGState *rng_state,
const int branch,
const int num_branches,
const int dimension)
{
return path_rng_3D(kg,
rng_state->rng_hash,
rng_state->sample * num_branches + branch,
rng_state->rng_offset + dimension);
}
/* Utility functions to get light termination value,
* since it might not be needed in many cases.
*/

View File

@ -147,10 +147,11 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
{
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
const float2 rand_light = path_state_rng_2D(kg, rng_state, PRNG_LIGHT);
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
if (!light_sample_from_position(kg,
rng_state,
rand_light.z,
rand_light.x,
rand_light.y,
sd->time,

View File

@ -702,10 +702,11 @@ ccl_device_forceinline bool integrate_volume_equiangular_sample_light(
/* Sample position on a light. */
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
const float2 rand_light = path_state_rng_2D(kg, rng_state, PRNG_LIGHT);
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
LightSample ls ccl_optional_struct_init;
if (!light_sample_from_volume_segment(kg,
rand_light.z,
rand_light.x,
rand_light.y,
sd->time,
@ -765,10 +766,11 @@ ccl_device_forceinline void integrate_volume_direct_light(
{
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
const float2 rand_light = path_state_rng_2D(kg, rng_state, PRNG_LIGHT);
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
if (!light_sample_from_position(kg,
rng_state,
rand_light.z,
rand_light.x,
rand_light.y,
sd->time,

View File

@ -11,7 +11,7 @@ CCL_NAMESPACE_BEGIN
/* Simple CDF based sampling over all lights in the scene, without taking into
* account shading position or normal. */
ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu)
ccl_device int light_distribution_sample(KernelGlobals kg, const float randn)
{
/* This is basically std::upper_bound as used by PBRT, to find a point light or
* triangle to emit from, proportional to area. a good improvement would be to
@ -19,7 +19,7 @@ ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *ra
* arbitrary shaders. */
int first = 0;
int len = kernel_data.integrator.num_distribution + 1;
float r = *randu;
float r = randn;
do {
int half_len = len >> 1;
@ -38,18 +38,13 @@ ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *ra
* make this fail on rare occasions. */
int index = clamp(first - 1, 0, kernel_data.integrator.num_distribution - 1);
/* Rescale to reuse random number. this helps the 2D samples within
* each area light be stratified as well. */
float distr_min = kernel_data_fetch(light_distribution, index).totarea;
float distr_max = kernel_data_fetch(light_distribution, index + 1).totarea;
*randu = (r - distr_min) / (distr_max - distr_min);
return index;
}
template<bool in_volume_segment>
ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
float randu,
const float randn,
const float randu,
const float randv,
const float time,
const float3 P,
@ -58,7 +53,7 @@ ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
ccl_private LightSample *ls)
{
/* Sample light index from distribution. */
const int index = light_distribution_sample(kg, &randu);
const int index = light_distribution_sample(kg, randn);
const float pdf_selection = kernel_data.integrator.distribution_pdf_lights;
return light_sample<in_volume_segment>(
kg, randu, randv, time, P, bounce, path_flag, index, pdf_selection, ls);

View File

@ -324,7 +324,8 @@ ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg,
* Uses either a flat distribution or light tree. */
ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg,
float randu,
const float randn,
const float randu,
const float randv,
const float time,
const float3 P,
@ -337,17 +338,19 @@ ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg,
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
return light_tree_sample<true>(
kg, randu, randv, time, P, D, t, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls);
kg, randn, randu, randv, time, P, D, t, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls);
}
else
#endif
{
return light_distribution_sample<true>(kg, randu, randv, time, P, bounce, path_flag, ls);
return light_distribution_sample<true>(
kg, randn, randu, randv, time, P, bounce, path_flag, ls);
}
}
ccl_device bool light_sample_from_position(KernelGlobals kg,
ccl_private const RNGState *rng_state,
const float randn,
const float randu,
const float randv,
const float time,
@ -361,12 +364,13 @@ ccl_device bool light_sample_from_position(KernelGlobals kg,
#ifdef __LIGHT_TREE__
if (kernel_data.integrator.use_light_tree) {
return light_tree_sample<false>(
kg, randu, randv, time, P, N, 0, shader_flags, bounce, path_flag, ls);
kg, randn, randu, randv, time, P, N, 0, shader_flags, bounce, path_flag, ls);
}
else
#endif
{
return light_distribution_sample<false>(kg, randu, randv, time, P, bounce, path_flag, ls);
return light_distribution_sample<false>(
kg, randn, randu, randv, time, P, bounce, path_flag, ls);
}
}

View File

@ -551,8 +551,9 @@ ccl_device bool get_left_probability(KernelGlobals kg,
template<bool in_volume_segment>
ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
float randu,
float randv,
float randn,
const float randu,
const float randv,
const float time,
const float3 P,
const float3 N_or_D,
@ -580,7 +581,7 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
if (knode->child_index <= 0) {
/* At a leaf node, we pick an emitter. */
selected_emitter = light_tree_cluster_select_emitter<in_volume_segment>(
kg, randv, P, N_or_D, t, has_transmission, knode, &pdf_selection);
kg, randn, P, N_or_D, t, has_transmission, knode, &pdf_selection);
break;
}
@ -598,7 +599,7 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
float discard;
float total_prob = left_prob;
node_index = left_index;
sample_resevoir(right_index, 1.0f - left_prob, node_index, discard, total_prob, randu);
sample_resevoir(right_index, 1.0f - left_prob, node_index, discard, total_prob, randn);
pdf_leaf *= (node_index == left_index) ? left_prob : (1.0f - left_prob);
}

View File

@ -14,111 +14,111 @@
namespace DeviceStrings {
/* "" */
ccl_device_constant DeviceString _emptystring_ = {0ull};
ccl_device_constant DeviceString _emptystring_ = 0ull;
/* "common" */
ccl_device_constant DeviceString u_common = {14645198576927606093ull};
ccl_device_constant DeviceString u_common = 14645198576927606093ull;
/* "world" */
ccl_device_constant DeviceString u_world = {16436542438370751598ull};
ccl_device_constant DeviceString u_world = 16436542438370751598ull;
/* "shader" */
ccl_device_constant DeviceString u_shader = {4279676006089868ull};
ccl_device_constant DeviceString u_shader = 4279676006089868ull;
/* "object" */
ccl_device_constant DeviceString u_object = {973692718279674627ull};
ccl_device_constant DeviceString u_object = 973692718279674627ull;
/* "NDC" */
ccl_device_constant DeviceString u_ndc = {5148305047403260775ull};
ccl_device_constant DeviceString u_ndc = 5148305047403260775ull;
/* "screen" */
ccl_device_constant DeviceString u_screen = {14159088609039777114ull};
ccl_device_constant DeviceString u_screen = 14159088609039777114ull;
/* "camera" */
ccl_device_constant DeviceString u_camera = {2159505832145726196ull};
ccl_device_constant DeviceString u_camera = 2159505832145726196ull;
/* "raster" */
ccl_device_constant DeviceString u_raster = {7759263238610201778ull};
ccl_device_constant DeviceString u_raster = 7759263238610201778ull;
/* "hsv" */
ccl_device_constant DeviceString u_hsv = {2177035556331879497ull};
ccl_device_constant DeviceString u_hsv = 2177035556331879497ull;
/* "hsl" */
ccl_device_constant DeviceString u_hsl = {7749766809258288148ull};
ccl_device_constant DeviceString u_hsl = 7749766809258288148ull;
/* "XYZ" */
ccl_device_constant DeviceString u_xyz = {4957977063494975483ull};
ccl_device_constant DeviceString u_xyz = 4957977063494975483ull;
/* "xyY" */
ccl_device_constant DeviceString u_xyy = {5138822319725660255ull};
ccl_device_constant DeviceString u_xyy = 5138822319725660255ull;
/* "sRGB" */
ccl_device_constant DeviceString u_srgb = {15368599878474175032ull};
ccl_device_constant DeviceString u_srgb = 15368599878474175032ull;
/* "object:location" */
ccl_device_constant DeviceString u_object_location = {7846190347358762897ull};
ccl_device_constant DeviceString u_object_location = 7846190347358762897ull;
/* "object:color" */
ccl_device_constant DeviceString u_object_color = {12695623857059169556ull};
ccl_device_constant DeviceString u_object_color = 12695623857059169556ull;
/* "object:alpha" */
ccl_device_constant DeviceString u_object_alpha = {11165053919428293151ull};
ccl_device_constant DeviceString u_object_alpha = 11165053919428293151ull;
/* "object:index" */
ccl_device_constant DeviceString u_object_index = {6588325838217472556ull};
ccl_device_constant DeviceString u_object_index = 6588325838217472556ull;
/* "geom:dupli_generated" */
ccl_device_constant DeviceString u_geom_dupli_generated = {6715607178003388908ull};
ccl_device_constant DeviceString u_geom_dupli_generated = 6715607178003388908ull;
/* "geom:dupli_uv" */
ccl_device_constant DeviceString u_geom_dupli_uv = {1294253317490155849ull};
ccl_device_constant DeviceString u_geom_dupli_uv = 1294253317490155849ull;
/* "material:index" */
ccl_device_constant DeviceString u_material_index = {741770758159634623ull};
ccl_device_constant DeviceString u_material_index = 741770758159634623ull;
/* "object:random" */
ccl_device_constant DeviceString u_object_random = {15789063994977955884ull};
ccl_device_constant DeviceString u_object_random = 15789063994977955884ull;
/* "particle:index" */
ccl_device_constant DeviceString u_particle_index = {9489711748229903784ull};
ccl_device_constant DeviceString u_particle_index = 9489711748229903784ull;
/* "particle:random" */
ccl_device_constant DeviceString u_particle_random = {17993722202766855761ull};
ccl_device_constant DeviceString u_particle_random = 17993722202766855761ull;
/* "particle:age" */
ccl_device_constant DeviceString u_particle_age = {7380730644710951109ull};
ccl_device_constant DeviceString u_particle_age = 7380730644710951109ull;
/* "particle:lifetime" */
ccl_device_constant DeviceString u_particle_lifetime = {16576828923156200061ull};
ccl_device_constant DeviceString u_particle_lifetime = 16576828923156200061ull;
/* "particle:location" */
ccl_device_constant DeviceString u_particle_location = {10309536211423573010ull};
ccl_device_constant DeviceString u_particle_location = 10309536211423573010ull;
/* "particle:rotation" */
ccl_device_constant DeviceString u_particle_rotation = {17858543768041168459ull};
ccl_device_constant DeviceString u_particle_rotation = 17858543768041168459ull;
/* "particle:size" */
ccl_device_constant DeviceString u_particle_size = {16461524249715420389ull};
ccl_device_constant DeviceString u_particle_size = 16461524249715420389ull;
/* "particle:velocity" */
ccl_device_constant DeviceString u_particle_velocity = {13199101248768308863ull};
ccl_device_constant DeviceString u_particle_velocity = 13199101248768308863ull;
/* "particle:angular_velocity" */
ccl_device_constant DeviceString u_particle_angular_velocity = {16327930120486517910ull};
ccl_device_constant DeviceString u_particle_angular_velocity = 16327930120486517910ull;
/* "geom:numpolyvertices" */
ccl_device_constant DeviceString u_geom_numpolyvertices = {382043551489988826ull};
ccl_device_constant DeviceString u_geom_numpolyvertices = 382043551489988826ull;
/* "geom:trianglevertices" */
ccl_device_constant DeviceString u_geom_trianglevertices = {17839267571524187074ull};
ccl_device_constant DeviceString u_geom_trianglevertices = 17839267571524187074ull;
/* "geom:polyvertices" */
ccl_device_constant DeviceString u_geom_polyvertices = {1345577201967881769ull};
ccl_device_constant DeviceString u_geom_polyvertices = 1345577201967881769ull;
/* "geom:name" */
ccl_device_constant DeviceString u_geom_name = {13606338128269760050ull};
ccl_device_constant DeviceString u_geom_name = 13606338128269760050ull;
/* "geom:undisplaced" */
ccl_device_constant DeviceString u_geom_undisplaced = {12431586303019276305ull};
ccl_device_constant DeviceString u_geom_undisplaced = 12431586303019276305ull;
/* "geom:is_smooth" */
ccl_device_constant DeviceString u_is_smooth = {857544214094480123ull};
ccl_device_constant DeviceString u_is_smooth = 857544214094480123ull;
/* "geom:is_curve" */
ccl_device_constant DeviceString u_is_curve = {129742495633653138ull};
ccl_device_constant DeviceString u_is_curve = 129742495633653138ull;
/* "geom:curve_thickness" */
ccl_device_constant DeviceString u_curve_thickness = {10605802038397633852ull};
ccl_device_constant DeviceString u_curve_thickness = 10605802038397633852ull;
/* "geom:curve_length" */
ccl_device_constant DeviceString u_curve_length = {11423459517663715453ull};
ccl_device_constant DeviceString u_curve_length = 11423459517663715453ull;
/* "geom:curve_tangent_normal" */
ccl_device_constant DeviceString u_curve_tangent_normal = {12301397394034985633ull};
ccl_device_constant DeviceString u_curve_tangent_normal = 12301397394034985633ull;
/* "geom:curve_random" */
ccl_device_constant DeviceString u_curve_random = {15293085049960492358ull};
ccl_device_constant DeviceString u_curve_random = 15293085049960492358ull;
/* "geom:is_point" */
ccl_device_constant DeviceString u_is_point = {2511357849436175953ull};
ccl_device_constant DeviceString u_is_point = 2511357849436175953ull;
/* "geom:point_radius" */
ccl_device_constant DeviceString u_point_radius = {9956381140398668479ull};
ccl_device_constant DeviceString u_point_radius = 9956381140398668479ull;
/* "geom:point_position" */
ccl_device_constant DeviceString u_point_position = {15684484280742966916ull};
ccl_device_constant DeviceString u_point_position = 15684484280742966916ull;
/* "geom:point_random" */
ccl_device_constant DeviceString u_point_random = {5632627207092325544ull};
ccl_device_constant DeviceString u_point_random = 5632627207092325544ull;
/* "geom:normal_map_normal" */
ccl_device_constant DeviceString u_normal_map_normal = {10718948685686827073};
ccl_device_constant DeviceString u_normal_map_normal = 10718948685686827073;
/* "path:ray_length" */
ccl_device_constant DeviceString u_path_ray_length = {16391985802412544524ull};
ccl_device_constant DeviceString u_path_ray_length = 16391985802412544524ull;
/* "path:ray_depth" */
ccl_device_constant DeviceString u_path_ray_depth = {16643933224879500399ull};
ccl_device_constant DeviceString u_path_ray_depth = 16643933224879500399ull;
/* "path:diffuse_depth" */
ccl_device_constant DeviceString u_path_diffuse_depth = {13191651286699118408ull};
ccl_device_constant DeviceString u_path_diffuse_depth = 13191651286699118408ull;
/* "path:glossy_depth" */
ccl_device_constant DeviceString u_path_glossy_depth = {15717768399057252940ull};
ccl_device_constant DeviceString u_path_glossy_depth = 15717768399057252940ull;
/* "path:transparent_depth" */
ccl_device_constant DeviceString u_path_transparent_depth = {7821650266475578543ull};
ccl_device_constant DeviceString u_path_transparent_depth = 7821650266475578543ull;
/* "path:transmission_depth" */
ccl_device_constant DeviceString u_path_transmission_depth = {15113408892323917624ull};
ccl_device_constant DeviceString u_path_transmission_depth = 15113408892323917624ull;
} // namespace DeviceStrings
@ -1275,9 +1275,7 @@ ccl_device_extern bool osl_get_attribute(ccl_private ShaderGlobals *sg,
object = sd->object;
}
const uint64_t id = name.hash();
const AttributeDescriptor desc = find_attribute(kg, object, sd->prim, sd->type, id);
const AttributeDescriptor desc = find_attribute(kg, object, sd->prim, sd->type, name);
if (desc.offset != ATTR_STD_NOT_FOUND) {
return get_object_attribute(kg, sd, desc, type, derivatives, res);
}

View File

@ -5,47 +5,26 @@
CCL_NAMESPACE_BEGIN
struct DeviceString {
#if defined(__KERNEL_GPU__)
/* Strings are represented by their hashes in CUDA and OptiX. */
size_t str_;
ccl_device_inline_method uint64_t hash() const
{
return str_;
}
/* Strings are represented by their hashes on the GPU. */
typedef size_t DeviceString;
#elif defined(OPENIMAGEIO_USTRING_H)
ustring str_;
ccl_device_inline_method uint64_t hash() const
{
return str_.hash();
}
typedef ustring DeviceString;
#else
const char *str_;
typedef const char *DeviceString;
#endif
ccl_device_inline_method bool operator==(DeviceString b) const
{
return str_ == b.str_;
}
ccl_device_inline_method bool operator!=(DeviceString b) const
{
return str_ != b.str_;
}
};
ccl_device_inline DeviceString make_string(const char *str, size_t hash)
{
#if defined(__KERNEL_GPU__)
(void)str;
return {hash};
return hash;
#elif defined(OPENIMAGEIO_USTRING_H)
(void)hash;
return {ustring(str)};
return ustring(str);
#else
(void)hash;
return {str};
return str;
#endif
}

View File

@ -1,90 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "kernel/sample/util.h"
#include "util/hash.h"
#pragma once
CCL_NAMESPACE_BEGIN
ccl_device uint pmj_shuffled_sample_index(KernelGlobals kg, uint sample, uint dimension, uint seed)
{
const uint sample_count = kernel_data.integrator.pmj_sequence_size;
/* Shuffle the pattern order and sample index to better decorrelate
* dimensions and make the most of the finite patterns we have.
* The funky sample mask stuff is to ensure that we only shuffle
* *within* the current sample pattern, which is necessary to avoid
* early repeat pattern use. */
const uint pattern_i = hash_shuffle_uint(dimension, NUM_PMJ_PATTERNS, seed);
/* sample_count should always be a power of two, so this results in a mask. */
const uint sample_mask = sample_count - 1;
const uint sample_shuffled = nested_uniform_scramble(sample,
hash_wang_seeded_uint(dimension, seed));
sample = (sample & ~sample_mask) | (sample_shuffled & sample_mask);
return ((pattern_i * sample_count) + sample) % (sample_count * NUM_PMJ_PATTERNS);
}
ccl_device float pmj_sample_1D(KernelGlobals kg,
uint sample,
const uint rng_hash,
const uint dimension)
{
uint seed = rng_hash;
/* Use the same sample sequence seed for all pixels when using
* scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
seed = kernel_data.integrator.seed;
}
/* Fetch the sample. */
const uint index = pmj_shuffled_sample_index(kg, sample, dimension, seed);
float x = kernel_data_fetch(sample_pattern_lut, index * NUM_PMJ_DIMENSIONS);
/* Do limited Cranley-Patterson rotation when using scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
const float jitter_x = hash_wang_seeded_float(dimension, rng_hash) *
kernel_data.integrator.scrambling_distance;
x += jitter_x;
x -= floorf(x);
}
return x;
}
ccl_device float2 pmj_sample_2D(KernelGlobals kg,
uint sample,
const uint rng_hash,
const uint dimension)
{
uint seed = rng_hash;
/* Use the same sample sequence seed for all pixels when using
* scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
seed = kernel_data.integrator.seed;
}
/* Fetch the sample. */
const uint index = pmj_shuffled_sample_index(kg, sample, dimension, seed);
float x = kernel_data_fetch(sample_pattern_lut, index * NUM_PMJ_DIMENSIONS);
float y = kernel_data_fetch(sample_pattern_lut, index * NUM_PMJ_DIMENSIONS + 1);
/* Do limited Cranley-Patterson rotation when using scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
const float jitter_x = hash_wang_seeded_float(dimension, rng_hash) *
kernel_data.integrator.scrambling_distance;
const float jitter_y = hash_wang_seeded_float(dimension, rng_hash ^ 0xca0e1151) *
kernel_data.integrator.scrambling_distance;
x += jitter_x;
y += jitter_y;
x -= floorf(x);
y -= floorf(y);
}
return make_float2(x, y);
}
CCL_NAMESPACE_END

View File

@ -3,8 +3,8 @@
#pragma once
#include "kernel/sample/jitter.h"
#include "kernel/sample/sobol_burley.h"
#include "kernel/sample/tabulated_sobol.h"
#include "util/hash.h"
CCL_NAMESPACE_BEGIN
@ -23,10 +23,11 @@ ccl_device_forceinline float path_rng_1D(KernelGlobals kg,
#endif
if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_SOBOL_BURLEY) {
return sobol_burley_sample_1D(sample, dimension, rng_hash);
const uint index_mask = kernel_data.integrator.sobol_index_mask;
return sobol_burley_sample_1D(sample, dimension, rng_hash, index_mask);
}
else {
return pmj_sample_1D(kg, sample, rng_hash, dimension);
return tabulated_sobol_sample_1D(kg, sample, rng_hash, dimension);
}
}
@ -40,10 +41,47 @@ ccl_device_forceinline float2 path_rng_2D(KernelGlobals kg,
#endif
if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_SOBOL_BURLEY) {
return sobol_burley_sample_2D(sample, dimension, rng_hash);
const uint index_mask = kernel_data.integrator.sobol_index_mask;
return sobol_burley_sample_2D(sample, dimension, rng_hash, index_mask);
}
else {
return pmj_sample_2D(kg, sample, rng_hash, dimension);
return tabulated_sobol_sample_2D(kg, sample, rng_hash, dimension);
}
}
ccl_device_forceinline float3 path_rng_3D(KernelGlobals kg,
uint rng_hash,
int sample,
int dimension)
{
#ifdef __DEBUG_CORRELATION__
return make_float3((float)drand48(), (float)drand48(), (float)drand48());
#endif
if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_SOBOL_BURLEY) {
const uint index_mask = kernel_data.integrator.sobol_index_mask;
return sobol_burley_sample_3D(sample, dimension, rng_hash, index_mask);
}
else {
return tabulated_sobol_sample_3D(kg, sample, rng_hash, dimension);
}
}
ccl_device_forceinline float4 path_rng_4D(KernelGlobals kg,
uint rng_hash,
int sample,
int dimension)
{
#ifdef __DEBUG_CORRELATION__
return make_float4((float)drand48(), (float)drand48(), (float)drand48(), (float)drand48());
#endif
if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_SOBOL_BURLEY) {
const uint index_mask = kernel_data.integrator.sobol_index_mask;
return sobol_burley_sample_4D(sample, dimension, rng_hash, index_mask);
}
else {
return tabulated_sobol_sample_4D(kg, sample, rng_hash, dimension);
}
}
@ -97,7 +135,7 @@ ccl_device_inline uint path_rng_hash_init(KernelGlobals kg,
ccl_device_inline bool sample_is_class_A(int pattern, int sample)
{
#if 0
if (!(pattern == SAMPLING_PATTERN_PMJ || pattern == SAMPLING_PATTERN_SOBOL_BURLEY)) {
if (!(pattern == SAMPLING_PATTERN_TABULATED_SOBOL || pattern == SAMPLING_PATTERN_SOBOL_BURLEY)) {
/* Fallback: assign samples randomly.
* This is guaranteed to work "okay" for any sampler, but isn't good.
* (NOTE: the seed constant is just a random number to guard against
@ -114,8 +152,8 @@ ccl_device_inline bool sample_is_class_A(int pattern, int sample)
* Multi-Jittered Sample Sequences" by Christensen et al., but
* implemented with efficient bit-fiddling.
*
* This approach also turns out to work equally well with Sobol-Burley
* (see https://developer.blender.org/D15746#429471).
* This approach also turns out to work equally well with Owen
* scrambled and shuffled Sobol (see https://developer.blender.org/D15746#429471).
*/
return popcount(uint(sample) & 0xaaaaaaaa) & 1;
}

View File

@ -65,31 +65,75 @@ ccl_device_forceinline float sobol_burley(uint rev_bit_index,
}
/*
* Computes a 1D Owen-scrambled and shuffled Sobol sample.
* NOTE: the functions below intentionally produce samples that are
* uncorrelated between functions. For example, a 1D sample and 2D
* sample produced with the same index, dimension, and seed are
* uncorrelated with each other. This allows more care-free usage
* of the functions together, without having to worry about
* e.g. 1D and 2D samples being accidentally correlated with each
* other.
*/
ccl_device float sobol_burley_sample_1D(uint index, uint const dimension, uint seed)
/*
* Computes a 1D Owen-scrambled and shuffled Sobol sample.
*
* `index` is the index of the sample in the sequence.
*
* `dimension` is which dimensions of the sample you want to fetch. Note
* that different 1D dimensions are uncorrelated. For samples with > 1D
* stratification, use the multi-dimensional sampling methods below.
*
* `seed`: different seeds produce statistically independent,
* uncorrelated sequences.
*
* `shuffled_index_mask` limits the sample sequence length, improving
* performance. It must be a string of binary 1 bits followed by a
* string of binary 0 bits (e.g. 0xffff0000) for the sampler to operate
* correctly. In general, `reverse_integer_bits(shuffled_index_mask)`
* should be >= the maximum number of samples expected to be taken. A safe
* default (but least performant) is 0xffffffff, for maximum sequence
* length.
*/
ccl_device float sobol_burley_sample_1D(uint index,
uint const dimension,
uint seed,
uint shuffled_index_mask)
{
/* Include the dimension in the seed, so we get decorrelated
* sequences for different dimensions via shuffling. */
seed ^= hash_hp_uint(dimension);
/* Shuffle. */
/* Shuffle and mask. The masking is just for better
* performance at low sample counts. */
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xbff95bfe);
index &= shuffled_index_mask;
return sobol_burley(index, 0, seed ^ 0x635c77bd);
}
/*
* Computes a 2D Owen-scrambled and shuffled Sobol sample.
*
* `dimension_set` is which two dimensions of the sample you want to
* fetch. For example, 0 is the first two, 1 is the second two, etc.
* The dimensions within a single set are stratified, but different sets
* are uncorrelated.
*
* See sobol_burley_sample_1D for further usage details.
*/
ccl_device float2 sobol_burley_sample_2D(uint index, const uint dimension_set, uint seed)
ccl_device float2 sobol_burley_sample_2D(uint index,
const uint dimension_set,
uint seed,
uint shuffled_index_mask)
{
/* Include the dimension set in the seed, so we get decorrelated
* sequences for different dimension sets via shuffling. */
seed ^= hash_hp_uint(dimension_set);
/* Shuffle. */
/* Shuffle and mask. The masking is just for better
* performance at low sample counts. */
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xf8ade99a);
index &= shuffled_index_mask;
return make_float2(sobol_burley(index, 0, seed ^ 0xe0aaaf76),
sobol_burley(index, 1, seed ^ 0x94964d4e));
@ -97,15 +141,27 @@ ccl_device float2 sobol_burley_sample_2D(uint index, const uint dimension_set, u
/*
* Computes a 3D Owen-scrambled and shuffled Sobol sample.
*
* `dimension_set` is which three dimensions of the sample you want to
* fetch. For example, 0 is the first three, 1 is the second three, etc.
* The dimensions within a single set are stratified, but different sets
* are uncorrelated.
*
* See sobol_burley_sample_1D for further usage details.
*/
ccl_device float3 sobol_burley_sample_3D(uint index, const uint dimension_set, uint seed)
ccl_device float3 sobol_burley_sample_3D(uint index,
const uint dimension_set,
uint seed,
uint shuffled_index_mask)
{
/* Include the dimension set in the seed, so we get decorrelated
* sequences for different dimension sets via shuffling. */
seed ^= hash_hp_uint(dimension_set);
/* Shuffle. */
/* Shuffle and mask. The masking is just for better
* performance at low sample counts. */
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xcaa726ac);
index &= shuffled_index_mask;
return make_float3(sobol_burley(index, 0, seed ^ 0x9e78e391),
sobol_burley(index, 1, seed ^ 0x67c33241),
@ -114,15 +170,27 @@ ccl_device float3 sobol_burley_sample_3D(uint index, const uint dimension_set, u
/*
* Computes a 4D Owen-scrambled and shuffled Sobol sample.
*
* `dimension_set` is which four dimensions of the sample you want to
* fetch. For example, 0 is the first four, 1 is the second four, etc.
* The dimensions within a single set are stratified, but different sets
* are uncorrelated.
*
* See sobol_burley_sample_1D for further usage details.
*/
ccl_device float4 sobol_burley_sample_4D(uint index, const uint dimension_set, uint seed)
ccl_device float4 sobol_burley_sample_4D(uint index,
const uint dimension_set,
uint seed,
uint shuffled_index_mask)
{
/* Include the dimension set in the seed, so we get decorrelated
* sequences for different dimension sets via shuffling. */
seed ^= hash_hp_uint(dimension_set);
/* Shuffle. */
/* Shuffle and mask. The masking is just for better
* performance at low sample counts. */
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xc2c1a055);
index &= shuffled_index_mask;
return make_float4(sobol_burley(index, 0, seed ^ 0x39468210),
sobol_burley(index, 1, seed ^ 0xe9d8a845),

View File

@ -0,0 +1,174 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "kernel/sample/util.h"
#include "util/hash.h"
#pragma once
CCL_NAMESPACE_BEGIN
ccl_device uint tabulated_sobol_shuffled_sample_index(KernelGlobals kg,
uint sample,
uint dimension,
uint seed)
{
const uint sample_count = kernel_data.integrator.tabulated_sobol_sequence_size;
/* Shuffle the pattern order and sample index to decorrelate
* dimensions and make the most of the finite patterns we have.
* The funky sample mask stuff is to ensure that we only shuffle
* *within* the current sample pattern, which is necessary to avoid
* early repeat pattern use. */
const uint pattern_i = hash_shuffle_uint(dimension, NUM_TAB_SOBOL_PATTERNS, seed);
/* sample_count should always be a power of two, so this results in a mask. */
const uint sample_mask = sample_count - 1;
const uint sample_shuffled = nested_uniform_scramble(sample,
hash_wang_seeded_uint(dimension, seed));
sample = (sample & ~sample_mask) | (sample_shuffled & sample_mask);
return ((pattern_i * sample_count) + sample) % (sample_count * NUM_TAB_SOBOL_PATTERNS);
}
ccl_device float tabulated_sobol_sample_1D(KernelGlobals kg,
uint sample,
const uint rng_hash,
const uint dimension)
{
uint seed = rng_hash;
/* Use the same sample sequence seed for all pixels when using
* scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
seed = kernel_data.integrator.seed;
}
/* Fetch the sample. */
const uint index = tabulated_sobol_shuffled_sample_index(kg, sample, dimension, seed);
float x = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS);
/* Do limited Cranley-Patterson rotation when using scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
const float jitter_x = hash_wang_seeded_float(dimension, rng_hash) *
kernel_data.integrator.scrambling_distance;
x += jitter_x;
x -= floorf(x);
}
return x;
}
ccl_device float2 tabulated_sobol_sample_2D(KernelGlobals kg,
uint sample,
const uint rng_hash,
const uint dimension)
{
uint seed = rng_hash;
/* Use the same sample sequence seed for all pixels when using
* scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
seed = kernel_data.integrator.seed;
}
/* Fetch the sample. */
const uint index = tabulated_sobol_shuffled_sample_index(kg, sample, dimension, seed);
float x = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS);
float y = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS + 1);
/* Do limited Cranley-Patterson rotation when using scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
const float jitter_x = hash_wang_seeded_float(dimension, rng_hash) *
kernel_data.integrator.scrambling_distance;
const float jitter_y = hash_wang_seeded_float(dimension, rng_hash ^ 0xca0e1151) *
kernel_data.integrator.scrambling_distance;
x += jitter_x;
y += jitter_y;
x -= floorf(x);
y -= floorf(y);
}
return make_float2(x, y);
}
ccl_device float3 tabulated_sobol_sample_3D(KernelGlobals kg,
uint sample,
const uint rng_hash,
const uint dimension)
{
uint seed = rng_hash;
/* Use the same sample sequence seed for all pixels when using
* scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
seed = kernel_data.integrator.seed;
}
/* Fetch the sample. */
const uint index = tabulated_sobol_shuffled_sample_index(kg, sample, dimension, seed);
float x = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS);
float y = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS + 1);
float z = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS + 2);
/* Do limited Cranley-Patterson rotation when using scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
const float jitter_x = hash_wang_seeded_float(dimension, rng_hash) *
kernel_data.integrator.scrambling_distance;
const float jitter_y = hash_wang_seeded_float(dimension, rng_hash ^ 0xca0e1151) *
kernel_data.integrator.scrambling_distance;
const float jitter_z = hash_wang_seeded_float(dimension, rng_hash ^ 0xbf604c5a) *
kernel_data.integrator.scrambling_distance;
x += jitter_x;
y += jitter_y;
z += jitter_z;
x -= floorf(x);
y -= floorf(y);
z -= floorf(z);
}
return make_float3(x, y, z);
}
ccl_device float4 tabulated_sobol_sample_4D(KernelGlobals kg,
uint sample,
const uint rng_hash,
const uint dimension)
{
uint seed = rng_hash;
/* Use the same sample sequence seed for all pixels when using
* scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
seed = kernel_data.integrator.seed;
}
/* Fetch the sample. */
const uint index = tabulated_sobol_shuffled_sample_index(kg, sample, dimension, seed);
float x = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS);
float y = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS + 1);
float z = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS + 2);
float w = kernel_data_fetch(sample_pattern_lut, index * NUM_TAB_SOBOL_DIMENSIONS + 3);
/* Do limited Cranley-Patterson rotation when using scrambling distance. */
if (kernel_data.integrator.scrambling_distance < 1.0f) {
const float jitter_x = hash_wang_seeded_float(dimension, rng_hash) *
kernel_data.integrator.scrambling_distance;
const float jitter_y = hash_wang_seeded_float(dimension, rng_hash ^ 0xca0e1151) *
kernel_data.integrator.scrambling_distance;
const float jitter_z = hash_wang_seeded_float(dimension, rng_hash ^ 0xbf604c5a) *
kernel_data.integrator.scrambling_distance;
const float jitter_w = hash_wang_seeded_float(dimension, rng_hash ^ 0x99634d1d) *
kernel_data.integrator.scrambling_distance;
x += jitter_x;
y += jitter_y;
z += jitter_z;
w += jitter_w;
x -= floorf(x);
y -= floorf(y);
z -= floorf(z);
w -= floorf(w);
}
return make_float4(x, y, z, w);
}
CCL_NAMESPACE_END

View File

@ -148,8 +148,7 @@ CCL_NAMESPACE_BEGIN
enum PathTraceDimension {
/* Init bounce */
PRNG_FILTER = 0,
PRNG_LENS = 1,
PRNG_TIME = 2,
PRNG_LENS_TIME = 1,
/* Shade bounce */
PRNG_TERMINATE = 0,
@ -187,7 +186,7 @@ enum PathTraceDimension {
enum SamplingPattern {
SAMPLING_PATTERN_SOBOL_BURLEY = 0,
SAMPLING_PATTERN_PMJ = 1,
SAMPLING_PATTERN_TABULATED_SOBOL = 1,
SAMPLING_NUM_PATTERNS,
};
@ -1032,13 +1031,28 @@ typedef struct LocalIntersection {
typedef struct KernelCamera {
/* type */
int type;
int use_dof_or_motion_blur;
/* depth of field */
float aperturesize;
float blades;
float bladesrotation;
float focaldistance;
/* motion blur */
float shuttertime;
int num_motion_steps, have_perspective_motion;
int pad1;
int pad2;
int pad3;
/* panorama */
int panorama_type;
float fisheye_fov;
float fisheye_lens;
float4 equirectangular_range;
float fisheye_lens_polynomial_bias;
float4 equirectangular_range;
float4 fisheye_lens_polynomial_coefficients;
/* stereo */
@ -1055,16 +1069,6 @@ typedef struct KernelCamera {
float4 dx;
float4 dy;
/* depth of field */
float aperturesize;
float blades;
float bladesrotation;
float focaldistance;
/* motion blur */
float shuttertime;
int num_motion_steps, have_perspective_motion;
/* clipping */
float nearclip;
float cliplength;
@ -1075,7 +1079,6 @@ typedef struct KernelCamera {
/* render size */
float width, height;
int pad1;
/* anamorphic lens bokeh */
float inv_aperture_ratio;
@ -1466,15 +1469,15 @@ typedef struct KernelShaderEvalInput {
} KernelShaderEvalInput;
static_assert_align(KernelShaderEvalInput, 16);
/* Pre-computed sample table sizes for PMJ02 sampler.
/* Pre-computed sample table sizes for the tabulated Sobol sampler.
*
* NOTE: min and max samples *must* be a power of two, and patterns
* ideally should be as well.
*/
#define MIN_PMJ_SAMPLES 256
#define MAX_PMJ_SAMPLES 8192
#define NUM_PMJ_DIMENSIONS 2
#define NUM_PMJ_PATTERNS 256
#define MIN_TAB_SOBOL_SAMPLES 256
#define MAX_TAB_SOBOL_SAMPLES 8192
#define NUM_TAB_SOBOL_DIMENSIONS 4
#define NUM_TAB_SOBOL_PATTERNS 256
/* Device kernels.
*

View File

@ -23,7 +23,6 @@ set(SRC
image_sky.cpp
image_vdb.cpp
integrator.cpp
jitter.cpp
light.cpp
light_tree.cpp
mesh.cpp
@ -43,6 +42,7 @@ set(SRC
stats.cpp
svm.cpp
tables.cpp
tabulated_sobol.cpp
volume.cpp
)
@ -65,7 +65,6 @@ set(SRC_HEADERS
integrator.h
light.h
light_tree.h
jitter.h
mesh.h
object.h
osl.h
@ -81,6 +80,7 @@ set(SRC_HEADERS
stats.h
svm.h
tables.h
tabulated_sobol.h
volume.h
)

View File

@ -8,12 +8,12 @@
#include "scene/camera.h"
#include "scene/film.h"
#include "scene/integrator.h"
#include "scene/jitter.h"
#include "scene/light.h"
#include "scene/object.h"
#include "scene/scene.h"
#include "scene/shader.h"
#include "scene/stats.h"
#include "scene/tabulated_sobol.h"
#include "kernel/types.h"
@ -107,8 +107,11 @@ NODE_DEFINE(Integrator)
static NodeEnum sampling_pattern_enum;
sampling_pattern_enum.insert("sobol_burley", SAMPLING_PATTERN_SOBOL_BURLEY);
sampling_pattern_enum.insert("pmj", SAMPLING_PATTERN_PMJ);
SOCKET_ENUM(sampling_pattern, "Sampling Pattern", sampling_pattern_enum, SAMPLING_PATTERN_PMJ);
sampling_pattern_enum.insert("tabulated_sobol", SAMPLING_PATTERN_TABULATED_SOBOL);
SOCKET_ENUM(sampling_pattern,
"Sampling Pattern",
sampling_pattern_enum,
SAMPLING_PATTERN_TABULATED_SOBOL);
SOCKET_FLOAT(scrambling_distance, "Scrambling Distance", 1.0f);
static NodeEnum denoiser_type_enum;
@ -250,6 +253,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->sampling_pattern = sampling_pattern;
kintegrator->scrambling_distance = scrambling_distance;
kintegrator->sobol_index_mask = reverse_integer_bits(next_power_of_two(aa_samples - 1) - 1);
kintegrator->use_light_tree = scene->integrator->use_light_tree;
if (light_sampling_threshold > 0.0f) {
@ -259,23 +263,23 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->light_inv_rr_threshold = 0.0f;
}
constexpr int num_sequences = NUM_PMJ_PATTERNS;
int sequence_size = clamp(next_power_of_two(aa_samples - 1), MIN_PMJ_SAMPLES, MAX_PMJ_SAMPLES);
if (kintegrator->sampling_pattern == SAMPLING_PATTERN_PMJ &&
/* Build pre-tabulated Sobol samples if needed. */
int sequence_size = clamp(
next_power_of_two(aa_samples - 1), MIN_TAB_SOBOL_SAMPLES, MAX_TAB_SOBOL_SAMPLES);
if (kintegrator->sampling_pattern == SAMPLING_PATTERN_TABULATED_SOBOL &&
dscene->sample_pattern_lut.size() !=
(sequence_size * NUM_PMJ_DIMENSIONS * NUM_PMJ_PATTERNS)) {
kintegrator->pmj_sequence_size = sequence_size;
(sequence_size * NUM_TAB_SOBOL_PATTERNS * NUM_TAB_SOBOL_DIMENSIONS)) {
kintegrator->tabulated_sobol_sequence_size = sequence_size;
if (dscene->sample_pattern_lut.size() != 0) {
dscene->sample_pattern_lut.free();
}
float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * num_sequences *
NUM_PMJ_DIMENSIONS);
float4 *directions = (float4 *)dscene->sample_pattern_lut.alloc(
sequence_size * NUM_TAB_SOBOL_PATTERNS * NUM_TAB_SOBOL_DIMENSIONS);
TaskPool pool;
for (int j = 0; j < num_sequences; ++j) {
float2 *sequence = directions + j * sequence_size;
pool.push(
function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
for (int j = 0; j < NUM_TAB_SOBOL_PATTERNS; ++j) {
float4 *sequence = directions + j * sequence_size;
pool.push(function_bind(&tabulated_sobol_generate_4D, sequence, sequence_size, j));
}
pool.wait_work();

View File

@ -1,57 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2019-2022 Blender Foundation */
/* This file is based on "Progressive Multi-Jittered Sample Sequences"
* by Christensen, Kensler, and Kilpatrick, but with a much simpler and
* faster implementation based on "Stochastic Generation of (t, s)
* Sample Sequences" by Helmer, Christensen, and Kensler.
*/
#include "scene/jitter.h"
#include "util/hash.h"
#include <math.h>
#include <vector>
CCL_NAMESPACE_BEGIN
void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed)
{
/* Xor values for generating the PMJ02 sequence. These permute the
* order we visit the strata in, which is what makes the code below
* produce the PMJ02 sequence. Other choices are also possible, but
* result in different sequences. */
static uint xors[2][32] = {
{0x00000000, 0x00000000, 0x00000002, 0x00000006, 0x00000006, 0x0000000e, 0x00000036,
0x0000004e, 0x00000016, 0x0000002e, 0x00000276, 0x000006ce, 0x00000716, 0x00000c2e,
0x00003076, 0x000040ce, 0x00000116, 0x0000022e, 0x00020676, 0x00060ece, 0x00061716,
0x000e2c2e, 0x00367076, 0x004ec0ce, 0x00170116, 0x002c022e, 0x02700676, 0x06c00ece,
0x07001716, 0x0c002c2e, 0x30007076, 0x4000c0ce},
{0x00000000, 0x00000001, 0x00000003, 0x00000003, 0x00000007, 0x0000001b, 0x00000027,
0x0000000b, 0x00000017, 0x0000013b, 0x00000367, 0x0000038b, 0x00000617, 0x0000183b,
0x00002067, 0x0000008b, 0x00000117, 0x0001033b, 0x00030767, 0x00030b8b, 0x00071617,
0x001b383b, 0x00276067, 0x000b808b, 0x00160117, 0x0138033b, 0x03600767, 0x03800b8b,
0x06001617, 0x1800383b, 0x20006067, 0x0000808b}};
uint rng_i = rng_seed;
points[0].x = hash_hp_float(rng_i++);
points[0].y = hash_hp_float(rng_i++);
/* Subdivide the domain into smaller and smaller strata, filling in new
* points as we go. */
for (int log_N = 0, N = 1; N < size; log_N++, N *= 2) {
float strata_count = (float)(N * 2);
for (int i = 0; i < N && (N + i) < size; i++) {
/* Find the strata that are already occupied in this cell. */
uint occupied_x_stratum = (uint)(points[i ^ xors[0][log_N]].x * strata_count);
uint occupied_y_stratum = (uint)(points[i ^ xors[1][log_N]].y * strata_count);
/* Generate a new point in the unoccupied strata. */
points[N + i].x = ((float)(occupied_x_stratum ^ 1) + hash_hp_float(rng_i++)) / strata_count;
points[N + i].y = ((float)(occupied_y_stratum ^ 1) + hash_hp_float(rng_i++)) / strata_count;
}
}
}
CCL_NAMESPACE_END

View File

@ -1,15 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2019-2022 Blender Foundation */
#ifndef __JITTER_H__
#define __JITTER_H__
#include "util/types.h"
CCL_NAMESPACE_BEGIN
void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed);
CCL_NAMESPACE_END
#endif /* __JITTER_H__ */

View File

@ -226,6 +226,7 @@ NODE_DEFINE(ImageTextureNode)
extension_enum.insert("periodic", EXTENSION_REPEAT);
extension_enum.insert("clamp", EXTENSION_EXTEND);
extension_enum.insert("black", EXTENSION_CLIP);
extension_enum.insert("mirror", EXTENSION_MIRROR);
SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
static NodeEnum projection_enum;

View File

@ -0,0 +1,71 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2019-2022 Blender Foundation */
/* This file is based on the paper "Stochastic Generation of (t, s)
* Sample Sequences" by Helmer, Christensen, and Kensler.
*/
#include "scene/tabulated_sobol.h"
#include "util/hash.h"
#include <math.h>
#include <vector>
CCL_NAMESPACE_BEGIN
void tabulated_sobol_generate_4D(float4 points[], int size, int rng_seed)
{
/* Xor values for generating the (4D) Owen-scrambled Sobol sequence.
* These permute the order we visit the strata in, which is what
* makes the code below produce the scrambled Sobol sequence. Other
* choices are also possible, but result in different sequences. */
static uint xors[4][32] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0x00000000, 0x00000001, 0x00000001, 0x00000007, 0x00000001, 0x00000013, 0x00000015,
0x0000007f, 0x00000001, 0x00000103, 0x00000105, 0x0000070f, 0x00000111, 0x00001333,
0x00001555, 0x00007fff, 0x00000001, 0x00010003, 0x00010005, 0x0007000f, 0x00010011,
0x00130033, 0x00150055, 0x007f00ff, 0x00010101, 0x01030303, 0x01050505, 0x070f0f0f,
0x01111111, 0x13333333, 0x15555555, 0x7fffffff},
{0x00000000, 0x00000001, 0x00000003, 0x00000001, 0x00000005, 0x0000001f, 0x0000002b,
0x0000003d, 0x00000011, 0x00000133, 0x00000377, 0x00000199, 0x00000445, 0x00001ccf,
0x00002ddb, 0x0000366d, 0x00000101, 0x00010303, 0x00030707, 0x00010909, 0x00051515,
0x001f3f3f, 0x002b6b6b, 0x003dbdbd, 0x00101011, 0x01303033, 0x03707077, 0x01909099,
0x04515145, 0x1cf3f3cf, 0x2db6b6db, 0x36dbdb6d},
{0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x0000000d, 0x0000000c, 0x00000005,
0x0000004f, 0x00000014, 0x000000e7, 0x00000329, 0x0000039c, 0x00000011, 0x00001033,
0x00000044, 0x000030bb, 0x0000d1cd, 0x0000c2ec, 0x00005415, 0x0004fc3f, 0x00015054,
0x000e5c97, 0x0032e5b9, 0x0039725c, 0x00000101, 0x01000303, 0x00000404, 0x03000b0b,
0x0d001d1d, 0x0c002c2c, 0x05004545, 0x4f00cfcf},
};
/* Randomize the seed, in case it's incrementing. The constant is just a
* random number, and has no other significance. */
uint rng_i = hash_hp_seeded_uint(rng_seed, 0x44605a73);
points[0].x = hash_hp_float(rng_i++);
points[0].y = hash_hp_float(rng_i++);
points[0].z = hash_hp_float(rng_i++);
points[0].w = hash_hp_float(rng_i++);
/* Subdivide the domain into smaller and smaller strata, filling in new
* points as we go. */
for (int log_N = 0, N = 1; N < size; log_N++, N *= 2) {
float strata_count = (float)(N * 2);
for (int i = 0; i < N && (N + i) < size; i++) {
/* Find the strata that are already occupied in this cell. */
uint occupied_x_stratum = (uint)(points[i ^ xors[0][log_N]].x * strata_count);
uint occupied_y_stratum = (uint)(points[i ^ xors[1][log_N]].y * strata_count);
uint occupied_z_stratum = (uint)(points[i ^ xors[2][log_N]].z * strata_count);
uint occupied_w_stratum = (uint)(points[i ^ xors[3][log_N]].w * strata_count);
/* Generate a new point in the unoccupied strata. */
points[N + i].x = ((float)(occupied_x_stratum ^ 1) + hash_hp_float(rng_i++)) / strata_count;
points[N + i].y = ((float)(occupied_y_stratum ^ 1) + hash_hp_float(rng_i++)) / strata_count;
points[N + i].z = ((float)(occupied_z_stratum ^ 1) + hash_hp_float(rng_i++)) / strata_count;
points[N + i].w = ((float)(occupied_w_stratum ^ 1) + hash_hp_float(rng_i++)) / strata_count;
}
}
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2019-2022 Blender Foundation */
#ifndef __TABULATED_SOBOL_H__
#define __TABULATED_SOBOL_H__
#include "util/types.h"
CCL_NAMESPACE_BEGIN
void tabulated_sobol_generate_4D(float4 points[], int size, int rng_seed);
CCL_NAMESPACE_END
#endif /* __TABULATED_SOBOL_H__ */

View File

@ -22,13 +22,26 @@ static bool validate_cpu_capabilities()
#endif
}
/* These are not just static variables because we don't want to run the
* constructor until we know the instructions are supported. */
static vfloat8 float8_a()
{
return make_vfloat8(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f);
}
static vfloat8 float8_b()
{
return make_vfloat8(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f);
}
static vfloat8 float8_c()
{
return make_vfloat8(1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f);
}
#define INIT_FLOAT8_TEST \
if (!validate_cpu_capabilities()) \
return; \
\
const vfloat8 float8_a = make_vfloat8(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f); \
const vfloat8 float8_b = make_vfloat8(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f); \
const vfloat8 float8_c = make_vfloat8(1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f);
return;
#define compare_vector_scalar(a, b) \
for (size_t index = 0; index < 8; index++) \
@ -57,15 +70,15 @@ static bool validate_cpu_capabilities()
static const float float_b = 1.5f;
TEST(TEST_CATEGORY_NAME,
float8_add_vv){basic_test_vv(float8_a, float8_b, +)} TEST(TEST_CATEGORY_NAME, float8_sub_vv){
basic_test_vv(float8_a, float8_b, -)} TEST(TEST_CATEGORY_NAME, float8_mul_vv){
basic_test_vv(float8_a, float8_b, *)} TEST(TEST_CATEGORY_NAME, float8_div_vv){
basic_test_vv(float8_a, float8_b, /)} TEST(TEST_CATEGORY_NAME, float8_add_vf){
basic_test_vf(float8_a, float_b, +)} TEST(TEST_CATEGORY_NAME, float8_sub_vf){
basic_test_vf(float8_a, float_b, -)} TEST(TEST_CATEGORY_NAME, float8_mul_vf){
basic_test_vf(float8_a, float_b, *)} TEST(TEST_CATEGORY_NAME,
float8_div_vf){basic_test_vf(float8_a, float_b, /)}
TEST(TEST_CATEGORY_NAME, float8_add_vv){
basic_test_vv(float8_a(), float8_b(), +)} TEST(TEST_CATEGORY_NAME, float8_sub_vv){
basic_test_vv(float8_a(), float8_b(), -)} TEST(TEST_CATEGORY_NAME, float8_mul_vv){
basic_test_vv(float8_a(), float8_b(), *)} TEST(TEST_CATEGORY_NAME, float8_div_vv){
basic_test_vv(float8_a(), float8_b(), /)} TEST(TEST_CATEGORY_NAME, float8_add_vf){
basic_test_vf(float8_a(), float_b, +)} TEST(TEST_CATEGORY_NAME, float8_sub_vf){
basic_test_vf(float8_a(), float_b, -)} TEST(TEST_CATEGORY_NAME, float8_mul_vf){
basic_test_vf(float8_a(), float_b, *)} TEST(TEST_CATEGORY_NAME, float8_div_vf){
basic_test_vf(float8_a(), float_b, /)}
TEST(TEST_CATEGORY_NAME, float8_ctor)
{
@ -85,18 +98,18 @@ TEST(TEST_CATEGORY_NAME, float8_sqrt)
TEST(TEST_CATEGORY_NAME, float8_min_max)
{
INIT_FLOAT8_TEST
compare_vector_vector(min(float8_a, float8_b), float8_a);
compare_vector_vector(max(float8_a, float8_b), float8_b);
compare_vector_vector(min(float8_a(), float8_b()), float8_a());
compare_vector_vector(max(float8_a(), float8_b()), float8_b());
}
TEST(TEST_CATEGORY_NAME, float8_shuffle)
{
INIT_FLOAT8_TEST
vfloat8 res0 = shuffle<0, 1, 2, 3, 1, 3, 2, 0>(float8_a);
vfloat8 res0 = shuffle<0, 1, 2, 3, 1, 3, 2, 0>(float8_a());
compare_vector_vector(res0, make_vfloat8(0.1f, 0.2f, 0.3f, 0.4f, 0.6f, 0.8f, 0.7f, 0.5f));
vfloat8 res1 = shuffle<3>(float8_a);
vfloat8 res1 = shuffle<3>(float8_a());
compare_vector_vector(res1, make_vfloat8(0.4f, 0.4f, 0.4f, 0.4f, 0.8f, 0.8f, 0.8f, 0.8f));
vfloat8 res2 = shuffle<3, 2, 1, 0>(float8_a, float8_b);
vfloat8 res2 = shuffle<3, 2, 1, 0>(float8_a(), float8_b());
compare_vector_vector(res2, make_vfloat8(0.4f, 0.3f, 2.0f, 1.0f, 0.8f, 0.7f, 6.0f, 5.0f));
}

View File

@ -65,6 +65,8 @@ typedef enum ExtensionType {
EXTENSION_EXTEND = 1,
/* Clip to image size and set exterior pixels as transparent. */
EXTENSION_CLIP = 2,
/* Repeatedly flip the image horizontally and vertically. */
EXTENSION_MIRROR = 3,
EXTENSION_NUM_TYPES,
} ExtensionType;

View File

@ -5316,7 +5316,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
/* Connect to the Wayland server. */
display_->wl_display = wl_display_connect(nullptr);
if (!display_->wl_display) {
gwl_display_destroy(display_);
this->~GHOST_SystemWayland();
throw std::runtime_error("Wayland: unable to connect to display!");
}
@ -5360,7 +5360,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
"WAYLAND found but libdecor was not, install libdecor for Wayland support, "
"falling back to X11\n");
# endif
gwl_display_destroy(display_);
this->~GHOST_SystemWayland();
throw std::runtime_error("Wayland: unable to find libdecor!");
use_libdecor = true;
@ -5377,7 +5377,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
GWL_LibDecor_System &decor = *display_->libdecor;
decor.context = libdecor_new(display_->wl_display, &libdecor_interface);
if (!decor.context) {
gwl_display_destroy(display_);
this->~GHOST_SystemWayland();
throw std::runtime_error("Wayland: unable to create window decorations!");
}
}
@ -5388,7 +5388,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
{
GWL_XDG_Decor_System &decor = *display_->xdg_decor;
if (!decor.shell) {
gwl_display_destroy(display_);
this->~GHOST_SystemWayland();
throw std::runtime_error("Wayland: unable to access xdg_shell!");
}
}

View File

@ -1061,11 +1061,16 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
int32_t x_screen = screen_co[0], y_screen = screen_co[1];
if (window->getCursorGrabModeIsWarp()) {
/* WORKAROUND:
* Sometimes Windows ignores `SetCursorPos()` or `SendInput()` calls or the mouse event is
* outdated. Identify these cases by checking if the cursor is not yet within bounds. */
static bool is_warping_x = false;
static bool is_warping_y = false;
static uint64_t last_warp_time = 0;
{
/* WORKAROUND: Check the mouse event timestamp so we can ignore mousemove events that were
* already in the queue before we changed the cursor position. */
MOUSEMOVEPOINT mp = {x_screen, y_screen};
::GetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &mp, &mp, 1, GMMP_USE_DISPLAY_POINTS);
if (mp.time <= last_warp_time) {
return NULL;
}
}
int32_t x_new = x_screen;
int32_t y_new = y_screen;
@ -1112,31 +1117,35 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
window->getCursorGrabAccum(x_accum, y_accum);
if (x_new != x_screen || y_new != y_screen) {
system->setCursorPosition(x_new, y_new); /* wrap */
/* WORKAROUND: Store the current time so that we ignore outdated mousemove events. */
last_warp_time = ::GetTickCount64();
/* Do not update the accum values if we are an outdated or failed pos-warp event. */
if (!is_warping_x) {
is_warping_x = x_new != x_screen;
if (is_warping_x) {
x_accum += (x_screen - x_new);
}
}
/* For more control over which timestamp to store in the event, we use `SendInput` instead of
* `SetCursorPos` here.
* It is quite unlikely to happen, but still possible that some event between
* `last_warp_time` and `GHOST_SystemWin32::setCursorPosition` is sent. */
INPUT input[3] = {0};
input[0].type = INPUT_MOUSE;
input[0].mi.dx = (LONG)(x_new * (65535.0f / GetSystemMetrics(SM_CXSCREEN)));
input[0].mi.dy = (LONG)(y_new * (65535.0f / GetSystemMetrics(SM_CYSCREEN)));
input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
input[0].mi.time = last_warp_time;
if (!is_warping_y) {
is_warping_y = y_new != y_screen;
if (is_warping_y) {
y_accum += (y_screen - y_new);
}
}
/* Send 3 events with a jitter to make sure Windows does not occasionally and
* inexplicably ignore `SetCursorPos` or `SendInput`. */
input[2] = input[1] = input[0];
input[1].mi.dx += 1;
::SendInput(3, input, sizeof(INPUT));
x_accum += (x_screen - x_new);
y_accum += (y_screen - y_new);
window->setCursorGrabAccum(x_accum, y_accum);
/* When wrapping we don't need to add an event because the setCursorPosition call will cause
* a new event after. */
/* When wrapping we don't need to add an event because the `SendInput` call will cause new
* events after. */
return NULL;
}
is_warping_x = false;
is_warping_y = false;
x_screen += x_accum;
y_screen += y_accum;
}
@ -1210,16 +1219,16 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80;
const bool alt_pressed = has_state && state[VK_MENU] & 0x80;
if (!key_down) {
/* Pass. */
}
/* We can be here with !key_down if processing dead keys (diacritics). See T103119. */
/* No text with control key pressed (Alt can be used to insert special characters though!). */
else if (ctrl_pressed && !alt_pressed) {
if (ctrl_pressed && !alt_pressed) {
/* Pass. */
}
/* Don't call #ToUnicodeEx on dead keys as it clears the buffer and so won't allow diacritical
* composition. */
else if (MapVirtualKeyW(vk, 2) != 0) {
* composition. XXX: we are not checking return of MapVirtualKeyW for high bit set, which is
* what is supposed to indicate dead keys. But this is working now so approach cautiously. */
else if (MapVirtualKeyW(vk, MAPVK_VK_TO_CHAR) != 0) {
wchar_t utf16[3] = {0};
int r;
/* TODO: #ToUnicodeEx can respond with up to 4 utf16 chars (only 2 here).
@ -1234,6 +1243,10 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
utf8_char[0] = '\0';
}
}
if (!key_down) {
/* Clear or wm_event_add_ghostevent will warn of unexpected data on key up. */
utf8_char[0] = '\0';
}
}
#ifdef WITH_INPUT_IME

View File

@ -167,7 +167,7 @@ add_library(bli_lib
"../../../source/blender/blenlib/intern/rct.c"
"../../../source/blender/blenlib/intern/string.c"
"../../../source/blender/blenlib/intern/string_utf8.c"
"../../../source/blender/blenlib/intern/listbase.c"
"../../../source/blender/blenlib/intern/listbase.cc"
"../../../source/blender/blenlib/intern/math_color.c"
"../../../source/blender/blenlib/intern/math_geom.c"
"../../../source/blender/blenlib/intern/math_matrix.c"

View File

@ -94,6 +94,16 @@ _namespace = globals()
_modules_loaded = [_namespace[name] for name in _modules]
del _namespace
def _addon_support_items():
"""Return the addon support levels suitable for this Blender build."""
items = [
('OFFICIAL', "Official", "Officially supported"),
('COMMUNITY', "Community", "Maintained by community developers"),
]
if bpy.app.version_cycle == 'alpha':
items.append(('TESTING', "Testing", "Newly contributed scripts (excluded from release builds)"))
return items
def register():
from bpy.utils import register_class
@ -141,11 +151,7 @@ def register():
)
WindowManager.addon_support = EnumProperty(
items=[
('OFFICIAL', "Official", "Officially supported"),
('COMMUNITY', "Community", "Maintained by community developers"),
('TESTING', "Testing", "Newly contributed scripts (excluded from release builds)")
],
items=_addon_support_items(),
name="Support",
description="Display support level",
default={'OFFICIAL', 'COMMUNITY'},

View File

@ -9,7 +9,6 @@
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_library.h"
#include "AS_asset_library.hh"
#include "BLI_fileops.hh"

View File

@ -17,7 +17,6 @@
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BLI_set.hh"
#include "DNA_userdef_types.h"

View File

@ -7,8 +7,6 @@
#include "BKE_blender.h"
#include "BKE_preferences.h"
#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */
#include "BLI_path_util.h"
#include "BLI_string_ref.hh"
#include "DNA_asset_types.h"

View File

@ -13,8 +13,6 @@
#include "AS_asset_representation.h"
#include "AS_asset_representation.hh"
#include "BKE_asset.h"
namespace blender::asset_system {
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,

View File

@ -4,7 +4,6 @@
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "BKE_appdir.h"
#include "BKE_preferences.h"
#include "BLI_fileops.h"
@ -13,8 +12,6 @@
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
#include "CLG_log.h"
#include "testing/testing.h"
#include "asset_library_test_common.hh"

View File

@ -4,17 +4,8 @@
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "BKE_appdir.h"
#include "BKE_preferences.h"
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
#include "CLG_log.h"
#include "testing/testing.h"
#include "asset_library_test_common.hh"

View File

@ -5,7 +5,6 @@
#include "AS_asset_library.h"
#include "AS_asset_library.hh"
#include "BKE_appdir.h"
#include "BKE_callbacks.h"
#include "asset_library_service.hh"

View File

@ -25,13 +25,13 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 3
#define BLENDER_FILE_SUBVERSION 4
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
* was written with too new a version. */
#define BLENDER_FILE_MIN_VERSION 305
#define BLENDER_FILE_MIN_SUBVERSION 3
#define BLENDER_FILE_MIN_SUBVERSION 4
/** User readable version string. */
const char *BKE_blender_version_string(void);

View File

@ -254,14 +254,6 @@ void BKE_mesh_texspace_get_reference(struct Mesh *me,
float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
/**
* Split faces based on the edge angle and loop normals.
* Matches behavior of face splitting in render engines.
*
* \note Will leave #CD_NORMAL loop data layer which is used by render engines to set shading up.
*/
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
/**
* Create new mesh from the given object at its current state.
* The owner of this mesh is unknown, it is up to the caller to decide.

View File

@ -425,6 +425,11 @@ inline const bNode *bNodeTree::group_output_node() const
return this->runtime->group_output_node;
}
inline blender::Span<const bNode *> bNodeTree::group_input_nodes() const
{
return this->nodes_by_type("NodeGroupInput");
}
inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));

View File

@ -516,6 +516,11 @@ typedef struct SculptAttribute {
int elem_size, elem_num;
bool data_for_bmesh; /* Temporary data store as array outside of bmesh. */
/* Data is a flat array outside the CustomData system.
* This will be true if simple_array is requested in
* SculptAttributeParams, or the PBVH type is PBVH_GRIDS or PBVH_BMESH.
*/
bool simple_array;
/* Data stored per BMesh element. */
int bmesh_cd_offset;

View File

@ -414,7 +414,8 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, struct Mesh *me);
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
int gridsize);
int gridsize,
int display_gridsize);
/**
* Multi-res level, only valid for type == #PBVH_GRIDS.

View File

@ -1436,7 +1436,7 @@ void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], con
}
/**
* Find roots of cubic equation (c0 x^3 + c1 x^2 + c2 x + c3)
* Find roots of cubic equation (c0 + c1 x + c2 x^2 + c3 x^3)
* \return number of roots in `o`.
*
* \note it is up to the caller to allocate enough memory for `o`.

View File

@ -1363,7 +1363,7 @@ void BKE_mesh_material_index_remove(Mesh *me, short index)
}
MutableVArraySpan<int> indices_span(material_indices.varray);
for (const int i : indices_span.index_range()) {
if (indices_span[i] > 0 && indices_span[i] > index) {
if (indices_span[i] > 0 && indices_span[i] >= index) {
indices_span[i]--;
}
}
@ -1836,267 +1836,6 @@ void BKE_mesh_calc_normals_split(Mesh *mesh)
BKE_mesh_calc_normals_split_ex(mesh, nullptr, ensure_corner_normal_layer(*mesh));
}
/* Split faces helper functions. */
struct SplitFaceNewVert {
struct SplitFaceNewVert *next;
int new_index;
int orig_index;
const float *vnor;
};
struct SplitFaceNewEdge {
struct SplitFaceNewEdge *next;
int new_index;
int orig_index;
int v1;
int v2;
};
/**
* Detect necessary new vertices, and update loop vertex indices accordingly.
* \warning Leaves mesh in invalid state.
* \param lnors_spacearr: Mandatory because trying to do the job in simple way without that data is
* doomed to fail, even when only dealing with smooth/flat faces one can find cases that no simple
* algorithm can handle properly.
*/
static int split_faces_prepare_new_verts(Mesh &mesh,
const MLoopNorSpaceArray &lnors_spacearr,
SplitFaceNewVert **new_verts,
MemArena &memarena)
{
const int loops_len = mesh.totloop;
int verts_len = mesh.totvert;
MutableSpan<MLoop> loops = mesh.loops_for_write();
BKE_mesh_vertex_normals_ensure(&mesh);
float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
BitVector<> verts_used(verts_len, false);
BitVector<> done_loops(loops_len, false);
BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
for (int loop_idx = 0; loop_idx < loops_len; loop_idx++) {
if (done_loops[loop_idx]) {
continue;
}
const MLoopNorSpace &lnor_space = *lnors_spacearr.lspacearr[loop_idx];
const int vert_idx = loops[loop_idx].v;
const bool vert_used = verts_used[vert_idx];
/* If vert is already used by another smooth fan, we need a new vert for this one. */
const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
if (lnor_space.flags & MLNOR_SPACE_IS_SINGLE) {
/* Single loop in this fan... */
BLI_assert(POINTER_AS_INT(lnor_space.loops) == loop_idx);
done_loops[loop_idx].set();
if (vert_used) {
loops[loop_idx].v = new_vert_idx;
}
}
else {
for (const LinkNode *lnode = lnor_space.loops; lnode; lnode = lnode->next) {
const int ml_fan_idx = POINTER_AS_INT(lnode->link);
done_loops[ml_fan_idx].set();
if (vert_used) {
loops[ml_fan_idx].v = new_vert_idx;
}
}
}
if (!vert_used) {
verts_used[vert_idx].set();
/* We need to update that vertex's normal here, we won't go over it again. */
/* This is important! *DO NOT* set vnor to final computed lnor,
* vnor should always be defined to 'automatic normal' value computed from its polys,
* not some custom normal.
* Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
copy_v3_v3(vert_normals[vert_idx], lnor_space.vec_lnor);
}
else {
/* Add new vert to list. */
SplitFaceNewVert *new_vert = static_cast<SplitFaceNewVert *>(
BLI_memarena_alloc(&memarena, sizeof(*new_vert)));
new_vert->orig_index = vert_idx;
new_vert->new_index = new_vert_idx;
new_vert->vnor = lnor_space.vec_lnor; /* See note above. */
new_vert->next = *new_verts;
*new_verts = new_vert;
}
}
return verts_len - mesh.totvert;
}
/* Detect needed new edges, and update accordingly loops' edge indices.
* WARNING! Leaves mesh in invalid state. */
static int split_faces_prepare_new_edges(Mesh *mesh,
SplitFaceNewEdge **new_edges,
MemArena *memarena)
{
const int num_polys = mesh->totpoly;
int num_edges = mesh->totedge;
MutableSpan<MEdge> edges = mesh->edges_for_write();
MutableSpan<MLoop> loops = mesh->loops_for_write();
const Span<MPoly> polys = mesh->polys();
BitVector<> edges_used(num_edges, false);
EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
const MPoly *mp = polys.data();
for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
MLoop *ml_prev = &loops[mp->loopstart + mp->totloop - 1];
MLoop *ml = &loops[mp->loopstart];
for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
void **eval;
if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
const int edge_idx = ml_prev->e;
/* That edge has not been encountered yet, define it. */
if (edges_used[edge_idx]) {
/* Original edge has already been used, we need to define a new one. */
const int new_edge_idx = num_edges++;
*eval = POINTER_FROM_INT(new_edge_idx);
ml_prev->e = new_edge_idx;
SplitFaceNewEdge *new_edge = (SplitFaceNewEdge *)BLI_memarena_alloc(memarena,
sizeof(*new_edge));
new_edge->orig_index = edge_idx;
new_edge->new_index = new_edge_idx;
new_edge->v1 = ml_prev->v;
new_edge->v2 = ml->v;
new_edge->next = *new_edges;
*new_edges = new_edge;
}
else {
/* We can re-use original edge. */
edges[edge_idx].v1 = ml_prev->v;
edges[edge_idx].v2 = ml->v;
*eval = POINTER_FROM_INT(edge_idx);
edges_used[edge_idx].set();
}
}
else {
/* Edge already known, just update loop's edge index. */
ml_prev->e = POINTER_AS_INT(*eval);
}
ml_prev = ml;
}
}
BLI_edgehash_free(edges_hash, nullptr);
return num_edges - mesh->totedge;
}
/* Perform actual split of vertices. */
static void split_faces_split_new_verts(Mesh *mesh,
SplitFaceNewVert *new_verts,
const int num_new_verts)
{
const int verts_len = mesh->totvert - num_new_verts;
float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
/* Normals were already calculated at the beginning of this operation, we rely on that to update
* them partially here. */
BLI_assert(!BKE_mesh_vertex_normals_are_dirty(mesh));
/* Remember new_verts is a single linklist, so its items are in reversed order... */
for (int i = mesh->totvert - 1; i >= verts_len; i--, new_verts = new_verts->next) {
BLI_assert(new_verts->new_index == i);
BLI_assert(new_verts->new_index != new_verts->orig_index);
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
if (new_verts->vnor) {
copy_v3_v3(vert_normals[i], new_verts->vnor);
}
}
}
/* Perform actual split of edges. */
static void split_faces_split_new_edges(Mesh *mesh,
SplitFaceNewEdge *new_edges,
const int num_new_edges)
{
const int num_edges = mesh->totedge - num_new_edges;
MutableSpan<MEdge> edges = mesh->edges_for_write();
/* Remember new_edges is a single linklist, so its items are in reversed order... */
MEdge *new_med = &edges[mesh->totedge - 1];
for (int i = mesh->totedge - 1; i >= num_edges; i--, new_med--, new_edges = new_edges->next) {
BLI_assert(new_edges->new_index == i);
BLI_assert(new_edges->new_index != new_edges->orig_index);
CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
new_med->v1 = new_edges->v1;
new_med->v2 = new_edges->v2;
}
}
void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
{
const int num_polys = mesh->totpoly;
if (num_polys == 0) {
return;
}
BKE_mesh_tessface_clear(mesh);
MLoopNorSpaceArray lnors_spacearr = {nullptr};
/* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr, ensure_corner_normal_layer(*mesh));
/* Stealing memarena from loop normals space array. */
MemArena *memarena = lnors_spacearr.mem;
SplitFaceNewVert *new_verts = nullptr;
SplitFaceNewEdge *new_edges = nullptr;
/* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
const int num_new_verts = split_faces_prepare_new_verts(
*mesh, lnors_spacearr, &new_verts, *memarena);
if (num_new_verts > 0) {
/* Reminder: beyond this point, there is no way out, mesh is in invalid state
* (due to early-reassignment of loops' vertex and edge indices to new,
* to-be-created split ones). */
const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
/* We can have to split a vertex without having to add a single new edge... */
const bool do_edges = (num_new_edges > 0);
/* Reallocate all vert and edge related data. */
CustomData_realloc(&mesh->vdata, mesh->totvert, mesh->totvert + num_new_verts);
mesh->totvert += num_new_verts;
if (do_edges) {
CustomData_realloc(&mesh->edata, mesh->totedge, mesh->totedge + num_new_edges);
mesh->totedge += num_new_edges;
}
/* Update normals manually to avoid recalculation after this operation. */
mesh->runtime->vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime->vert_normals,
sizeof(float[3]) * mesh->totvert);
/* Perform actual split of vertices and edges. */
split_faces_split_new_verts(mesh, new_verts, num_new_verts);
if (do_edges) {
split_faces_split_new_edges(mesh, new_edges, num_new_edges);
}
}
/* NOTE: after this point mesh is expected to be valid again. */
/* CD_NORMAL is expected to be temporary only. */
if (free_loop_normals) {
CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
}
/* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
BKE_lnor_spacearr_free(&lnors_spacearr);
#ifdef VALIDATE_MESH
BKE_mesh_validate(mesh, true, true);
#endif
}
/* **** Depsgraph evaluation **** */
void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)

View File

@ -426,6 +426,28 @@ void multires_flush_sculpt_updates(Object *object)
}
Mesh *mesh = static_cast<Mesh *>(object->data);
/* Check that the multires modifier still exists.
* Fixes crash when deleting multires modifier
* from within sculpt mode.
*/
ModifierData *md;
MultiresModifierData *mmd = nullptr;
VirtualModifierData virtualModifierData;
for (md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); md;
md = md->next) {
if (md->type == eModifierType_Multires) {
if (BKE_modifier_is_enabled(nullptr, md, eModifierMode_Realtime)) {
mmd = (MultiresModifierData *)md;
}
}
}
if (!mmd) {
return;
}
multiresModifier_reshapeFromCCG(
sculpt_session->multires.modifier->totlvl, mesh, sculpt_session->subdiv_ccg);

View File

@ -1130,7 +1130,7 @@ static void node_init(const bContext *C, bNodeTree *ntree, bNode *node)
ntype->initfunc(ntree, node);
}
if (ntree->typeinfo->node_add_init != nullptr) {
if (ntree->typeinfo && ntree->typeinfo->node_add_init) {
ntree->typeinfo->node_add_init(ntree, node);
}

View File

@ -340,7 +340,7 @@ static void determine_group_input_states(
}
/* Check if group inputs are required to be single values, because they are (indirectly)
* connected to some socket that does not support fields. */
for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) {
for (const bNode *node : tree.group_input_nodes()) {
for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) {
SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()];
if (state.requires_single) {
@ -349,7 +349,7 @@ static void determine_group_input_states(
}
}
/* If an input does not support fields, this should be reflected in all Group Input nodes. */
for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) {
for (const bNode *node : tree.group_input_nodes()) {
for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) {
SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()];
const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=

View File

@ -75,7 +75,7 @@ static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob,
const SculptAttributeParams *params,
PBVHType pbvhtype,
bool flat_array_for_bmesh);
void sculptsession_bmesh_add_layers(Object *ob);
static void sculptsession_bmesh_add_layers(Object *ob);
using blender::MutableSpan;
using blender::Span;
@ -2454,7 +2454,7 @@ static bool sculpt_attribute_create(SculptSession *ss,
permanent = (out->params.permanent = false);
}
simple_array = (out->params.simple_array = true);
simple_array = true;
}
BLI_assert(!(simple_array && permanent));
@ -2467,6 +2467,7 @@ static bool sculpt_attribute_create(SculptSession *ss,
out->data = MEM_calloc_arrayN(totelem, elemsize, __func__);
out->data_for_bmesh = ss->bm != nullptr;
out->simple_array = true;
out->bmesh_cd_offset = -1;
out->layer = nullptr;
out->elem_size = elemsize;
@ -2476,6 +2477,8 @@ static bool sculpt_attribute_create(SculptSession *ss,
return true;
}
out->simple_array = false;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
CustomData *cdata = nullptr;
@ -2511,8 +2514,6 @@ static bool sculpt_attribute_create(SculptSession *ss,
case PBVH_FACES: {
CustomData *cdata = nullptr;
out->data_for_bmesh = false;
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = &me->vdata;
@ -2534,10 +2535,10 @@ static bool sculpt_attribute_create(SculptSession *ss,
cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
}
out->data = nullptr;
out->layer = cdata->layers + index;
out->bmesh_cd_offset = -1;
out->data = out->layer->data;
out->data_for_bmesh = false;
out->bmesh_cd_offset = -1;
out->elem_size = CustomData_get_elem_size(out->layer);
break;
@ -2565,31 +2566,36 @@ static bool sculpt_attr_update(Object *ob, SculptAttribute *attr)
bool bad = false;
if (attr->params.simple_array) {
if (attr->data) {
bad = attr->elem_num != elem_num;
if (bad) {
MEM_SAFE_FREE(attr->data);
}
else {
attr->data_for_bmesh = false;
}
}
else {
CustomData *cdata = sculpt_get_cdata(ob, attr->domain);
if (cdata) {
int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name);
/* Check if we are a coerced simple array and shouldn't be. */
bad |= attr->simple_array && !attr->params.simple_array &&
!ELEM(BKE_pbvh_type(ss->pbvh), PBVH_GRIDS, PBVH_BMESH);
bad |= (ss->bm != nullptr) != attr->data_for_bmesh;
CustomData *cdata = sculpt_get_cdata(ob, attr->domain);
if (cdata && !attr->simple_array) {
int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name);
bad |= layer_index == -1;
bad |= (ss->bm != nullptr) != attr->data_for_bmesh;
if (!bad) {
if (attr->data_for_bmesh) {
attr->bmesh_cd_offset = cdata->layers[layer_index].offset;
}
else {
attr->data = cdata->layers[layer_index].data;
}
}
}
if (bad) {
if (attr->simple_array) {
MEM_SAFE_FREE(attr->data);
}
sculpt_attribute_create(ss,
ob,
attr->domain,
@ -2598,7 +2604,7 @@ static bool sculpt_attr_update(Object *ob, SculptAttribute *attr)
attr,
&attr->params,
BKE_pbvh_type(ss->pbvh),
true);
attr->data_for_bmesh);
}
return bad;
@ -2724,6 +2730,8 @@ static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob,
SculptAttribute *attr = BKE_sculpt_attribute_get(ob, domain, proptype, name);
if (attr) {
sculpt_attr_update(ob, attr);
return attr;
}
@ -2762,7 +2770,7 @@ static void sculptsession_bmesh_attr_update_internal(Object *ob)
}
}
void sculptsession_bmesh_add_layers(Object *ob)
static void sculptsession_bmesh_add_layers(Object *ob)
{
SculptSession *ss = ob->sculpt;
SculptAttributeParams params = {0};
@ -2869,7 +2877,7 @@ bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr)
Mesh *me = BKE_object_get_original_mesh(ob);
if (attr->params.simple_array) {
if (attr->simple_array) {
MEM_SAFE_FREE(attr->data);
}
else if (ss->bm) {

View File

@ -383,7 +383,8 @@ static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
int gridsize)
int gridsize,
int display_gridsize)
{
const int gridarea = (gridsize - 1) * (gridsize - 1);
int totquad = 0;
@ -391,13 +392,18 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
/* grid hidden layer is present, so have to check each grid for
* visibility */
int depth1 = (int)(log2((double)gridsize - 1.0) + DBL_EPSILON);
int depth2 = (int)(log2((double)display_gridsize - 1.0) + DBL_EPSILON);
int skip = depth2 < depth1 ? 1 << (depth1 - depth2 - 1) : 1;
for (int i = 0; i < totgrid; i++) {
const BLI_bitmap *gh = grid_hidden[grid_indices[i]];
if (gh) {
/* grid hidden are present, have to check each element */
for (int y = 0; y < gridsize - 1; y++) {
for (int x = 0; x < gridsize - 1; x++) {
for (int y = 0; y < gridsize - skip; y += skip) {
for (int x = 0; x < gridsize - skip; x += skip) {
if (!paint_is_grid_face_hidden(gh, gridsize, x, y)) {
totquad++;
}
@ -414,8 +420,11 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
{
int totquads = BKE_pbvh_count_grid_quads(
pbvh->grid_hidden, node->prim_indices, node->totprim, pbvh->gridkey.grid_size);
int totquads = BKE_pbvh_count_grid_quads(pbvh->grid_hidden,
node->prim_indices,
node->totprim,
pbvh->gridkey.grid_size,
pbvh->gridkey.grid_size);
BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
BKE_pbvh_node_mark_rebuild_draw(node);
}

View File

@ -89,7 +89,7 @@ set(SRC
intern/lasso_2d.c
intern/lazy_threading.cc
intern/length_parameterize.cc
intern/listbase.c
intern/listbase.cc
intern/math_base.c
intern/math_base_inline.c
intern/math_base_safe_inline.c

View File

@ -22,56 +22,56 @@
void BLI_movelisttolist(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
if (src->first == nullptr) {
return;
}
if (dst->first == NULL) {
if (dst->first == nullptr) {
dst->first = src->first;
dst->last = src->last;
}
else {
((Link *)dst->last)->next = src->first;
((Link *)src->first)->prev = dst->last;
((Link *)dst->last)->next = static_cast<Link *>(src->first);
((Link *)src->first)->prev = static_cast<Link *>(dst->last);
dst->last = src->last;
}
src->first = src->last = NULL;
src->first = src->last = nullptr;
}
void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
if (src->first == nullptr) {
return;
}
if (dst->first == NULL) {
if (dst->first == nullptr) {
dst->first = src->first;
dst->last = src->last;
}
else {
((Link *)src->last)->next = dst->first;
((Link *)dst->first)->prev = src->last;
((Link *)src->last)->next = static_cast<Link *>(dst->first);
((Link *)dst->first)->prev = static_cast<Link *>(src->last);
dst->first = src->first;
}
src->first = src->last = NULL;
src->first = src->last = nullptr;
}
void BLI_addhead(ListBase *listbase, void *vlink)
{
Link *link = vlink;
Link *link = static_cast<Link *>(vlink);
if (link == NULL) {
if (link == nullptr) {
return;
}
link->next = listbase->first;
link->prev = NULL;
link->next = static_cast<Link *>(listbase->first);
link->prev = nullptr;
if (listbase->first) {
((Link *)listbase->first)->prev = link;
}
if (listbase->last == NULL) {
if (listbase->last == nullptr) {
listbase->last = link;
}
listbase->first = link;
@ -79,19 +79,19 @@ void BLI_addhead(ListBase *listbase, void *vlink)
void BLI_addtail(ListBase *listbase, void *vlink)
{
Link *link = vlink;
Link *link = static_cast<Link *>(vlink);
if (link == NULL) {
if (link == nullptr) {
return;
}
link->next = NULL;
link->prev = listbase->last;
link->next = nullptr;
link->prev = static_cast<Link *>(listbase->last);
if (listbase->last) {
((Link *)listbase->last)->next = link;
}
if (listbase->first == NULL) {
if (listbase->first == nullptr) {
listbase->first = link;
}
listbase->last = link;
@ -99,9 +99,9 @@ void BLI_addtail(ListBase *listbase, void *vlink)
void BLI_remlink(ListBase *listbase, void *vlink)
{
Link *link = vlink;
Link *link = static_cast<Link *>(vlink);
if (link == NULL) {
if (link == nullptr) {
return;
}
@ -132,8 +132,8 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
Link *linkb = vlinkb;
Link *linka = static_cast<Link *>(vlinka);
Link *linkb = static_cast<Link *>(vlinkb);
if (!linka || !linkb) {
return;
@ -185,15 +185,15 @@ void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
Link *linkb = vlinkb;
Link linkc = {NULL};
Link *linka = static_cast<Link *>(vlinka);
Link *linkb = static_cast<Link *>(vlinkb);
Link linkc = {nullptr};
if (!linka || !linkb) {
return;
}
/* The reference to `linkc` assigns NULL, not a dangling pointer so it can be ignored. */
/* The reference to `linkc` assigns nullptr, not a dangling pointer so it can be ignored. */
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 1201 /* gcc12.1+ only */
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdangling-pointer"
@ -221,7 +221,7 @@ void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vli
void *BLI_pophead(ListBase *listbase)
{
Link *link;
if ((link = listbase->first)) {
if ((link = static_cast<Link *>(listbase->first))) {
BLI_remlink(listbase, link);
}
return link;
@ -230,7 +230,7 @@ void *BLI_pophead(ListBase *listbase)
void *BLI_poptail(ListBase *listbase)
{
Link *link;
if ((link = listbase->last)) {
if ((link = static_cast<Link *>(listbase->last))) {
BLI_remlink(listbase, link);
}
return link;
@ -238,9 +238,9 @@ void *BLI_poptail(ListBase *listbase)
void BLI_freelinkN(ListBase *listbase, void *vlink)
{
Link *link = vlink;
Link *link = static_cast<Link *>(vlink);
if (link == NULL) {
if (link == nullptr) {
return;
}
@ -253,7 +253,7 @@ void BLI_freelinkN(ListBase *listbase, void *vlink)
*/
static void listbase_double_from_single(Link *iter, ListBase *listbase)
{
Link *prev = NULL;
Link *prev = nullptr;
listbase->first = iter;
do {
iter->prev = prev;
@ -281,7 +281,7 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
{
if (listbase->first != listbase->last) {
Link *head = listbase->first;
Link *head = static_cast<Link *>(listbase->first);
head = listbase_sort_fn(head, cmp);
listbase_double_from_single(head, listbase);
}
@ -292,7 +292,7 @@ void BLI_listbase_sort_r(ListBase *listbase,
void *thunk)
{
if (listbase->first != listbase->last) {
Link *head = listbase->first;
Link *head = static_cast<Link *>(listbase->first);
head = listbase_sort_fn_r(head, cmp, thunk);
listbase_double_from_single(head, listbase);
}
@ -300,25 +300,25 @@ void BLI_listbase_sort_r(ListBase *listbase,
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
{
Link *prevlink = vprevlink;
Link *newlink = vnewlink;
Link *prevlink = static_cast<Link *>(vprevlink);
Link *newlink = static_cast<Link *>(vnewlink);
/* newlink before nextlink */
if (newlink == NULL) {
if (newlink == nullptr) {
return;
}
/* empty list */
if (listbase->first == NULL) {
if (listbase->first == nullptr) {
listbase->first = newlink;
listbase->last = newlink;
return;
}
/* insert at head of list */
if (prevlink == NULL) {
newlink->prev = NULL;
newlink->next = listbase->first;
if (prevlink == nullptr) {
newlink->prev = nullptr;
newlink->next = static_cast<Link *>(listbase->first);
newlink->next->prev = newlink;
listbase->first = newlink;
return;
@ -339,25 +339,25 @@ void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
{
Link *nextlink = vnextlink;
Link *newlink = vnewlink;
Link *nextlink = static_cast<Link *>(vnextlink);
Link *newlink = static_cast<Link *>(vnewlink);
/* newlink before nextlink */
if (newlink == NULL) {
if (newlink == nullptr) {
return;
}
/* empty list */
if (listbase->first == NULL) {
if (listbase->first == nullptr) {
listbase->first = newlink;
listbase->last = newlink;
return;
}
/* insert at end of list */
if (nextlink == NULL) {
newlink->prev = listbase->last;
newlink->next = NULL;
if (nextlink == nullptr) {
newlink->prev = static_cast<Link *>(listbase->last);
newlink->next = nullptr;
((Link *)listbase->last)->next = newlink;
listbase->last = newlink;
return;
@ -378,14 +378,14 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
{
Link *l_old = vreplacelink;
Link *l_new = vnewlink;
Link *l_old = static_cast<Link *>(vreplacelink);
Link *l_new = static_cast<Link *>(vnewlink);
/* update adjacent links */
if (l_old->next != NULL) {
if (l_old->next != nullptr) {
l_old->next->prev = l_new;
}
if (l_old->prev != NULL) {
if (l_old->prev != nullptr) {
l_old->prev->next = l_new;
}
@ -404,7 +404,7 @@ void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlin
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
{
Link *link = vlink;
Link *link = static_cast<Link *>(vlink);
Link *hook = link;
const bool is_up = step < 0;
@ -453,7 +453,7 @@ void BLI_freelist(ListBase *listbase)
{
Link *link, *next;
link = listbase->first;
link = static_cast<Link *>(listbase->first);
while (link) {
next = link->next;
free(link);
@ -467,7 +467,7 @@ void BLI_freelistN(ListBase *listbase)
{
Link *link, *next;
link = listbase->first;
link = static_cast<Link *>(listbase->first);
while (link) {
next = link->next;
MEM_freeN(link);
@ -482,7 +482,8 @@ int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
Link *link;
int count = 0;
for (link = listbase->first; link && count != count_max; link = link->next) {
for (link = static_cast<Link *>(listbase->first); link && count != count_max;
link = link->next) {
count++;
}
@ -494,7 +495,7 @@ int BLI_listbase_count(const ListBase *listbase)
Link *link;
int count = 0;
for (link = listbase->first; link; link = link->next) {
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
count++;
}
@ -503,11 +504,11 @@ int BLI_listbase_count(const ListBase *listbase)
void *BLI_findlink(const ListBase *listbase, int number)
{
Link *link = NULL;
Link *link = nullptr;
if (number >= 0) {
link = listbase->first;
while (link != NULL && number != 0) {
link = static_cast<Link *>(listbase->first);
while (link != nullptr && number != 0) {
number--;
link = link->next;
}
@ -518,11 +519,11 @@ void *BLI_findlink(const ListBase *listbase, int number)
void *BLI_rfindlink(const ListBase *listbase, int number)
{
Link *link = NULL;
Link *link = nullptr;
if (number >= 0) {
link = listbase->last;
while (link != NULL && number != 0) {
link = static_cast<Link *>(listbase->last);
while (link != nullptr && number != 0) {
number--;
link = link->prev;
}
@ -533,11 +534,11 @@ void *BLI_rfindlink(const ListBase *listbase, int number)
void *BLI_findlinkfrom(Link *start, int number)
{
Link *link = NULL;
Link *link = nullptr;
if (number >= 0) {
link = start;
while (link != NULL && number != 0) {
while (link != nullptr && number != 0) {
number--;
link = link->next;
}
@ -548,14 +549,14 @@ void *BLI_findlinkfrom(Link *start, int number)
int BLI_findindex(const ListBase *listbase, const void *vlink)
{
Link *link = NULL;
Link *link = nullptr;
int number = 0;
if (vlink == NULL) {
if (vlink == nullptr) {
return -1;
}
link = listbase->first;
link = static_cast<Link *>(listbase->first);
while (link) {
if (link == vlink) {
return number;
@ -570,14 +571,14 @@ int BLI_findindex(const ListBase *listbase, const void *vlink)
void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
Link *link = nullptr;
const char *id_iter;
if (id == NULL) {
return NULL;
if (id == nullptr) {
return nullptr;
}
for (link = listbase->first; link; link = link->next) {
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
id_iter = ((const char *)link) + offset;
if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
@ -585,16 +586,16 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
}
}
return NULL;
return nullptr;
}
void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
{
/* Same as #BLI_findstring but find reverse. */
Link *link = NULL;
Link *link = nullptr;
const char *id_iter;
for (link = listbase->last; link; link = link->prev) {
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
id_iter = ((const char *)link) + offset;
if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
@ -602,15 +603,15 @@ void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset
}
}
return NULL;
return nullptr;
}
void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
Link *link = nullptr;
const char *id_iter;
for (link = listbase->first; link; link = link->next) {
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
/* exact copy of BLI_findstring(), except for this line */
id_iter = *((const char **)(((const char *)link) + offset));
@ -619,16 +620,16 @@ void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int off
}
}
return NULL;
return nullptr;
}
void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
/* Same as #BLI_findstring_ptr but find reverse. */
Link *link = NULL;
Link *link = nullptr;
const char *id_iter;
for (link = listbase->last; link; link = link->prev) {
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
/* exact copy of BLI_rfindstring(), except for this line */
id_iter = *((const char **)(((const char *)link) + offset));
@ -637,15 +638,15 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
}
}
return NULL;
return nullptr;
}
void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
{
Link *link = NULL;
Link *link = nullptr;
const void *ptr_iter;
for (link = listbase->first; link; link = link->next) {
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
/* exact copy of BLI_findstring(), except for this line */
ptr_iter = *((const void **)(((const char *)link) + offset));
@ -654,16 +655,16 @@ void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
}
}
return NULL;
return nullptr;
}
void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
{
/* Same as #BLI_findptr but find reverse. */
Link *link = NULL;
Link *link = nullptr;
const void *ptr_iter;
for (link = listbase->last; link; link = link->prev) {
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
/* exact copy of BLI_rfindstring(), except for this line */
ptr_iter = *((const void **)(((const char *)link) + offset));
@ -672,7 +673,7 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
}
}
return NULL;
return nullptr;
}
void *BLI_listbase_bytes_find(const ListBase *listbase,
@ -680,10 +681,10 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
const size_t bytes_size,
const int offset)
{
Link *link = NULL;
Link *link = nullptr;
const void *ptr_iter;
for (link = listbase->first; link; link = link->next) {
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
ptr_iter = (const void *)(((const char *)link) + offset);
if (memcmp(bytes, ptr_iter, bytes_size) == 0) {
@ -691,7 +692,7 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
}
}
return NULL;
return nullptr;
}
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
@ -700,10 +701,10 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
{
/* Same as #BLI_listbase_bytes_find but find reverse. */
Link *link = NULL;
Link *link = nullptr;
const void *ptr_iter;
for (link = listbase->last; link; link = link->prev) {
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
ptr_iter = (const void *)(((const char *)link) + offset);
if (memcmp(bytes, ptr_iter, bytes_size) == 0) {
@ -711,7 +712,7 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
}
}
return NULL;
return nullptr;
}
void *BLI_listbase_string_or_index_find(const ListBase *listbase,
@ -719,12 +720,13 @@ void *BLI_listbase_string_or_index_find(const ListBase *listbase,
const size_t string_offset,
const int index)
{
Link *link = NULL;
Link *link_at_index = NULL;
Link *link = nullptr;
Link *link_at_index = nullptr;
int index_iter;
for (link = listbase->first, index_iter = 0; link; link = link->next, index_iter++) {
if (string != NULL && string[0] != '\0') {
for (link = static_cast<Link *>(listbase->first), index_iter = 0; link;
link = link->next, index_iter++) {
if (string != nullptr && string[0] != '\0') {
const char *string_iter = ((const char *)link) + string_offset;
if (string[0] == string_iter[0] && STREQ(string, string_iter)) {
@ -740,11 +742,11 @@ void *BLI_listbase_string_or_index_find(const ListBase *listbase,
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
Link *link = nullptr;
const char *id_iter;
int i = 0;
link = listbase->first;
link = static_cast<Link *>(listbase->first);
while (link) {
id_iter = ((const char *)link) + offset;
@ -761,17 +763,17 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
ListBase BLI_listbase_from_link(Link *some_link)
{
ListBase list = {some_link, some_link};
if (some_link == NULL) {
if (some_link == nullptr) {
return list;
}
/* Find the first element. */
while (((Link *)list.first)->prev != NULL) {
while (((Link *)list.first)->prev != nullptr) {
list.first = ((Link *)list.first)->prev;
}
/* Find the last element. */
while (((Link *)list.last)->next != NULL) {
while (((Link *)list.last)->next != nullptr) {
list.last = ((Link *)list.last)->next;
}
@ -783,11 +785,11 @@ void BLI_duplicatelist(ListBase *dst, const ListBase *src)
struct Link *dst_link, *src_link;
/* in this order, to ensure it works if dst == src */
src_link = src->first;
dst->first = dst->last = NULL;
src_link = static_cast<Link *>(src->first);
dst->first = dst->last = nullptr;
while (src_link) {
dst_link = MEM_dupallocN(src_link);
dst_link = static_cast<Link *>(MEM_dupallocN(src_link));
BLI_addtail(dst, dst_link);
src_link = src_link->next;
@ -796,9 +798,9 @@ void BLI_duplicatelist(ListBase *dst, const ListBase *src)
void BLI_listbase_reverse(ListBase *lb)
{
struct Link *curr = lb->first;
struct Link *prev = NULL;
struct Link *next = NULL;
struct Link *curr = static_cast<Link *>(lb->first);
struct Link *prev = nullptr;
struct Link *next = nullptr;
while (curr) {
next = curr->next;
curr->next = prev;
@ -808,7 +810,7 @@ void BLI_listbase_reverse(ListBase *lb)
}
/* swap first/last */
curr = lb->first;
curr = static_cast<Link *>(lb->first);
lb->first = lb->last;
lb->last = curr;
}
@ -816,39 +818,39 @@ void BLI_listbase_reverse(ListBase *lb)
void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
{
/* make circular */
((Link *)lb->first)->prev = lb->last;
((Link *)lb->last)->next = lb->first;
((Link *)lb->first)->prev = static_cast<Link *>(lb->last);
((Link *)lb->last)->next = static_cast<Link *>(lb->first);
lb->first = vlink;
lb->last = ((Link *)vlink)->prev;
((Link *)lb->first)->prev = NULL;
((Link *)lb->last)->next = NULL;
((Link *)lb->first)->prev = nullptr;
((Link *)lb->last)->next = nullptr;
}
void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
{
/* make circular */
((Link *)lb->first)->prev = lb->last;
((Link *)lb->last)->next = lb->first;
((Link *)lb->first)->prev = static_cast<Link *>(lb->last);
((Link *)lb->last)->next = static_cast<Link *>(lb->first);
lb->first = ((Link *)vlink)->next;
lb->last = vlink;
((Link *)lb->first)->prev = NULL;
((Link *)lb->last)->next = NULL;
((Link *)lb->first)->prev = nullptr;
((Link *)lb->last)->next = nullptr;
}
LinkData *BLI_genericNodeN(void *data)
{
LinkData *ld;
if (data == NULL) {
return NULL;
if (data == nullptr) {
return nullptr;
}
/* create new link, and make it hold the given data */
ld = MEM_callocN(sizeof(LinkData), __func__);
ld = MEM_cnew<LinkData>(__func__);
ld->data = data;
return ld;

View File

@ -823,6 +823,99 @@ static void version_geometry_nodes_replace_transfer_attribute_node(bNodeTree *nt
}
}
/**
* The mesh primitive nodes created a uv map with a hardcoded name. Now they are outputting the uv
* map as a socket instead. The versioning just inserts a Store Named Attribute node after
* primitive nodes.
*/
static void version_geometry_nodes_primitive_uv_maps(bNodeTree &ntree)
{
blender::Vector<bNode *> new_nodes;
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
if (!ELEM(node->type,
GEO_NODE_MESH_PRIMITIVE_CONE,
GEO_NODE_MESH_PRIMITIVE_CUBE,
GEO_NODE_MESH_PRIMITIVE_CYLINDER,
GEO_NODE_MESH_PRIMITIVE_GRID,
GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE,
GEO_NODE_MESH_PRIMITIVE_UV_SPHERE)) {
continue;
}
bNodeSocket *primitive_output_socket = nullptr;
bNodeSocket *uv_map_output_socket = nullptr;
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
if (STREQ(socket->name, "UV Map")) {
uv_map_output_socket = socket;
}
if (socket->type == SOCK_GEOMETRY) {
primitive_output_socket = socket;
}
}
if (uv_map_output_socket != nullptr) {
continue;
}
uv_map_output_socket = nodeAddStaticSocket(
&ntree, node, SOCK_OUT, SOCK_VECTOR, PROP_NONE, "UV Map", "UV Map");
bNode *store_attribute_node = nodeAddStaticNode(
nullptr, &ntree, GEO_NODE_STORE_NAMED_ATTRIBUTE);
new_nodes.append(store_attribute_node);
store_attribute_node->parent = node->parent;
store_attribute_node->locx = node->locx + 25;
store_attribute_node->locy = node->locy;
store_attribute_node->offsetx = node->offsetx;
store_attribute_node->offsety = node->offsety;
NodeGeometryStoreNamedAttribute &storage = *static_cast<NodeGeometryStoreNamedAttribute *>(
store_attribute_node->storage);
storage.domain = ATTR_DOMAIN_CORNER;
/* Intentionally use 3D instead of 2D vectors, because 2D vectors did not exist in older
* releases and would make the file crash when trying to open it. */
storage.data_type = CD_PROP_FLOAT3;
bNodeSocket *store_attribute_geometry_input = static_cast<bNodeSocket *>(
store_attribute_node->inputs.first);
bNodeSocket *store_attribute_name_input = store_attribute_geometry_input->next;
bNodeSocket *store_attribute_value_input = nullptr;
LISTBASE_FOREACH (bNodeSocket *, socket, &store_attribute_node->inputs) {
if (socket->type == SOCK_VECTOR) {
store_attribute_value_input = socket;
break;
}
}
bNodeSocket *store_attribute_geometry_output = static_cast<bNodeSocket *>(
store_attribute_node->outputs.first);
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (link->fromsock == primitive_output_socket) {
link->fromnode = store_attribute_node;
link->fromsock = store_attribute_geometry_output;
}
}
bNodeSocketValueString *name_value = static_cast<bNodeSocketValueString *>(
store_attribute_name_input->default_value);
const char *uv_map_name = node->type == GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE ? "UVMap" :
"uv_map";
BLI_strncpy(name_value->value, uv_map_name, sizeof(name_value->value));
nodeAddLink(&ntree,
node,
primitive_output_socket,
store_attribute_node,
store_attribute_geometry_input);
nodeAddLink(
&ntree, node, uv_map_output_socket, store_attribute_node, store_attribute_value_input);
}
/* Move nodes to the front so that they are drawn behind existing nodes. */
for (bNode *node : new_nodes) {
BLI_remlink(&ntree.nodes, node);
BLI_addhead(&ntree.nodes, node);
}
if (!new_nodes.is_empty()) {
nodeRebuildIDVector(&ntree);
}
}
void do_versions_after_linking_300(Main *bmain, ReportList * /*reports*/)
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@ -3708,18 +3801,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
if (!MAIN_VERSION_ATLEAST(bmain, 305, 4)) {
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type == NTREE_GEOMETRY) {
version_node_socket_name(ntree, GEO_NODE_COLLECTION_INFO, "Geometry", "Instances");
@ -3732,5 +3814,24 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
image->seam_margin = 8;
}
}
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type == NTREE_GEOMETRY) {
version_geometry_nodes_primitive_uv_maps(*ntree);
}
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
}
}

View File

@ -86,12 +86,14 @@ struct GPUBatch *DRW_pbvh_tris_get(PBVHBatches *batches,
struct PBVHAttrReq *attrs,
int attrs_num,
PBVH_GPU_Args *args,
int *r_prim_count);
int *r_prim_count,
bool do_coarse_grids);
struct GPUBatch *DRW_pbvh_lines_get(struct PBVHBatches *batches,
struct PBVHAttrReq *attrs,
int attrs_num,
PBVH_GPU_Args *args,
int *r_prim_count);
int *r_prim_count,
bool do_coarse_grids);
#ifdef __cplusplus
}

View File

@ -1552,7 +1552,8 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob)
const bool is_select_mode = DRW_state_is_select();
const bool is_paint_mode = (draw_ctx->object_mode &
(OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) != 0;
(OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL |
OB_MODE_SCULPT_CURVES)) != 0;
const bool from_dupli = (ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) != 0;
const bool has_bounds = !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE);
const bool has_texspace = has_bounds &&

View File

@ -97,11 +97,13 @@ BLI_INLINE void workbench_material_get_image(
case SH_NODE_TEX_IMAGE: {
const NodeTexImage *storage = static_cast<NodeTexImage *>(node->storage);
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
const bool use_repeat = (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
const bool use_mirror = (storage->extension == SHD_IMAGE_EXTENSION_MIRROR);
const bool use_repeat = use_mirror || (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
const bool use_clip = (storage->extension == SHD_IMAGE_EXTENSION_CLIP);
SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
SET_FLAG_FROM_TEST(*r_sampler, use_repeat, GPU_SAMPLER_REPEAT);
SET_FLAG_FROM_TEST(*r_sampler, use_clip, GPU_SAMPLER_CLAMP_BORDER);
SET_FLAG_FROM_TEST(*r_sampler, use_mirror, GPU_SAMPLER_MIRROR_REPEAT);
break;
}
case SH_NODE_TEX_ENVIRONMENT: {

View File

@ -1220,10 +1220,12 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd,
GPUBatch *geom;
if (!scd->use_wire) {
geom = DRW_pbvh_tris_get(batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount);
geom = DRW_pbvh_tris_get(
batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount, scd->fast_mode);
}
else {
geom = DRW_pbvh_lines_get(batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount);
geom = DRW_pbvh_lines_get(
batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount, scd->fast_mode);
}
short index = 0;

View File

@ -66,6 +66,22 @@ using blender::Vector;
using string = std::string;
static bool valid_pbvh_attr(int type)
{
switch (type) {
case CD_PBVH_CO_TYPE:
case CD_PBVH_NO_TYPE:
case CD_PBVH_FSET_TYPE:
case CD_PBVH_MASK_TYPE:
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR:
case CD_MLOOPUV:
return true;
}
return false;
}
struct PBVHVbo {
uint64_t type;
eAttrDomain domain;
@ -99,6 +115,8 @@ struct PBVHBatch {
string key;
GPUBatch *tris = nullptr, *lines = nullptr;
int tris_count = 0, lines_count = 0;
bool is_coarse =
false; /* Coarse multires, will use full-sized VBOs only index buffer changes. */
void sort_vbos(Vector<PBVHVbo> &master_vbos)
{
@ -122,6 +140,10 @@ struct PBVHBatch {
{
key = "";
if (is_coarse) {
key += "c:";
}
sort_vbos(master_vbos);
for (int vbo_i : vbos) {
@ -157,6 +179,12 @@ struct PBVHBatches {
int material_index = 0;
/* Stuff for displaying coarse multires grids. */
GPUIndexBuf *tri_index_coarse = nullptr;
GPUIndexBuf *lines_index_coarse = nullptr;
int coarse_level = 0; /* Coarse multires depth. */
int tris_count_coarse = 0, lines_count_coarse = 0;
int count_faces(PBVH_GPU_Args *args)
{
int count = 0;
@ -178,6 +206,7 @@ struct PBVHBatches {
count = BKE_pbvh_count_grid_quads((BLI_bitmap **)args->grid_hidden,
args->grid_indices,
args->totprim,
args->ccg_key.grid_size,
args->ccg_key.grid_size);
break;
@ -217,9 +246,11 @@ struct PBVHBatches {
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
}
string build_key(PBVHAttrReq *attrs, int attrs_num)
string build_key(PBVHAttrReq *attrs, int attrs_num, bool do_coarse_grids)
{
string key;
PBVHBatch batch;
@ -228,6 +259,10 @@ struct PBVHBatches {
for (int i : IndexRange(attrs_num)) {
PBVHAttrReq *attr = attrs + i;
if (!valid_pbvh_attr(attr->type)) {
continue;
}
PBVHVbo vbo(attr->domain, attr->type, string(attr->name));
vbo.build_key();
@ -235,6 +270,7 @@ struct PBVHBatches {
batch.vbos.append(i);
}
batch.is_coarse = do_coarse_grids;
batch.build_key(vbos);
return batch.key;
}
@ -272,18 +308,21 @@ struct PBVHBatches {
return nullptr;
}
bool has_batch(PBVHAttrReq *attrs, int attrs_num)
bool has_batch(PBVHAttrReq *attrs, int attrs_num, bool do_coarse_grids)
{
return batches.contains(build_key(attrs, attrs_num));
return batches.contains(build_key(attrs, attrs_num, do_coarse_grids));
}
PBVHBatch &ensure_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args)
PBVHBatch &ensure_batch(PBVHAttrReq *attrs,
int attrs_num,
PBVH_GPU_Args *args,
bool do_coarse_grids)
{
if (!has_batch(attrs, attrs_num)) {
create_batch(attrs, attrs_num, args);
if (!has_batch(attrs, attrs_num, do_coarse_grids)) {
create_batch(attrs, attrs_num, args, do_coarse_grids);
}
return batches.lookup(build_key(attrs, attrs_num));
return batches.lookup(build_key(attrs, attrs_num, do_coarse_grids));
}
void fill_vbo_normal_faces(
@ -484,9 +523,12 @@ struct PBVHBatches {
for (int x = 0; x < gridsize; x++) {
CCGElem *elems[4] = {
CCG_grid_elem(&args->ccg_key, grid, x, y),
CCG_grid_elem(&args->ccg_key, grid, x + 1, y),
CCG_grid_elem(&args->ccg_key, grid, x + 1, y + 1),
CCG_grid_elem(&args->ccg_key, grid, x, y + 1),
CCG_grid_elem(&args->ccg_key, grid, min_ii(x + 1, gridsize - 1), y),
CCG_grid_elem(&args->ccg_key,
grid,
min_ii(x + 1, gridsize - 1),
min_ii(y + 1, gridsize - 1)),
CCG_grid_elem(&args->ccg_key, grid, x, min_ii(y + 1, gridsize - 1)),
};
func(x, y, grid_index, elems, 0);
@ -858,10 +900,10 @@ struct PBVHBatches {
break;
}
default:
BLI_assert(0);
printf("%s: error\n", __func__);
printf("%s: Unsupported attribute type %u\n", __func__, type);
BLI_assert_unreachable();
break;
return;
}
if (need_aliases) {
@ -944,8 +986,10 @@ struct PBVHBatches {
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
tri_index = lines_index = nullptr;
tri_index = lines_index = tri_index_coarse = lines_index_coarse = nullptr;
faces_count = tris_count = count;
}
}
@ -1041,7 +1085,7 @@ struct PBVHBatches {
lines_index = GPU_indexbuf_build(&elb_lines);
}
void create_index_grids(PBVH_GPU_Args *args)
void create_index_grids(PBVH_GPU_Args *args, bool do_coarse)
{
int *mat_index = static_cast<int *>(
CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index"));
@ -1053,15 +1097,24 @@ struct PBVHBatches {
needs_tri_index = true;
int gridsize = args->ccg_key.grid_size;
int display_gridsize = gridsize;
int totgrid = args->totprim;
int skip = 1;
const int display_level = do_coarse ? coarse_level : args->ccg_key.level;
if (display_level < args->ccg_key.level) {
display_gridsize = (1 << display_level) + 1;
skip = 1 << (args->ccg_key.level - display_level - 1);
}
for (int i : IndexRange(args->totprim)) {
int grid_index = args->grid_indices[i];
bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH;
BLI_bitmap *gh = args->grid_hidden[grid_index];
for (int y = 0; y < gridsize - 1; y++) {
for (int x = 0; x < gridsize - 1; x++) {
for (int y = 0; y < gridsize - 1; y += skip) {
for (int x = 0; x < gridsize - 1; x += skip) {
if (gh && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
/* Skip hidden faces by just setting smooth to true. */
smooth = true;
@ -1082,12 +1135,17 @@ struct PBVHBatches {
CCGKey *key = &args->ccg_key;
uint visible_quad_len = BKE_pbvh_count_grid_quads(
(BLI_bitmap **)args->grid_hidden, args->grid_indices, totgrid, key->grid_size);
uint visible_quad_len = BKE_pbvh_count_grid_quads((BLI_bitmap **)args->grid_hidden,
args->grid_indices,
totgrid,
key->grid_size,
display_gridsize);
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX);
GPU_indexbuf_init(
&elb_lines, GPU_PRIM_LINES, 2 * totgrid * gridsize * (gridsize - 1), INT_MAX);
GPU_indexbuf_init(&elb_lines,
GPU_PRIM_LINES,
2 * totgrid * display_gridsize * (display_gridsize - 1),
INT_MAX);
if (needs_tri_index) {
uint offset = 0;
@ -1098,17 +1156,17 @@ struct PBVHBatches {
BLI_bitmap *gh = args->grid_hidden[args->grid_indices[i]];
for (int j = 0; j < gridsize - 1; j++) {
for (int k = 0; k < gridsize - 1; k++) {
for (int j = 0; j < gridsize - skip; j += skip) {
for (int k = 0; k < gridsize - skip; k += skip) {
/* Skip hidden grid face */
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
continue;
}
/* Indices in a Clockwise QUAD disposition. */
v0 = offset + j * gridsize + k;
v1 = v0 + 1;
v2 = v1 + gridsize;
v3 = v2 - 1;
v1 = offset + j * gridsize + k + skip;
v2 = offset + (j + skip) * gridsize + k + skip;
v3 = offset + (j + skip) * gridsize + k;
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
@ -1116,7 +1174,7 @@ struct PBVHBatches {
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
if (j + 2 == gridsize) {
if (j / skip + 2 == display_gridsize) {
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
}
grid_visible = true;
@ -1131,22 +1189,38 @@ struct PBVHBatches {
else {
uint offset = 0;
const uint grid_vert_len = square_uint(gridsize - 1) * 4;
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
bool grid_visible = false;
BLI_bitmap *gh = args->grid_hidden[args->grid_indices[i]];
uint v0, v1, v2, v3;
for (int j = 0; j < gridsize - 1; j++) {
for (int k = 0; k < gridsize - 1; k++) {
for (int j = 0; j < gridsize - skip; j += skip) {
for (int k = 0; k < gridsize - skip; k += skip) {
/* Skip hidden grid face */
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
continue;
}
/* VBO data are in a Clockwise QUAD disposition. */
v0 = offset + (j * (gridsize - 1) + k) * 4;
v1 = v0 + 1;
v2 = v0 + 2;
v3 = v0 + 3;
v0 = (j * (gridsize - 1) + k) * 4;
if (skip > 1) {
v1 = (j * (gridsize - 1) + k + skip - 1) * 4;
v2 = ((j + skip - 1) * (gridsize - 1) + k + skip - 1) * 4;
v3 = ((j + skip - 1) * (gridsize - 1) + k) * 4;
}
else {
v1 = v2 = v3 = v0;
}
/* VBO data are in a Clockwise QUAD disposition. Note
* that vertices might be in different quads if we're
* building a coarse index buffer.
*/
v0 += offset;
v1 += offset + 1;
v2 += offset + 2;
v3 += offset + 3;
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
@ -1154,7 +1228,7 @@ struct PBVHBatches {
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
if (j + 2 == gridsize) {
if ((j / skip) + 2 == display_gridsize) {
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
}
grid_visible = true;
@ -1167,8 +1241,16 @@ struct PBVHBatches {
}
}
tri_index = GPU_indexbuf_build(&elb);
lines_index = GPU_indexbuf_build(&elb_lines);
if (do_coarse) {
tri_index_coarse = GPU_indexbuf_build(&elb);
lines_index_coarse = GPU_indexbuf_build(&elb_lines);
tris_count_coarse = visible_quad_len;
lines_count_coarse = totgrid * display_gridsize * (display_gridsize - 1);
}
else {
tri_index = GPU_indexbuf_build(&elb);
lines_index = GPU_indexbuf_build(&elb_lines);
}
}
void create_index(PBVH_GPU_Args *args)
@ -1181,7 +1263,12 @@ struct PBVHBatches {
create_index_bmesh(args);
break;
case PBVH_GRIDS:
create_index_grids(args);
create_index_grids(args, false);
if (args->ccg_key.level > coarse_level) {
create_index_grids(args, true);
}
break;
}
@ -1207,7 +1294,7 @@ struct PBVHBatches {
}
}
void create_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args)
void create_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args, bool do_coarse_grids)
{
check_index_buffers(args);
@ -1216,17 +1303,23 @@ struct PBVHBatches {
batch.tris = GPU_batch_create(GPU_PRIM_TRIS,
nullptr,
/* can be nullptr if buffer is empty */
tri_index);
batch.tris_count = tris_count;
do_coarse_grids ? tri_index_coarse : tri_index);
batch.tris_count = do_coarse_grids ? tris_count_coarse : tris_count;
batch.is_coarse = do_coarse_grids;
if (lines_index) {
batch.lines = GPU_batch_create(GPU_PRIM_LINES, nullptr, lines_index);
batch.lines_count = lines_count;
batch.lines = GPU_batch_create(
GPU_PRIM_LINES, nullptr, do_coarse_grids ? lines_index_coarse : lines_index);
batch.lines_count = do_coarse_grids ? lines_count_coarse : lines_count;
}
for (int i : IndexRange(attrs_num)) {
PBVHAttrReq *attr = attrs + i;
if (!valid_pbvh_attr(attr->type)) {
continue;
}
if (!has_vbo(attr->domain, int(attr->type), attr->name)) {
create_vbo(attr->domain, uint32_t(attr->type), attr->name, args);
}
@ -1272,9 +1365,12 @@ GPUBatch *DRW_pbvh_tris_get(PBVHBatches *batches,
PBVHAttrReq *attrs,
int attrs_num,
PBVH_GPU_Args *args,
int *r_prim_count)
int *r_prim_count,
bool do_coarse_grids)
{
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args);
do_coarse_grids &= args->pbvh_type == PBVH_GRIDS;
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args, do_coarse_grids);
*r_prim_count = batch.tris_count;
@ -1285,9 +1381,12 @@ GPUBatch *DRW_pbvh_lines_get(PBVHBatches *batches,
PBVHAttrReq *attrs,
int attrs_num,
PBVH_GPU_Args *args,
int *r_prim_count)
int *r_prim_count,
bool do_coarse_grids)
{
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args);
do_coarse_grids &= args->pbvh_type == PBVH_GRIDS;
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args, do_coarse_grids);
*r_prim_count = batch.lines_count;

View File

@ -59,7 +59,7 @@ static bool is_cursor_visible(const DRWContextState *draw_ctx, Scene *scene, Vie
}
/* don't draw cursor in paint modes, but with a few exceptions */
if (draw_ctx->object_mode & OB_MODE_ALL_PAINT) {
if ((draw_ctx->object_mode & (OB_MODE_ALL_PAINT | OB_MODE_SCULPT_CURVES)) != 0) {
/* exception: object is in weight paint and has deforming armature in pose mode */
if (draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) {
if (BKE_object_pose_armature_get(draw_ctx->obact) != NULL) {

View File

@ -6,7 +6,6 @@
#include <string>
#include "AS_asset_identifier.hh"
#include "AS_asset_representation.h"
#include "AS_asset_representation.hh"
@ -15,7 +14,6 @@
#include "BLO_readfile.h"
#include "ED_asset_handle.h"
#include "ED_asset_list.hh"
#include "WM_api.h"

View File

@ -26,7 +26,6 @@
#include "BKE_appdir.h"
#include "BKE_asset.h"
#include "BKE_idprop.hh"
#include "BKE_preferences.h"
#include "CLG_log.h"

View File

@ -15,7 +15,6 @@
#include "BKE_context.h"
#include "BLI_map.hh"
#include "BLI_path_util.h"
#include "BLI_utility_mixins.hh"
#include "DNA_space_types.h"
@ -112,6 +111,7 @@ class AssetList : NonCopyable {
void clear(bContext *C);
bool needsRefetch() const;
bool isLoaded() const;
void iterate(AssetListIterFn fn) const;
bool listen(const wmNotifier &notifier) const;
int size() const;
@ -190,6 +190,11 @@ bool AssetList::needsRefetch() const
return filelist_needs_force_reset(filelist_) || filelist_needs_reading(filelist_);
}
bool AssetList::isLoaded() const
{
return filelist_is_ready(filelist_);
}
void AssetList::iterate(AssetListIterFn fn) const
{
FileList *files = filelist_;
@ -423,7 +428,7 @@ bool ED_assetlist_is_loaded(const AssetLibraryReference *library_reference)
if (list->needsRefetch()) {
return false;
}
return true;
return list->isLoaded();
}
void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference,

View File

@ -9,13 +9,12 @@
#include "BKE_bpath.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_preferences.h"
#include "BKE_report.h"
#include "BLI_fileops.h"
#include "BLI_fileops.h" /* MSVC needs this for `PATH_MAX` */
#include "BLI_fnmatch.h"
#include "BLI_path_util.h"
#include "BLI_set.hh"
@ -37,8 +36,6 @@
#include "DNA_space_types.h"
#include "BLO_writefile.h"
using namespace blender;
/* -------------------------------------------------------------------- */

View File

@ -581,6 +581,12 @@ void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, c
*/
struct Mesh *ED_mesh_context(struct bContext *C);
/**
* Split all edges that would appear sharp based onface and edge sharpness tags and the auto smooth
* angle.
*/
void ED_mesh_split_faces(struct Mesh *mesh);
/* mesh backup */
typedef struct BMBackup {
struct BMesh *bmcopy;

View File

@ -10,6 +10,7 @@ set(INC
../../bmesh
../../depsgraph
../../draw
../../geometry
../../gpu
../../imbuf
../../makesdna
@ -76,6 +77,17 @@ if(WITH_GMP)
add_definitions(-DWITH_GMP)
endif()
if(WITH_TBB)
add_definitions(-DWITH_TBB)
list(APPEND INC_SYS
${TBB_INCLUDE_DIRS}
)
list(APPEND LIB
${TBB_LIBRARIES}
)
endif()
blender_add_lib(bf_editor_mesh "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -14,6 +14,7 @@
#include "DNA_view3d_types.h"
#include "BLI_array.hh"
#include "BLI_index_mask_ops.hh"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@ -42,6 +43,8 @@
#include "ED_uvedit.h"
#include "ED_view3d.h"
#include "GEO_mesh_split_edges.hh"
#include "mesh_intern.h" /* own include */
using blender::Array;
@ -1464,3 +1467,43 @@ Mesh *ED_mesh_context(bContext *C)
return (Mesh *)data;
}
void ED_mesh_split_faces(Mesh *mesh)
{
using namespace blender;
Array<MEdge> edges(mesh->edges());
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : float(M_PI);
BKE_edges_sharp_from_angle_set(edges.data(),
edges.size(),
loops.data(),
loops.size(),
polys.data(),
BKE_mesh_poly_normals_ensure(mesh),
polys.size(),
split_angle);
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int poly_i : range) {
const MPoly &poly = polys[poly_i];
if (!(poly.flag & ME_SMOOTH)) {
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
edges[loop.e].flag |= ME_SHARP;
}
}
}
});
Vector<int64_t> split_indices;
const IndexMask split_mask = index_mask_ops::find_indices_based_on_predicate(
edges.index_range(), 4096, split_indices, [&](const int64_t i) {
return edges[i].flag & ME_SHARP;
});
if (split_mask.is_empty()) {
return;
}
geometry::split_edges(*mesh, split_mask);
}

View File

@ -55,6 +55,7 @@
#include "WM_api.h"
#include "WM_types.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
@ -670,7 +671,8 @@ static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph,
Mesh *me = BKE_mesh_new_from_object(depsgraph, object, false, preserve_origindex);
if (me->flag & ME_AUTOSMOOTH) {
BKE_mesh_split_faces(me, true);
ED_mesh_split_faces(me);
CustomData_free_layers(&me->ldata, CD_NORMAL, me->totloop);
}
return me;

View File

@ -3531,6 +3531,9 @@ void ED_region_info_draw_multiline(ARegion *region,
/* background box */
rcti rect = *ED_region_visible_rect(region);
/* Needed in case scripts leave the font size at an unexpected value, see: T102213. */
BLF_size(fontid, style->widget.points * U.dpi_fac);
/* Box fill entire width or just around text. */
if (!full_redraw) {
const char **text = &text_array[0];

View File

@ -4812,28 +4812,19 @@ bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
int ED_screen_animation_play(bContext *C, int sync, int mode)
{
bScreen *screen = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
Scene *scene_eval = DEG_get_evaluated_scene(CTX_data_ensure_evaluated_depsgraph(C));
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
/* stop playback now */
ED_screen_animation_timer(C, 0, 0, 0);
Main *bmain = CTX_data_main(C);
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Depsgraph *graph = BKE_scene_get_depsgraph(scene, view_layer);
if (graph) {
Scene *scene_eval = DEG_get_evaluated_scene(graph);
/* The audio handles are preserved throughout the dependency graph evaluation.
* Checking for scene->playback_handle even for non-evaluated scene should be okay. */
BKE_sound_stop_scene(scene_eval);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
}
}
BKE_sound_stop_scene(scene_eval);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
else {
/* these settings are currently only available from a menu in the TimeLine */
if (mode == 1) { /* XXX only play audio forwards!? */
Scene *scene_eval = DEG_get_evaluated_scene(CTX_data_ensure_evaluated_depsgraph(C));
BKE_sound_play_scene(scene_eval);
}

Some files were not shown because too many files have changed in this diff Show More